Scrapy 爬虫入门

1. scrapy 项目目录

scrapy是通过命令运行的爬虫框架

scrapy startproject projectname  // 创建scrapy项目

通过命令创建scrapy项目后,会自动生成一个projectname的文件夹,其中包括一个spiders文件夹,以及items.py、pipelines.py、middlewares.py、settings.py等python文件。spiders文件夹用于放置不同的spider文件,items.py中用于定义需要获取的数据容器,pipelines.py中定义的数据进一步加工与处理(如存放数据库、下载图片等),middlewares.py中定义自定义的中间件,一般用于自定义去重url逻辑、给request添加消息头模拟浏览器、定义ip池等,settings.py为爬虫的设置文件。

2. 爬虫items

import scrapy
class AppsSpiderItem(scrapy.Item):
    app_id = scrapy.Field()
    platform = scrapy.Field()
    ...

定义结构化数据信息的格式如下:

结构化数据名 = scrapy.Feild()

对于每一个需要提取的数据均需要定义对应的结构化数据名

3. 定义爬虫

Spider类是Scrapy中与爬虫相关的一个基类,所有爬虫文件必须继承该类(scrapy.Spider)

在爬虫项目中可以通过genspider命令自动在spiders文件夹中创建一个爬虫

scrapy genspider name domain
scrapy genspider test www.baidu.com
import scrapy

class TestSpider(scrapy.Spider):
    name = 'test'
    allowed_domains = ['www.baidu.com']
    start_urls = ['http://www.baidu.com/']

    def parse(self, response):
        pass

默认生成的spider只重写了parse方法,运行时其会自动调用默认的start_requests(),从start_urls中获取url发起请求,请求完成后会默认调用parse方法,在parse中编写具体解析逻辑。

4. 通过post请求url

默认生成的request是通过get请求,当需要同过post请求时可以通过重写start_requests方法,添加formdata

class TestSpider(scrapy.Spider):
    name = 'test'
    allowed_domains = ['www.baidu.com']
    start_urls = ['http://www.baidu.com/']

    def start_requests(self):
        url = self.start_urls[0]
        formdata = {'name':'mike'}
        yield scrapy.FormRequest(url=url, formdata=formdata, callback=self.parse)

    def parse(self, response):
        pass

自定义的request需要显式地定义callback方法

5. 运行爬虫

默认的运行方式是通过命令调用爬虫

scrapy runspider test.py (爬虫文件名)
scrapy crawl test(爬虫名)

当想通过idea运行scrapy爬虫时,可以通过py文件模拟cmdline

创建run.py文件,在其中定义

from scrapy import cmdline

name = 'google_play'
cmd = 'scrapy crawl {0}'.format(name) + ' --nolog'
cmdline.execute(cmd.split())

这种方式运行的爬虫可以在idea中debug爬虫,推荐使用

6. BeautifulSoup解析网页

解析网页一般通过正则表达式,xpath和BeautifulSoup解析,在此简要介绍BeautifulSoup的常用方法

BeautifulSoup是将复杂的HTML文档转化为一个复杂的树型结构,每个节点都是一个python对象,所有对象可以归纳为4种:

  • Tag
  • NavigableString
  • BeautifulSoup
  • Comment

1). Tag

Tag表示HTML中的一个个标签,获得一个节点后,可以通过 .tagname 获得其子tag,如

soup.div
soup.a

这种方式当且仅当其这种子节点类型只有一个时使用,当其子节点同一类型有多个时,可硬通过 .contents获得其所有子节点的集合。

soup.contents

.attrs 获取标签的所有属性

print(soup.p.attrs)
#{'class': ['title'], 'name': 'dromouse'}

获得某个属性

print(soup.p['class']
#['title']
print(soup.p.get('class'))
#['title']

2). NavigableString

当想要获取标签的内容时可以通过 .string获得

print soup.p.string
#The Dormouse's story

3). BeautifuSoup

BeautifulSoup对象表示一个文档的全部内容

4). Comment (一般不用)

常用方法:

description = soup.find_all('div', attrs={'class': 'W4P4ne '})  // 获得特定属性的div标签的集合
description[0].meta.attrs['content']                            // 获得集合中第一个标签的meta子标签的‘content’属性值

7. 模拟浏览器 自定义user-agent

一般情况下,我们需要不停更换用户代理,降低被ban的风险。默认情况下,scrapy会给所有的request一个默认的user-agent。当需要自定义user-agent时,具体实现是通过request对象的headers属性,以及自定义一个downloadmiddleware。

class AppSpiderDownloaderMiddleWare(object):

    def __init__(self, user_agent_list):
        self.user_agent = user_agent_list

    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        middleware = cls(crawler.settings.get('MY_USER_AGENT'))
        return middleware

    def process_request(self, request, spider):
        #随机选择一个user-agent
        request.headers['user-agent'] = random.choice(self.user_agent)

在上列中,我们自定义了一个下载中间件,这样就可以保证每一个请求在交给下载器之前都会经过这里,同时在创建中间件时,传入了定义在settings中的user-agent集合。

MY_USER_AGENT = ["Mozilla/5.0+(Windows+NT+6.2;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/45.0.2454.101+Safari/537.36",
    "Mozilla/5.0+(Windows+NT+5.1)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/28.0.1500.95+Safari/537.36+SE+2.X+MetaSr+1.0",
    "Mozilla/5.0+(Windows+NT+6.1;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/50.0.2657.3+Safari/537.36",
    "Mozilla/5.0+(Windows+NT+6.1;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/51.0.2704.106+Safari/537.36",
    "Mozilla/5.0+(Windows+NT+6.1)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/47.0.2526.108+Safari/537.36+2345Explorer/7.1.0.12633",
    "Mozilla/5.0+(Macintosh;+Intel+Mac+OS+X+10_11_4)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/49.0.2623.110+Safari/537.36",
    "Mozilla/5.0+(Macintosh;+Intel+Mac+OS+X+10_9_5)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/42.0.2311.152+Safari/537.36",
    "Mozilla/5.0+(Windows+NT+6.1;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/42.0.2311.152+Safari/537.36",
    "Mozilla/5.0+(Macintosh;+Intel+Mac+OS+X+10_10_2)+AppleWebKit/600.3.18+(KHTML,+like+Gecko)+Version/8.0.3+Safari/600.3.18",
    "Mozilla/5.0+(Windows+NT+6.1;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/49.0.2623.22+Safari/537.36+SE+2.X+MetaSr+1.0",
    "Mozilla/5.0+(Macintosh;+Intel+Mac+OS+X+10_11_4)+AppleWebKit/601.5.17+(KHTML,+like+Gecko)+Version/9.1+Safari/601.5.17",
    "Mozilla/5.0+(Windows+NT+6.1;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/48.0.2564.103+Safari/537.36",
    "Mozilla/5.0+(Windows+NT+6.1;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/47.0.2526.80+Safari/537.36+Core/1.47.640.400+QQBrowser/9.4.8309.400",
    "Mozilla/5.0+(Macintosh;+Intel+Mac+OS+X+10_10_5)+AppleWebKit/600.8.9+(KHTML,+like+Gecko)+Version/8.0.8+Safari/600.8.9",
    "Mozilla/5.0+(Windows+NT+6.3;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/39.0.2171.99+Safari/537.36+2345Explorer/6.4.0.10356",
    "Mozilla/5.0+(Windows+NT+6.1;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/45.0.2454.87+Safari/537.36+QQBrowser/9.2.5584.400",
    "Mozilla/5.0+(Windows+NT+6.1;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/47.0.2526.111+Safari/537.36",
    "Mozilla/5.0+(Windows+NT+6.1;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/33.0.1750.146+BIDUBrowser/6.x+Safari/537.36",
    "Mozilla/5.0+(Windows+NT+6.1)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/39.0.2171.99+Safari/537.36+2345Explorer/6.5.0.11018",
    "Mozilla/5.0+(Windows+NT+6.2;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/42.0.2311.154+Safari/537.36+LBBROWSER"]

然后在settings.py文件中开启Middleware配置

# Enable or disable downloader middlewares
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
   'apps_spider.middlewares.AppsSpiderDownloaderMiddleware': 543,
}

8. 设置ip池

在settings文件中定义ip集合

IPPOOL=[
	{"ipaddr":"61.129.70.131:8080"},
	{"ipaddr":"61.152.81.193:9100"},
	{"ipaddr":"120.204.85.29:3128"},
	{"ipaddr":"219.228.126.86:8123"},
	{"ipaddr":"61.152.81.193:9100"},
	{"ipaddr":"218.82.33.225:53853"},
	{"ipaddr":"223.167.190.17:42789"}
]

自定义中间件,在每次request前随机添加ip地址

import random
from scrapy import signals
from myproxies.settings import IPPOOL
 
class ProxiesSpiderMiddleware(object):
 
      def __init__(self,ip=''):
          self.ip=ip
       
      def process_request(self, request, spider):
          thisip=random.choice(IPPOOL)
          print("this is ip:"+thisip["ipaddr"])
          request.meta["proxy"]="http://"+thisip["ipaddr"]

在settings文件中启用这个中间件

# Enable or disable downloader middlewares
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
   'apps_spider.middlewares.ProxiesSpiderMiddleware': 543,
}

ip地址可以在免费ip,或在github中搜索proxy ip获得

9. 保存数据到json

在pipelines中编写处理items的逻辑

import codecs
import json
import urllib.request

class AppsSpiderPipeline(object):
    icon_path = "./icons"

    def __init__(self):
        self.file = codecs.open("./apps.json", "wb", encoding="utf-8")

    def process_item(self, item, spider):
        d = dict(item)
        icon_url = d.pop('icon_url')
        
        # 下载图片
        local_path = self.icon_path + '/' + d['app_id'] + '.jpg'
        urllib.request.urlretrieve(icon_url, filename=local_path)
        
        # 持久化到json
        i = json.dumps(d, ensure_ascii=False)
        line = i + '\n'
        self.file.write(line)

        return item

    def close_spider(self, spider):
        self.file.close()

在settings中启用pipelines

# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
   'apps_spider.pipelines.AppsSpiderPipeline': 300,
}

10.解决ajax异步加载内容

某些网页第一次请求仅获取部分内容,当用户浏览到页面底端才通过js再次加载新的内容。对于这种页面,只需在每次请求得到的response中定位到下次请求的网址,即可递归爬取到该页面所有内容。以google play列表页为例:

 

 

 

 

 

 

 

 

 

### Scrapy 爬虫入门教程与基本用法 #### 安装Scrapy框架 为了开始使用Scrapy,需先安装此框架。可以通过pip工具轻松完成这一过程,在命令行输入`pip install scrapy`即可完成安装[^2]。 #### 创建Scrapy项目 一旦环境准备就绪,可以利用Scrapy提供的命令行工具创建一个新的项目。通过执行`scrapy startproject myprojectname`来初始化一个新项目,其中myprojectname代表项目的名称。 #### 构建爬虫文件 在项目建立之后,下一步是在该项目内构建具体的爬虫逻辑。这通常涉及到几个重要组件: - **Items**: 数据模型定义于`items.py`中,用于描述要提取的数据字段。例如,对于网页中的书籍信息,可能需要定义如下结构: ```python import scrapy class BookItem(scrapy.Item): title = scrapy.Field() author = scrapy.Field() price = scrapy.Field() ``` - **Spiders (爬虫)**: 实际负责访问目标网址并解析页面内容的部分位于独立的Python脚本。这些脚本继承自`scrapy.Spider`类,并实现特定方法以处理URL请求及其响应。 - **Pipelines(管道)**: 处理已抓取到的信息流经路径的一部分;可以在pipeline中清洗、验证或保存数据至数据库等操作[^4]。 #### 编写第一个Spider实例:dang.py 作为例子,这展示了一个简单的dang.py蜘蛛程序片段,旨在获取当当网上图书的相关详情: ```python import scrapy from ..items import DangDangBookItem # 导入之前定义好的item class DangSpider(scrapy.Spider): name = 'dang' allowed_domains = ['book.dangdang.com'] start_urls = ['http://category.dangdang.com/cp01.54.00.00.00.00.html'] def parse(self, response): books = response.xpath('//ul[@class="bigimg"]/li') for book in books: item = DangDangBookItem() item['title'] = book.xpath('./a/@title').get().strip() item['link'] = "https:" + book.xpath('.//a/@href').get().strip() yield item next_page_url = response.css('li.next a::attr(href)').extract_first() if next_page_url is not None: yield scrapy.Request(response.urljoin(next_page_url)) ``` 这段代码展示了如何从指定类别下的多页列表中收集书名和链接地址。 #### 启动爬虫运行 最后一步就是让编写的spider工作起来啦!只需切换回终端窗口,定位到项目根目录下,键入`scrapy crawl dang`就能启动名为"dang"的那个爬虫了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值