scrapy 爬虫框架的基础使用

scrapy 是为了爬取数据,提取结构性数据的应用框架。

安装

> pip install scrapy
# 如果报超时错误,则切换源
> pip install scrapy -i https://pypi.douban.com/simple

创建项目与项目简介

在命令行中进入项目存储目录下,执行以下命令:

> scrapy startproject <项目名称>

创建之后,进入项目目录,可看到项目目录:

╠═╗  项目名
  ╠═╗  项目名
    ╠═╗  spiders            --爬虫核心功能的存储文件夹
      ╠═   __init__.py
    ╠═   __init__.py        
    ╠═   items.py           --定义数据结构的地方,是一个继承自scrapy.Item的类
    ╠═   middlewares.py     --中间件
    ╠═   pipelines.py       --管道文件,用于处理下载数据的后续处理
    ╠═   settings.py        --配置文件
  ╠═  scrapy.cfg


创建爬虫与爬虫文件介绍

在项目目录下,在命令行中执行以下命令:

> scrapy genspider <爬虫名> <网址(不包含http)>

执行命令后,在项目目录/项目同名目录/spiders目录下,会发现项目创建了一个文件。打开文件,文件初始化内容如下:

import scrapy

class <爬虫名>Spider(scrapy.Spider):
    name = '<爬虫名>'                 # 爬虫的名字
    allowed_domains = ['<网址>']      # 限定允许访问的域名
    start_urls = ['http://<网址>/']   # 起始的url地址,第一次要访问的url

    def parse(self, response):
        '''执行起始url地址后执行的代码
        args:
          response: 执行起始url后,得到的结果(对象,与requests执行后的结果一样)
        '''
        pass

如果在命令行中输入的命令中,爬虫名是中文,那么项目会在创建的文件名前添加a字符,在类名前加A字符,name属性名不变。

运行爬虫

在项目目录下,在命令行中执行以下命令:

> scrapy crawl <爬虫名>

如果为爬虫名是中文(上节说项目自动修改了文件名和类名),依旧使用中文,不需要添加 aA字符。

工作原理

  1. 引擎向spiders获取url;
  2. 引擎将获取的url发送给调度器;
  3. 调度器将url生成一个请求对象返回给引擎,存放到引擎的请求队列中;
  4. 引擎将请求队列中的请求对象分配给下载器;
  5. 下载器从互联网上下载数据并返回给引擎;
  6. 引擎将数据返还给spiders,spiders通过数据解析将解析结果发送给引擎;
  7. 引擎会判断解析结果是url还是数据,如果是url将会从第2步重复,如果是数据将会发送给管道,管道负责将数据保存到文件或数据库等存储单元中。
                         ╔═══════════════╗
                         ║     调度器     ║           ╔═══════════════╗
                         ╚═══════════════╝           ║     互联网     ║
                           ↑        ↑   ╎            ╚═══════════════╝
                          url      url 请求                 ↑   ╎
                           ╎        ╎   ↓             从互联网上下载数据
                         ╔═══════════════╗                 ╎   ↓ 
   ╔══════════╗          ║               ║ --请 求-->╔═══════════════╗
   ║  管 道   ║<--数 据--║      引擎     ║           ║     下载器     ║
   ╚══════════╝          ║               ║ <--数 据--╚═══════════════╝
 (存储到文件/数据库中)      ╚═══════════════╝  
                           ↑        ↑   ╎
                        解析结果    url 数据
                           ╎        ╎   ↓
                       ╔═══════════════════╗
                       ║     spiders       ║
                       ╚═══════════════════╝
                         (通过xpath解析数据)

response中可用的属性与方法

response.text          获取html代码/接口数据 (字符串)
response.body          二进制数据
response.xpath()       列表,元素为 seletor对象,参数为xpath语法
seletor对象.extract()   获取seletor对象的data属性值,数据类型为字符串
元素为seletor对象的列表.extract_first()
                          提取列表(元素为seletor对象)中的第一个数据,不存在则返回None
seletor对象.xpath()    seletor对象也可以调用xpath
response.meta          字典,上一步中传递的数据

需要获取多个url页面数据

在爬虫文件中,可以使用 scrapy.Request(url='', callback=self.parse, meta={'<key>': 'value'})主动调用网页爬虫,其中,参数url是要爬取的网页,callback是获取数据后处理的函数。

如果多个url的数据处理一样,如分页查询。可以直接调用自身的处理函数。如果是其他url,如子页面数据获取,可以模仿 parse()方法自定义一个处理函数。

若有多个数据处理函数,在 Request()函数中使用 meta参数传递字典,将这一步骤得到的数据传递到下一步骤。需要的数据全部获取完成时,统一加入数据存储类中。

函数数据存储文件 — items.py

在数据存储文件中需要定义我们需要的数据:

import scrapy

class <爬虫名>Item(scrapy.Item):
    <数据变量名> = scrapy.Field()  # 以定义类属性的形式定义数据变量名

定义之后如何使用呢?

在 spiders 目录的爬虫文件中,先导入数据存储类,然后实例化数据存储类时将数据当作参数传入:

# 导入
from <项目名>.items import <数据存储文件的类名>

# 使用,在parse() 爬虫信息处理函数中
<自定义变量> = <数据存储文件的类名>(<数据变量名>='<数据值>')

# 例:
# items.py
class ScrapyStudyItem(scrapy.Item):
    name = scrapy.Field()
# 爬虫文件.py
def parse(self, response):
    # 省去了数据处理步骤
    it = ScrapyStudyItem(name="aaa")
    print(it)  # 结果为: {'name': 'aaa'}

管道文件 — pipelines.py

在爬虫文件中,处理完数据并使用数据存储对象将数据实例化后,使用 yield 生成器,可自动传递到管道文件中。

在管道文件中,方法 process_item(self, item, spider)随时监听程序,生成器传递一条,此方法就会执行一次。其中 item就是生成器传递的数据。

# 爬虫文件.py
def parse(self, response):
    # 省去了数据处理步骤
    it = ScrapyStudyItem(name="aaa")
    yield it  # 通过生成器传递数据
# pipelines.py
def process_item(self, item, spider):
    print(item) # 结果为: {'name': 'aaa'}
    # 通常,在这里都是写将数据保存到文件,保存到数据库的代码,这里为了明了直接打印了数据
    return item

管道文件的类定义中,还可以定义两个方法 open_spider(self, spider)close_spider(self, spider),分别表示爬虫文件执行的前后所对应的前置和后置执行函数。通常用于文件的开启关闭,数据库连接等初始化和结束操作。

如果需要添加新的管道,则模仿着自定义一个管道类。定义完成后,在配置文件中将这个管道类添加到 ITEM_PIPELINES配置中。

post请求

post请求一般是需要传递参数的,但是爬虫文件中的 parse() 方法是自动执行的,无法传递参数。这个方法无效了。需要创建一个名字叫做 start_requests(self)的方法来获取post方式请求的url的数据。

start_requests(self)方法在项目执行时也是自动执行,但是不同的是,这个方法没有指定要获取的 url,需要在方法内自定义。下面例子可以表示使用方法:

class BaiduSpider(scrapy.Spider):
    name = 'baidu'
    allowed_domains = ['fanyi.baidu.com']
    # start_urls = ['http://fanyi.baidu.com/']
    # def parse(self, response):
    #     pass
    def start_requests(self):
        url = "http://fanyi.baidu.com/sug"
        data = {"kw": 'blue'}
        # url是要访问的url,formdata是参数,callback是数据处理函数
        yield scrapy.FromRequest(url=url, formdata=data, callback=self.parse_second)
    def parse_second(self, response):
        # 数据处理
        print(response.text)

配置文件 — settings.py

ROBOTSTXT_OBEY = True        -- 是否遵循网站的robots协议,默认为True。
ITEM_PIPELINES = {           -- 将 # 符号去除,表示开启管道。此字典中包含定义的所有管道
   '<项目名>.pipelines.<项目名>Pipeline': 300,  -- 定义的一条管道,值为优先级
}
LOG_LEVEL = ""               -- 日志打印的等级,默认为DEBUG,可选项:
                                CRITICAL, ERROR, WARNING, INFO, DEBUG 
LOG_FILE = "xxx.log"         -- 日志保存到文件中,而不打印