Scrapy

安装

pip install scrapy

创建项目

首先创建一个新的Scrapy项目。

scrapy startproject tutorial

创建的tutorial 目录:


这些文件是:
scrapy.cfg: 项目的配置文件
tutorial/ : 该项目的python模块。之后您将在此加入代码。
tutorial/ items.py: 项目中的item文件.
tutorial/ pipelines.py: 项目中的pipelines文件.
tutorial/ settings.py: 项目的设置文件.
tutorial/ spiders /: 放置spider代码的目录.

简单流程

  1. 创建一个Scrapy项目;
  2. 定义提取的Item;
  3. 编写爬取网站的 spider 并提取 Item;
  4. 编写 Item Pipeline 来存储提取到的Item(即数据)。

    定义Item

    Item 是保存爬取到的数据的容器;其使用方法和python字典类似, 并且提供了额外保护机制来避免拼写错误导致的未定义字段错误。

可以通过创建一个 scrapy.Item 类, 并且定义类型为 scrapy.Field 的类属性来定义一个Item。


通过定义item, 可以很方便的使用Scrapy的其他方法。而这些方法需要知道item的定义。

编写第一个爬虫(Spider)

Spider是用户编写用于从单个网站(或者一些网站)爬取数据的类。

其包含了一个用于下载的初始URL,如何跟进网页中的链接以及如何分析页面中的内容, 提取生成 item 的方法。

为了创建一个Spider,您必须继承 scrapy.Spider 类, 且定义以下三个属性:

  1. name: 用于区别Spider。 该名字必须是唯一的,您不可以为不同的Spider设定相同的名字。
  2. start_urls: 包含了Spider在启动时进行爬取的url列表。 因此,第一个被获取到的页面将是其中之一。 后续的URL则从初始的URL获取到的数据中提取。
  3. parse() 是spider的一个方法。 被调用时,每个初始URL完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象。

以下为我们的第一个Spider代码,保存在 tutorial/spiders 目录下的 dmoz_spider.py 文件中:

爬取

进入项目的根目录,执行下列命令启动spider

scrapy crawl dmoz

刚才发生了什么

Scrapy为Spider的 start_urls 属性中的每个URL创建了 scrapy.Request 对象,并将 parse 方法作为回调函数(callback)赋值给了Request。

Request对象经过调度,执行生成 scrapy.http.Response 对象并送回给spider parse() 方法。

提取Item

Selectors选择器简介

从网页中提取数据有很多方法。Scrapy使用了一种基于 XPath 和 CSS 表达式机制: Scrapy Selectors 。

这里给出XPath表达式的例子及对应的含义:
/ html/ head/ title: 选择HTML文档中 标签内的 元素<br>/ html/ head/ title/ text(): 选择上面提到的 <title> 元素的文字<br>/ / td: 选择所有的 <td> 元素<br>/ / div[@class=”mine”]: 选择所有具有 class=”mine” 属性的 div 元素</td>

为了配合XPath,Scrapy除了提供了 Selector 之外,还提供了方法来避免每次从response中提取数据时生成selector的麻烦。

Selector有四个基本的方法:
xpath(): 传入xpath表达式,返回该表达式所对应的所有节点的selector list列表 。
css(): 传入CSS表达式,返回该表达式所对应的所有节点的selector list列表.
extract(): 序列化该节点为unicode字符串并返回list。
re(): 根据传入的正则表达式对数据进行提取,返回unicode字符串list列表。

进入项目的根目录,启动shell:

shell的类似输出:


当shell载入后,您将得到一个包含response数据的本地 response 变量。输入 response.body 将输出response的包体, 输出 response.headers 可以看到response的包头。

更为重要的是,当输入 response.selector 时, 您将获取到一个可以用于查询返回数据的selector(选择器), 以及映射到 response.selector.xpath() 、 response.selector.css() 的 快捷方法(shortcut): response.xpath() 和 response.css() 。

同时,shell根据response提前初始化了变量 sel 。该selector根据response的类型自动选择最合适的分析规则(XML vs HTML)。

提取数据

在我们的spider中加入这段代码:

使用Item

Item 对象是自定义的python字典。 您可以使用标准的字典语法来获取到其每个字段的值。(字段即是我们之前用Field赋值的属性):


一般来说,Spider将会将爬取到的数据以 Item 对象返回。所以为了将爬取的数据返回,我们最终的代码将是:

现在对dmoz.org进行爬取将会产生 DmozItem 对象:

保存爬取到的数据

最简单存储爬取的数据是使用


该命令将采用 JSON 格式对爬取的数据进行序列化,生成 items.json 文件。

小规模的项目中,这种存储方式已经足够。 如果需要对爬取到的item做更多更为复杂的操作,您可以编写 Item Pipeline 。

一个例子

https://github.com/Jack-Cherish/python-spider/tree/master/cartoon

scrapy进行分布式爬虫

分布式爬虫原理

scrapy的单机架构:


可以看到,scrapy单机模式,通过一个scrapy引擎通过一个调度器,将Requests队列中的request请求发给下载器,进行页面的爬取。多台主机协作的关键是共享一个爬取队列。

分布式爬虫的关键是共享一个requests队列,维护该队列的主机称为master,而从机则负责数据的抓取,数据处理和数据存储,所以分布式爬虫架构如下图所示:


选用Redis队列进行存储,Redis是一种高效的非关系型数据库,以key-value的形式存储,结构灵活,它是内存中的数据结构存储系统,处理速度快,性能好,同时,提供了队列,集合等多种存储结构,方便队列维护。

另外一个问题,如何去重?这个的意思就是如何避免多台主机访问的request都不同,即让Reques队列中的请求都是不同的,那么就需要用到Redis提供的队列结构。Redis提供集合数据结构,在Redis集合中存储每个Request的指纹,在向Request队列中加入Request时首先验证指纹是否存在。如果存在,则不加入,如果不存在,则加入。

环境配置

目前已经有专门的python库实现了分布式架构。Scrapy-Redis库改写了Scrapy的调度器,队列等组件,可以方便的实现Scrapy分布式架构。

Scrapy-Redis链接:https://github.com/rolando/scrapy-redis

由于暂时只有单机环境,所以接下来:
scrapy进行分布式爬虫 - thinker1017 - 博客园