Scrapy爬虫初级编写方法

创建项目

使用scrapy编写爬虫首先需要创建项目. 与普通的Python项目不同, 新的scrapy项目需要通过命令行的方式:

scrapy startproject <项目名称>

这条命令将会创建一个以<项目名称>为名的目录, 内部结构如下:

<项目名称>/
    scrapy.cfg
    <项目名称>/
        __init__.py
        items.py
        pipelines.py
        settings.py
        spiders/
            __init__.py

这些内部文件/目录的作用是:

  • scrapy.cfg: 项目的配置文件

  • <项目名称>/: 内部目录, 项目的python模块, 爬虫的开发代码

  • <项目名称>/items.py: 定义使用的Item

  • <项目名称>/pipelines.py: 项目使用到的pipeline

  • <项目名称>/settings.py: 设置文件

  • <项目名称>/spiders/: 放置spider代码的目录

首先了解每个文件/模块的意义, 这些是scrapy组织内容结构和定义流程的方式.

定义Item

Item是保存爬取到的数据的容器. 定义的方法类似于sqlalchemy包所使用的ORM(对象关系映射)形式. 例如我们想定义爬取到的一条数据中, 包含网址的名字, URL, 以及对应的描述等三个字段, 定义方法如下:

import scrapy

class DmozItem(scrapy.Item):
    title = scrapy.Field()
    link = scrapy.Field()
    desc = scrapy.Field()

即创建一个scrapy.Item类, 并且定义每个字段为一个scrapy.Field. 这是Item的定义方式, 在使用的时候, 方法与python字典的用法类似.

编写提取数据的Spider

上一步定义了需要爬取的数据的格式, 现在则是要编写代码来提取这种数据, 即编写一个Spider. Spider是用户编写用于从单个网站(或者一些网站)爬取数据的类. 其包含了:

  • 一个用于下载的初始URL

  • 如何跟进网页中的链接以及如何分析页面中的内容

  • 提取生成 item 的方法

现在继承scrapy.Spider类, 创建一个Spider, 并且自定义以下属性:

  • name: 用于区别不同的Spider, 该名字必须是唯一的, 不可以为不同的Spider设定相同的名字

  • start_urls: 包含了Spider在启动时进行爬取的url列表. 因此, 第一个被获取到的页面将是其中之一, 后续的URL则从初始的URL获取到的数据中提取

  • parse(): spider的一个方法

    • 该方法负责

      • 解析返回的数据(response data)

      • 提取数据(生成item)

      • 生成需要进一步处理的URL的Request对象

    • 在被调用时, 每个初始URL完成下载后生成的Response对象, 将会作为唯一的参数传递给该函数

以下为一个Spider例子:

import scrapy

class DmozSpider(scrapy.spiders.Spider):
    name = "dmoz"
    allowed_domains = ["dmoz.org"]
    start_urls = [
        "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
        "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"
    ]

    def parse(self, response):
        filename = response.url.split("/")[-2]
        with open(filename, 'wb') as f:
            f.write(response.body)

Spider代码保存在<项目名称>/spiders/中, 新建一个python脚本如dmoz_spider.py文件.

爬取过程

这样就定义好了一个非常简单的爬虫. 通过命令启动Spider, 进行爬取工作:

scrapy crawl dmoz

这里的dmoz为上一步定义的DmozSpider类的名字(name). 在定义时要保证不同Spider的name是唯一的.

爬虫的原理简单来说, Scrapy为Spider的start_urls属性中的每个URL创建了scrapy.Request对象, 并将parse方法作为回调函数(callback)赋值给了每个Request对象. Request对象经过调度, 执行生成scrapy.http.Response对象, 并送回给spider的parse方法.

选择器(Selectors)

上面的代码实际上并没有使用之前定义的DmozItem类, 而是简单的将网页中的内容保存在文件中. 现在我们将会从网页内容中提取数据, 保存在DmozItem对象中.

Scrapy使用了基于XPathCSS表达式机制来提取网页中的数据, 这套提取数据的机制在代码中对应为选择器(Selectors).

XPath表达式的使用方法参考: XPath 教程

Selector有四个基本的方法:

  • xpath(): 传入xpath表达式, 返回该表达式所对应的所有结点的selector list列表

  • css(): 传入css表达式, 返回该表达式所对应的所有结点的selector list列表

  • extract(): 序列化该节点为unicode字符串并返回list

  • re(): 根据传入的正则表达式对数据进行提取, 返回unicode字符串list列表

查看网页内容

现在我们开始编写一个Selector. 首先需要知道爬取网站的组织格式, 我们提取的数据是保存在哪里的. 之前一般是通过浏览的F12方法去查看源码. 除此之外, scrapy提供了一种内置的Scrapy shell工具, 运行在IPython终端中, 供我们使用scrapy selector的方法对网页进行探索. 执行以下的命令来启动shell:

scrapy shell "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/"

shell载入后, 会生成一个response变量, 使用response.body属性就能获得response的返回体, 同理response.headers可以看到返回头. 这是scrapy组织输出的形式.

同时, shell也初始化了变量sel, 这是一个加载了上面response的selector, 使用对应的方法就能进行提取:

In [1]: sel.xpath('//title')
Out[1]: [<Selector xpath='//title' data=u'<title>Open Directory - Computers: Progr'>]

In [2]: sel.xpath('//title').extract()
Out[2]: [u'<title>Open Directory - Computers: Programming: Languages: Python: Books</title>']

In [3]: sel.xpath('//title/text()')
Out[3]: [<Selector xpath='//title/text()' data=u'Open Directory - Computers: Programming:'>]

In [4]: sel.xpath('//title/text()').extract()
Out[4]: [u'Open Directory - Computers: Programming: Languages: Python: Books']

In [5]: sel.xpath('//title/text()').re('(\w+):')
Out[5]: [u'Computers', u'Programming', u'Languages', u'Python']

可以看到Selector对象的使用方法: 首先使用xpathcss方法获得命中的Selector列表, 再使用extractre方法提取其中存储的数据.

因此Selector中, 既是一种数据存储形式, 包含了要提取的数据, 其子结构也对应为Selector, 也是提取各种详细数据方法的提供者.

提取数据

使用Selector来提取数据, 并使用之前定义的Item对象, 对应的Spider代码变为:

import scrapy

from tutorial.items import DmozItem

class DmozSpider(scrapy.Spider):
    name = "dmoz"
    allowed_domains = ["dmoz.org"]
    start_urls = [
        "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
        "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"
    ]

    def parse(self, response):
        for sel in response.xpath('//ul/li'):
            item = DmozItem()
            item['title'] = sel.xpath('a/text()').extract()
            item['link'] = sel.xpath('a/@href').extract()
            item['desc'] = sel.xpath('text()').extract()
            yield item

一般来说, Spider会将爬取到的数据以Item对象返回.

保存爬取到的数据

最简单存储爬取的数据的方式是使用Feed exports, 可以对爬取的数据进行序列化, 如JSON格式, 生成对应的.json文件.

使用的方法如下:

scrapy crawl dmoz -o items.json

需要对爬取到的item做更多更为复杂的操作, 需要编写Item Pipeline, 添加在<项目名称>/pipelines.py脚本中.

最后更新于