Scrapy 1.0.5官方文档

简介

最近在ofashion的爬虫组实习,用的scrapy,重新阅读了下官方文档,作了些记录。

初始

安装

pip install scrapy

创建项目

在开始爬取之前,您必须创建一个新的Scrapy项目。 进入您打算存储代码的目录中,运行下列命令:
scrapy startproject tutorial
该命令将会创建包含下列内容的tutorial目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
tutorial/
scrapy.cfg

tutorial/
__init__.py

items.py

pipelines.py

settings.py

spiders/
__init__.py
...

Item

Item 是保存爬取到的数据的容器;其使用方法和python字典类似。虽然您也可以在Scrapy中直接使用dict,但是 Item 提供了额外保护机制来避免拼写错误导致的未定义字段错误。 另外也可以与Item Loaders 一起使用,一种帮助用户方便地填充项目的机制

创建一个scrapy.Item类, 并且定义类型为scrapy.Field的类属性来定义一个Item。编辑tutorial目录中的items.py文件:

1
2
3
4
5
6
import scrapy

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

编写第一个爬虫(Spider)

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

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

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

  • name: 用于区别Spider。 该名字必须是唯一的,您不可以为不同的Spider设定相同的名字。
  • start_urls: 包含了Spider在启动时进行爬取的url列表。 因此,第一个被获取到的页面将是其中之一。 后续的URL则从初始的URL获取到的数据中提取。
  • parse() 是spider的一个方法。 被调用时,每个初始URL完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象。
    以下为我们的第一个Spider代码,保存在 tutorial/spiders 目录下的 dmoz_spider.py 文件中:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import scrapy

    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):
    filename = response.url.split("/")[-2] + '.html'
    with open(filename, 'wb') as f:
    f.write(response.body)

爬取

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

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

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

提取Item

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

这里给出XPath表达式的例子及对应的含义:

  • /html/head/title: 选择HTML文档中 <head> 标签内的 <title> 元素
  • /html/head/title/text(): 选择上面提到的 <title> 元素的文字
  • //td: 选择所有的 <td> 元素
  • //div[@class="mine"]: 选择所有具有 class="mine" 属性的 div 元素

Selector有四个基本的方法

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

scrapy shell

进入项目的根目录,执行下列命令来启动shell:
scrapy shell "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/"
进入shell,将得到一个response变量,并且拥有selector属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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/",
]

def parse(self, response):
for href in response.css("ul.directory.dir-col > li > a::attr('href')"):
url = response.urljoin(response.url, href.extract())
yield scrapy.Request(url, callback=self.parse_dir_contents)

def parse_dir_contents(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

现在, parse() 仅仅从页面中提取我们感兴趣的链接,使用 response.urljoin 方法构造一个绝对路径的URL(页面上的链接都是相对路径的), 产生(yield)一个请求, 该请求使用 parse_dir_contents() 方法作为回调函数, 用于最终产生我们想要的数据.。

这里展现的即是Scrapy的追踪链接的机制: 当您在回调函数中yield一个Request后, Scrapy将会调度,发送该请求,并且在该请求完成时,调用所注册的回调函数。

保存爬取到的数据

最简单存储爬取的数据的方式是使用 Feed exports:
scrapy crawl dmoz -o items.json
该命令将采用 JSON 格式对爬取的数据进行序列化,生成 items.json 文件。

如果需要对爬取到的item做更多更为复杂的操作,您可以编写 Item Pipeline 。 类似于我们在创建项目时对Item做的,用于您编写自己的 tutorial/pipelines.py 也被创建。 不过如果您仅仅想要保存item,您不需要实现任何的pipeline。

命令行工具(Command line tools)

Scrapy是通过 scrapy 命令行工具进行控制的。 这里我们称之为 “Scrapy tool” 以用来和子命令进行区分。 对于子命令,我们称为 “command” 或者 “Scrapy commands”。

调整设置

Scrapy将会在以下路径中寻找记录了配置参数的 scrapy.cfg 文件, 该文件以ini的方式记录:

  1. /etc/scrapy.cfg 或 c:\scrapy\scrapy.cfg (系统层面)
  2. ~/.config/scrapy.cfg ($XDG_CONFIG_HOME) 及 ~/.scrapy.cfg ($HOME) 作为全局(用户层面)设置, 以及
  3. 在scrapy项目根路径下的 scrapy.cfg (参考之后的章节)

从这些文件中读取到的设置按照以下的顺序合并: 用户定义的值具有比系统级别的默认值更高的优先级, 而项目定义的设置则会覆盖其他.

Scrapy也会读取并通过环境变量来设置. 目前支持的有:

  • SCRAPY_SETTINGS_MODULE (查看 指定设定(Designating the settings))
  • SCRAPY_PROJECT

scrapy.cfg 存放的目录被认为是 项目的根目录 。该文件中包含python模块名的字段定义了项目的设置。例如:

1
2
[settings]
default = myproject.settings

可用的工具命令(tool commands)

该章节提供了可用的内置命令的列表。每个命令都提供了描述以及一些使用例子。

有些命令在项目里运行时的效果有些许区别。 以fetch命令为例,如果被爬取的url与某个特定spider相关联, 则该命令将会使用spider的动作(spider-overridden behaviours)。 (比如spider指定的 user_agent)。 该表现是有意而为之的。一般来说, fetch 命令就是用来测试检查spider是如何下载页面。

您总是可以通过运行命令来获取关于每个命令的详细内容:
scrapy <command> -h
您也可以查看所有可用的命令:
scrapy -h
Scrapy提供了两种类型的命令。一种必须在Scrapy项目中运行(针对项目(Project-specific)的命令),另外一种则不需要(全局命令)。全局命令在项目中运行时的表现可能会与在非项目中运行有些许差别(因为可能会使用项目的设定)。

全局命令:

  • startproject
  • settings
  • runspider
  • shell
  • fetch
  • view
  • version

项目(Project-only)命令:

  • crawl
  • check
  • list
  • parse
  • genspider
  • bench

startproject

  • 语法: scrapy startproject <project_name>
  • 是否需要项目: no
    project_name 文件夹下创建一个名为 project_name 的Scrapy项目。

例子:
$ scrapy startproject myproject

genspider

  • 语法: scrapy genspider [-t template] <name> <domain>
  • 是否需要项目: yes
    在当前项目中创建spider。

这仅仅是创建spider的一种快捷方法。该方法可以使用提前定义好的模板来生成spider。您也可以自己创建spider的源码文件。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ scrapy genspider -l
Available templates:
basic
crawl
csvfeed
xmlfeed

$ scrapy genspider -d basic
import scrapy

class $classname(scrapy.Spider):
name = "$name"
allowed_domains = ["$domain"]
start_urls = (
'http://www.$domain/',
)

def parse(self, response):
pass

$ scrapy genspider -t basic example example.com
Created spider 'example' using template 'basic' in module:
mybot.spiders.example

crawl

  • 语法: scrapy crawl <spider>
  • 是否需要项目: yes
    使用spider进行爬取。

例子:

1
2
$ scrapy crawl myspider
[ ... myspider starts crawling ... ]

check

  • 语法: scrapy check [-l] <spider>
  • 是否需要项目: yes
    运行contract检查。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ scrapy check -l
first_spider
* parse
* parse_item
second_spider
* parse
* parse_item

$ scrapy check
[FAILED] first_spider:parse_item
>>> 'RetailPricex' field is missing

[FAILED] first_spider:parse
>>> Returned 92 requests, expected 0..4

list

  • 语法: scrapy list
  • 是否需要项目: yes
    列出当前项目中所有可用的spider。每行输出一个spider。

使用例子:

1
2
3
$ scrapy list
spider1
spider2

fetch

  • 语法: scrapy fetch <url>
  • 是否需要项目: no
    使用Scrapy下载器(downloader)下载给定的URL,并将获取到的内容送到标准输出。

该命令以spider下载页面的方式获取页面。例如,如果spider有 USER_AGENT 属性修改了 User Agent,该命令将会使用该属性。

因此,您可以使用该命令来查看spider如何获取某个特定页面。

该命令如果非项目中运行则会使用默认Scrapy downloader设定。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ scrapy fetch --nolog http://www.example.com/some/page.html
[ ... html content here ... ]

$ scrapy fetch --nolog --headers http://www.example.com/
{'Accept-Ranges': ['bytes'],
'Age': ['1263 '],
'Connection': ['close '],
'Content-Length': ['596'],
'Content-Type': ['text/html; charset=UTF-8'],
'Date': ['Wed, 18 Aug 2010 23:59:46 GMT'],
'Etag': ['"573c1-254-48c9c87349680"'],
'Last-Modified': ['Fri, 30 Jul 2010 15:30:18 GMT'],
'Server': ['Apache/2.2.3 (CentOS)']}

view

  • 语法: scrapy view <url>
  • 是否需要项目: no
    在浏览器中打开给定的URL,并以Scrapy spider获取到的形式展现。 有些时候spider获取到的页面和普通用户看到的并不相同。 因此该命令可以用来检查spider所获取到的页面,并确认这是您所期望的。

例子:

1
2
$ scrapy view http://www.example.com/some/page.html
[ ... browser starts ... ]

shell

  • 语法: scrapy shell [url]
  • 是否需要项目: no
    以给定的URL(如果给出)或者空(没有给出URL)启动Scrapy shell。

例子:

1
2
$ scrapy shell http://www.example.com/some/page.html
[ ... scrapy shell starts ... ]

parse

  • 语法: scrapy parse <url> [options]
  • 是否需要项目: yes
    获取给定的URL并使用相应的spider分析处理。如果您提供 --callback 选项,则使用spider的该方法处理,否则使用 parse

支持的选项:

  • --spider=SPIDER: 跳过自动检测spider并强制使用特定的spider
  • --a NAME=VALUE: 设置spider的参数(可能被重复)
  • --callback or -c: spider中用于解析返回(response)的回调函数
  • --pipelines: 在pipeline中处理item
  • --rules or -r: 使用 CrawlSpider 规则来发现用来解析返回(response)的回调函数
  • --noitems: 不显示爬取到的item
  • --nolinks: 不显示提取到的链接
  • --nocolour: 避免使用pygments对输出着色
  • --depth or -d: 指定跟进链接请求的层次数(默认: 1)
  • --verbose or -v: 显示每个请求的详细信息
    例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ scrapy parse http://www.example.com/ -c parse_item
    [ ... scrapy log lines crawling example.com spider ... ]

    >>> STATUS DEPTH LEVEL 1 <<<
    # Scraped Items ------------------------------------------------------------
    [{'name': u'Example item',
    'category': u'Furniture',
    'length': u'12 cm'}]

    # Requests -----------------------------------------------------------------
    []

    settings

  • 语法: scrapy settings [options]
  • 是否需要项目: no

获取Scrapy的设定

在项目中运行时,该命令将会输出项目的设定值,否则输出Scrapy默认设定。

例子:

1
2
3
4
$ scrapy settings --get BOT_NAME
scrapybot
$ scrapy settings --get DOWNLOAD_DELAY
0

runspider

  • 语法: scrapy runspider <spider_file.py>
  • 是否需要项目: no
    在未创建项目的情况下,运行一个编写在Python文件中的spider。

例子:

1
2
$ scrapy runspider myspider.py
[ ... spider starts crawling ... ]

version

  • 语法: scrapy version [-v]
  • 是否需要项目: no

输出Scrapy版本。配合 -v 运行时,该命令同时输出Python, Twisted以及平台的信息,方便bug提交。

bench

0.17 新版功能.

  • 语法: scrapy bench
  • 是否需要项目: no
    运行benchmark测试。

Spiders

对spider来说,爬取的循环类似下文:

  1. 以初始的URL初始化Request,并设置回调函数。 当该request下载完毕并返回时,将生成response,并作为参数传给该回调函数。
    spider中初始的request是通过调用 start_requests() 来获取的。 start_requests() 读取 start_urls 中的URL, 并以 parse 为回调函数生成 Request

  2. 在回调函数内分析返回的(网页)内容,返回 Item 对象、dict、 Request 或者一个包括三者的可迭代容器。 返回的Request对象之后会经过Scrapy处理,下载相应的内容,并调用设置的callback函数(函数可相同)。

  3. 在回调函数内,您可以使用 选择器(Selectors) (您也可以使用BeautifulSoup, lxml 或者您想用的任何解析器) 来分析网页内容,并根据分析的数据生成item。
  4. 最后,由spider返回的item将被存到数据库(由某些 Item Pipeline 处理)或使用 Feed exports 存入到文件中。

虽然该循环对任何类型的spider都(多少)适用,但Scrapy仍然为了不同的需求提供了多种默认spider。 之后将讨论这些spider。

scrapy.Spider

class scrapy.spiders.Spider

Spider是最简单的spider。每个其他的spider必须继承自该类(包括Scrapy自带的其他spider以及您自己编写的spider)。 Spider并没有提供什么特殊的功能。 其仅仅提供了 start_requests() 的默认实现,读取并请求spider属性中的 start_urls, 并根据返回的结果(resulting responses)调用spider的 parse 方法。

name
定义spider名字的字符串(string)。spider的名字定义了Scrapy如何定位(并初始化)spider,所以其必须是唯一的。 不过您可以生成多个相同的spider实例(instance),这没有任何限制。 name是spider最重要的属性,而且是必须的。

如果该spider爬取单个网站(single domain),一个常见的做法是以该网站(domain)(加或不加 后缀 )来命名spider。 例如,如果spider爬取 mywebsite.com ,该spider通常会被命名为 mywebsite 。

allowed_domains
可选。包含了spider允许爬取的域名(domain)列表(list)。 当 OffsiteMiddleware 启用时, 域名不在列表中的URL不会被跟进。

start_urls
URL列表。当没有制定特定的URL时,spider将从该列表中开始进行爬取。 因此,第一个被获取到的页面的URL将是该列表之一。 后续的URL将会从获取到的数据中提取。

custom_settings
该设置是一个dict.当启动spider时,该设置将会覆盖项目级的设置. 由于设置必须在初始化(instantiation)前被更新,所以该属性必须定义为class属性.

crawler
该属性在初始化class后,由类方法 from_crawler() 设置, 并且链接了本spider实例对应的 Crawler 对象.

Crawler包含了很多项目中的组件,作为单一的入口点 (例如插件,中间件,信号管理器等)

start_requests()
该方法必须返回一个可迭代对象(iterable)。该对象包含了spider用于爬取的第一个Request。

当spider启动爬取并且未制定URL时,该方法被调用。 当指定了URL时,make_requests_from_url() 将被调用来创建Request对象。 该方法仅仅会被Scrapy调用一次,因此您可以将其实现为生成器。

该方法的默认实现是使用 start_urls 的url生成Request。

如果您想要修改最初爬取某个网站的Request对象,您可以重写(override)该方法。 例如,如果您需要在启动时以POST登录某个网站,你可以这么写:

1
2
3
4
5
6
7
8
9
10
11
12
class MySpider(scrapy.Spider):
name = 'myspider'

def start_requests(self):
return [scrapy.FormRequest("http://www.example.com/login",
formdata={'user': 'john', 'pass': 'secret'},
callback=self.logged_in)]

def logged_in(self, response):
# here you would extract links to follow and return Requests for
# each of them, with another callback
pass

在单个回调函数中返回多个Request以及Item的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import scrapy

class MySpider(scrapy.Spider):
name = 'example.com'
allowed_domains = ['example.com']
start_urls = [
'http://www.example.com/1.html',
'http://www.example.com/2.html',
'http://www.example.com/3.html',
]

def parse(self, response):
sel = scrapy.Selector(response)
for h3 in response.xpath('//h3').extract():
yield {"title": h3}

for url in response.xpath('//a/@href').extract():
yield scrapy.Request(url, callback=self.parse)

除了 start_urls ,你也可以直接使用 start_requests() ; 您也可以使用 Items 来给予数据更多的结构性(give data more structure):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import scrapy
from myproject.items import MyItem

class MySpider(scrapy.Spider):
name = 'example.com'
allowed_domains = ['example.com']

def start_requests(self):
yield scrapy.Request('http://www.example.com/1.html', self.parse)
yield scrapy.Request('http://www.example.com/2.html', self.parse)
yield scrapy.Request('http://www.example.com/3.html', self.parse)

def parse(self, response):
for h3 in response.xpath('//h3').extract():
yield MyItem(title=h3)

for url in response.xpath('//a/@href').extract():
yield scrapy.Request(url, callback=self.parse)

CrawlSpider

class scrapy.spiders.CrawlSpider

爬取一般网站常用的spider。其定义了一些规则(rule)来提供跟进link的方便的机制。 也许该spider并不是完全适合您的特定网站或项目,但其对很多情况都使用。 因此您可以以其为起点,根据需求修改部分方法。当然您也可以实现自己的spider。

除了从Spider继承过来的(您必须提供的)属性外,其提供了一个新的属性:

rules
一个包含一个(或多个) Rule 对象的集合(list)。 每个 Rule 对爬取网站的动作定义了特定表现。 Rule对象在下边会介绍。 如果多个rule匹配了相同的链接,则根据他们在本属性中被定义的顺序,第一个会被使用。

该spider也提供了一个可复写(overrideable)的方法:

parse_start_url(response)
当start_url的请求返回时,该方法被调用。 该方法分析最初的返回值并必须返回一个 Item 对象或者 一个 Request 对象或者 一个可迭代的包含二者对象。

爬取规则(Crawling rules)

link_extractor 是一个 Link Extractor 对象。 其定义了如何从爬取到的页面提取链接。

callback 是一个callable或string(该spider中同名的函数将会被调用)。 从link_extractor中每获取到链接时将会调用该函数。该回调函数接受一个response作为其第一个参数, 并返回一个包含 Item 以及(或) Request 对象(或者这两者的子类)的列表(list)。

警告:当编写爬虫规则时,请避免使用 parse 作为回调函数。 由于 CrawlSpider 使用 parse 方法来实现其逻辑,如果 您覆盖了 parse 方法,crawl spider 将会运行失败。

cb_kwargs 包含传递给回调函数的参数(keyword argument)的字典。

follow 是一个布尔(boolean)值,指定了根据该规则从response提取的链接是否需要跟进。 如果 callback 为None, follow 默认设置为 True ,否则默认为 False

process_links 是一个callable或string(该spider中同名的函数将会被调用)。 从link_extractor中获取到链接列表时将会调用该函数。该方法主要用来过滤。

process_request 是一个callable或string(该spider中同名的函数将会被调用)。 该规则提取到每个request时都会调用该函数。该函数必须返回一个request或者None。 (用来过滤request)

CrawlSpider样例

接下来给出配合rule使用CrawlSpider的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor

class MySpider(CrawlSpider):
name = 'example.com'
allowed_domains = ['example.com']
start_urls = ['http://www.example.com']

rules = (
# 提取匹配 'category.php' (但不匹配 'subsection.php') 的链接并跟进链接(没有callback意味着follow默认为True)
Rule(LinkExtractor(allow=('category\.php', ), deny=('subsection\.php', ))),

# 提取匹配 'item.php' 的链接并使用spider的parse_item方法进行分析
Rule(LinkExtractor(allow=('item\.php', )), callback='parse_item'),
)

def parse_item(self, response):
self.logger.info('Hi, this is an item page! %s', response.url)

item = scrapy.Item()
item['id'] = response.xpath('//td[@id="item_id"]/text()').re(r'ID: (\d+)')
item['name'] = response.xpath('//td[@id="item_name"]/text()').extract()
item['description'] = response.xpath('//td[@id="item_description"]/text()').extract()
return item

该spider将从example.com的首页开始爬取,获取category以及item的链接并对后者使用 parse_item 方法。 当item获得返回(response)时,将使用XPath处理HTML并生成一些数据填入 Item 中。

选择器(Selectors)

构造选择器(selectors)

Scrapy selector是以 文字(text) 或 TextResponse 构造的 Selector 实例。 其根据输入的类型自动选择最优的分析方法(XML vs HTML):

1
2
>>> from scrapy.selector import Selector
>>> from scrapy.http import HtmlResponse

以文字构造:
1
2
3
>>> body = '<html><body><span>good</span></body></html>'
>>> Selector(text=body).xpath('//span/text()').extract()
[u'good']

以response构造:
1
2
3
>>> response = HtmlResponse(url='http://example.com', body=body)
>>> Selector(response=response).xpath('//span/text()').extract()
[u'good']

为了方便起见,response对象以 .selector 属性提供了一个selector, 您可以随时使用该快捷方法:
1
2
>>> response.selector.xpath('//span/text()').extract()
[u'good']

使用选择器

.extract()

为了提取真实的原文数据,你需要调用 .extract() 方法如下:

1
2
>>> response.xpath('//title/text()').extract()
[u'Example website']

如果想要提取到第一个匹配到的元素, 必须调用 .extract_first() selector
1
2
>>> response.xpath('//div[@id="images"]/a/text()').extract_first()
u'Name: My image 1 '

如果没有匹配的元素,则返回 None:
1
2
>>> response.xpath('//div/[id="not-exists"]/text()').extract_first() is None
True

您也可以设置默认的返回值,替代 None :
1
2
>>> sel.xpath('//div/[id="not-exists"]/text()').extract_first(default='not-found')
'not-found'

注意CSS选择器可以使用CSS3伪元素(pseudo-elements)来选择文字或者属性节点:
1
2
>>> response.css('title::text').extract()
[u'Example website']

现在我们将得到根URL(base URL)和一些图片链接:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
>>> response.xpath('//base/@href').extract()
[u'http://example.com/']

>>> response.css('base::attr(href)').extract()
[u'http://example.com/']

>>> response.xpath('//a[contains(@href, "image")]/@href').extract()
[u'image1.html',
u'image2.html',
u'image3.html',
u'image4.html',
u'image5.html']

>>> response.css('a[href*=image]::attr(href)').extract()
[u'image1.html',
u'image2.html',
u'image3.html',
u'image4.html',
u'image5.html']

>>> response.xpath('//a[contains(@href, "image")]/img/@src').extract()
[u'image1_thumb.jpg',
u'image2_thumb.jpg',
u'image3_thumb.jpg',
u'image4_thumb.jpg',
u'image5_thumb.jpg']

>>> response.css('a[href*=image] img::attr(src)').extract()
[u'image1_thumb.jpg',
u'image2_thumb.jpg',
u'image3_thumb.jpg',
u'image4_thumb.jpg',
u'image5_thumb.jpg']

结合正则表达式使用选择器(selectors)

Selector 也有一个 .re() 方法,用来通过正则表达式来提取数据。然而,不同于使用 .xpath() 或者 .css() 方法, .re() 方法返回unicode字符串的列表。所以你无法构造嵌套式的 .re() 调用。

下面是一个例子,从上面的 HTML code 中提取图像名字:

1
2
3
4
5
6
>>> response.xpath('//a[contains(@href, "image")]/text()').re(r'Name:\s*(.*)')
[u'My image 1',
u'My image 2',
u'My image 3',
u'My image 4',
u'My image 5']

另外还有一个糅合了 .extract_first().re() 的函数 .re_first() . 使用该函数可以提取第一个匹配到的字符串:
1
2
>>> response.xpath('//a[contains(@href, "image")]/text()').re_first(r'Name:\s*(.*)')
u'My image 1'

使用相对XPaths

比较合适的处理方法(注意 .//p XPath的点前缀):

1
2
>>> for p in divs.xpath('.//p'):  # extracts all <p> inside
... print p.extract()

另一种常见的情况将是提取所有直系 <p> 的结果:
1
2
>>> for p in divs.xpath('p'):
... print p.extract()

正则表达式

例如在XPath的 starts-with()contains() 无法满足需求时, test() 函数可以非常有用。

例如在列表中选择有”class”元素且结尾为一个数字的链接:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> from scrapy import Selector
>>> doc = """
... <div>
... <ul>
... <li class="item-0"><a href="link1.html">first item</a></li>
... <li class="item-1"><a href="link2.html">second item</a></li>
... <li class="item-inactive"><a href="link3.html">third item</a></li>
... <li class="item-1"><a href="link4.html">fourth item</a></li>
... <li class="item-0"><a href="link5.html">fifth item</a></li>
... </ul>
... </div>
... """
>>> sel = Selector(text=doc, type="html")
>>> sel.xpath('//li//@href').extract()
[u'link1.html', u'link2.html', u'link3.html', u'link4.html', u'link5.html']
>>> sel.xpath('//li[re:test(@class, "item-\d$")]//@href').extract()
[u'link1.html', u'link2.html', u'link4.html', u'link5.html']

集合操作

集合操作可以方便地用于在提取文字元素前从文档树中去除一些部分。

例如使用itemscopes组和对应的itemprops来提取微数据(来自http://schema.org/Product的样本内容):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
>>> doc = """
... <div itemscope itemtype="http://schema.org/Product">
... <span itemprop="name">Kenmore White 17" Microwave</span>
... <img src="kenmore-microwave-17in.jpg" alt='Kenmore 17" Microwave' />
... <div itemprop="aggregateRating"
... itemscope itemtype="http://schema.org/AggregateRating">
... Rated <span itemprop="ratingValue">3.5</span>/5
... based on <span itemprop="reviewCount">11</span> customer reviews
... </div>
...
... <div itemprop="offers" itemscope itemtype="http://schema.org/Offer">
... <span itemprop="price">$55.00</span>
... <link itemprop="availability" href="http://schema.org/InStock" />In stock
... </div>
...
... Product description:
... <span itemprop="description">0.7 cubic feet countertop microwave.
... Has six preset cooking categories and convenience features like
... Add-A-Minute and Child Lock.</span>
...
... Customer reviews:
...
... <div itemprop="review" itemscope itemtype="http://schema.org/Review">
... <span itemprop="name">Not a happy camper</span> -
... by <span itemprop="author">Ellie</span>,
... <meta itemprop="datePublished" content="2011-04-01">April 1, 2011
... <div itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating">
... <meta itemprop="worstRating" content = "1">
... <span itemprop="ratingValue">1</span>/
... <span itemprop="bestRating">5</span>stars
... </div>
... <span itemprop="description">The lamp burned out and now I have to replace
... it. </span>
... </div>
...
... <div itemprop="review" itemscope itemtype="http://schema.org/Review">
... <span itemprop="name">Value purchase</span> -
... by <span itemprop="author">Lucas</span>,
... <meta itemprop="datePublished" content="2011-03-25">March 25, 2011
... <div itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating">
... <meta itemprop="worstRating" content = "1"/>
... <span itemprop="ratingValue">4</span>/
... <span itemprop="bestRating">5</span>stars
... </div>
... <span itemprop="description">Great microwave for the price. It is small and
... fits in my apartment.</span>
... </div>
... ...
... </div>
... """
>>> sel = Selector(text=doc, type="html")
>>> for scope in sel.xpath('//div[@itemscope]'):
... print "current scope:", scope.xpath('@itemtype').extract()
... props = scope.xpath('''
... set:difference(./descendant::*/@itemprop,
... .//*[@itemscope]/*/@itemprop)''')
... print " properties:", props.extract()
... print
...

current scope: [u'http://schema.org/Product']
properties: [u'name', u'aggregateRating', u'offers', u'description', u'review', u'review']

current scope: [u'http://schema.org/AggregateRating']
properties: [u'ratingValue', u'reviewCount']

current scope: [u'http://schema.org/Offer']
properties: [u'price', u'availability']

current scope: [u'http://schema.org/Review']
properties: [u'name', u'author', u'datePublished', u'reviewRating', u'description']

current scope: [u'http://schema.org/Rating']
properties: [u'worstRating', u'ratingValue', u'bestRating']

current scope: [u'http://schema.org/Review']
properties: [u'name', u'author', u'datePublished', u'reviewRating', u'description']

current scope: [u'http://schema.org/Rating']
properties: [u'worstRating', u'ratingValue', u'bestRating']

在这里,我们首先在 itemscope 元素上迭代,对于其中的每一个元素,我们寻找所有的 itemprops 元素,并排除那些本身在另一个 itemscope 内的元素。

//node[1] and (//node)[1]的不同

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> from scrapy import Selector
>>> sel = Selector(text="""
....: <ul class="list">
....: <li>1</li>
....: <li>2</li>
....: <li>3</li>
....: </ul>
....: <ul class="list">
....: <li>4</li>
....: <li>5</li>
....: <li>6</li>
....: </ul>""")
>>> xp = lambda x: sel.xpath(x).extract()

拿了所有一级<li>

1
2
>>> xp("//li[1]")
[u'<li>1</li>', u'<li>4</li>']

拿的第一个一级<li>
1
2
>>> xp("(//li)[1]")
[u'<li>1</li>']

Item Loaders

自己阅读文档后,认为Item Loaders的作用有些多此一举,select的功能在parse中解析后赋值到item上返回即可。Item Loaders使用后,对于不同的网站格式存储相同的字段格式时,则需要重写Item Loaders类和spider;如果不使用,只需要重写spider即可。个人愚见,请指正。

Scrapy终端(Scrapy shell)

可用的快捷命令(shortcut)

  • shelp() - 打印可用对象及快捷命令的帮助列表
  • fetch(request_or_url) - 根据给定的请求(request)或URL获取一个新的response,并更新相关的对象
  • view(response) - 在本机的浏览器打开给定的response。 其会在response的body中添加一个 tag ,使得外部链接(例如图片及css)能正确显示。 注意,该操作会在本地创建一个临时文件,且该文件不会被自动删除。

可用的Scrapy对象

Scrapy终端根据下载的页面会自动创建一些方便使用的对象,例如 Response 对象及 Selector 对象(对HTML及XML内容)。

这些对象有:

  • crawler - 当前 Crawler 对象.
  • spider - 处理URL的spider。 对当前URL没有处理的Spider时则为一个 Spider 对象。
  • request - 最近获取到的页面的 Request 对象。 您可以使用 replace() 修改该request。或者 使用 fetch 快捷方式来获取新的request。
  • response - 包含最近获取到的页面的 Response 对象。
  • sel - 根据最近获取到的response构建的 Selector 对象。
  • settings - 当前的 Scrapy settings

在spider中启动shell来查看response

有时您想在spider的某个位置中查看被处理的response, 以确认您期望的response到达特定位置。

这可以通过 scrapy.shell.inspect_response 函数来实现。

以下是如何在spider中调用该函数的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import scrapy

class MySpider(scrapy.Spider):
name = "myspider"
start_urls = [
"http://example.com",
"http://example.org",
"http://example.net",
]

def parse(self, response):
# We want to inspect one specific response.
if ".org" in response.url:
from scrapy.shell import inspect_response
inspect_response(response, self)

# Rest of parsing code.

这个功能很是方便!
最后您可以点击Ctrl-D(Windows下Ctrl-Z)来退出终端,恢复爬取:
1
2
3
>>> ^D
2014-01-23 17:50:03-0400 [scrapy] DEBUG: Crawled (200) <GET http://example.net> (referer: None)
...

注意: 由于该终端屏蔽了Scrapy引擎,您在这个终端中不能使用 fetch 快捷命令(shortcut)。 当您离开终端时,spider会从其停下的地方恢复爬取,正如上面显示的那样。

Item Pipeline

当Item在Spider中被收集之后,它将会被传递到Item Pipeline,一些组件会按照一定的顺序执行对Item的处理。

每个item pipeline组件(有时称之为“Item Pipeline”)是实现了简单方法的Python类。他们接收到Item并通过它执行一些行为,同时也决定此Item是否继续通过pipeline,或是被丢弃而不再进行处理。

以下是item pipeline的一些典型应用:

  • 清理HTML数据
  • 验证爬取的数据(检查item包含某些字段)
  • 查重(并丢弃)将爬取结果保存到数据库中

编写你自己的item pipeline

每个item pipiline组件是一个独立的Python类,同时必须实现以下方法:
process_item(self, item, spider)
每个item pipeline组件都需要调用该方法,这个方法必须返回一个具有数据的dict,或是 Item (或任何继承类)对象, 或是抛出 DropItem 异常,被丢弃的item将不会被之后的pipeline组件所处理。

参数:

  • item (Item 对象或者一个dict) – 被爬取的item
  • spider (Spider 对象) – 爬取该item的spider

此外,他们也可以实现以下方法:

open_spider(self, spider)
当spider被开启时,这个方法被调用。

参数: spider (Spider 对象) – 被开启的spider
close_spider(self, spider)
当spider被关闭时,这个方法被调用

参数: spider (Spider 对象) – 被关闭的spider

Item pipeline 样例

验证价格,同时丢弃没有价格的item

让我们来看一下以下这个假设的pipeline,它为那些不含税(price_excludes_vat 属性)的item调整了 price 属性,同时丢弃了那些没有价格的item:

1
2
3
4
5
6
7
8
9
10
11
12
13
from scrapy.exceptions import DropItem

class PricePipeline(object):

vat_factor = 1.15

def process_item(self, item, spider):
if item['price']:
if item['price_excludes_vat']:
item['price'] = item['price'] * self.vat_factor
return item
else:
raise DropItem("Missing price in %s" % item)

将item写入JSON文件

以下pipeline将所有(从所有spider中)爬取到的item,存储到一个独立地 items.jl 文件,每行包含一个序列化为JSON格式的item:

1
2
3
4
5
6
7
8
9
10
11
import json

class JsonWriterPipeline(object):

def __init__(self):
self.file = open('items.jl', 'wb')

def process_item(self, item, spider):
line = json.dumps(dict(item)) + "\n"
self.file.write(line)
return item

将items写入MongoDB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import pymongo

class MongoPipeline(object):

collection_name = 'scrapy_items'

def __init__(self, mongo_uri, mongo_db):
self.mongo_uri = mongo_uri
self.mongo_db = mongo_db

@classmethod
def from_crawler(cls, crawler):
return cls(
mongo_uri=crawler.settings.get('MONGO_URI'),
mongo_db=crawler.settings.get('MONGO_DATABASE', 'items')
)

def open_spider(self, spider):
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db]

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

def process_item(self, item, spider):
self.db[self.collection_name].insert(dict(item))
return item

MySQL类似

去重

一个用于去重的过滤器,丢弃那些已经被处理过的item。让我们假设我们的item有一个唯一的id,但是我们spider返回的多个item中包含有相同的id:

1
2
3
4
5
6
7
8
9
10
11
12
13
from scrapy.exceptions import DropItem

class DuplicatesPipeline(object):

def __init__(self):
self.ids_seen = set()

def process_item(self, item, spider):
if item['id'] in self.ids_seen:
raise DropItem("Duplicate item found: %s" % item)
else:
self.ids_seen.add(item['id'])
return item

启用一个Item Pipeline组件

为了启用一个Item Pipeline组件,你必须将它的类添加到 ITEM_PIPELINES 配置,就像下面这个例子:

1
2
3
4
ITEM_PIPELINES = {
'myproject.pipelines.PricePipeline': 300,
'myproject.pipelines.JsonWriterPipeline': 800,
}

分配给每个类的整型值,确定了他们运行的顺序,item按数字从低到高的顺序,通过pipeline,通常将这些数字定义在0-1000范围内。

Feed exports

0.10 新版功能.

实现爬虫时最经常提到的需求就是能合适的保存爬取到的数据,或者说,生成一个带有爬取数据的”输出文件”(通常叫做”输出feed”),来供其他系统使用。

Scrapy自带了Feed输出,并且支持多种序列化格式(serialization format)及存储方式(storage backends)。

序列化方式(Serialization formats)

feed输出使用到了 Item exporters 。其自带支持的类型有:

  • JSON
  • JSON lines
  • CSV
  • XML
    您也可以通过 FEED_EXPORTERS 设置扩展支持的属性。

JSON

  • FEED_FORMAT: json
  • 使用的exporter: JsonItemExporter
  • 大数据量情况下使用JSON请参见 这个警告

    JSON lines

  • FEED_FORMAT: jsonlines
  • 使用的exporter: JsonLinesItemExporter

    CSV

  • FEED_FORMAT: csv
  • 使用的exporter: CsvItemExporter
    指定字段和其顺序

    XML

  • ·FEED_FORMAT·: ·xml·
  • 使用的exporter: XmlItemExporter

    Pickle

  • FEED_FORMAT: pickle
  • 使用的exporter: PickleItemExporter

    Marshal

  • FEED_FORMAT: marshal
  • 使用的exporter: MarshalItemExporter

存储(Storages)

使用feed输出时您可以通过使用 URI (通过 FEED_URI 设置) 来定义存储端。 feed输出支持URI方式支持的多种存储后端类型。

自带支持的存储后端有:

  • 本地文件系统
  • FTP
  • S3 (需要 boto)
  • 标准输出
    有些存储后端会因所需的外部库未安装而不可用。例如,S3只有在 boto 库安装的情况下才可使用。

存储URI参数

存储URI也包含参数。当feed被创建时这些参数可以被覆盖:

  • %(time)s - 当feed被创建时被timestamp覆盖
  • %(name)s - 被spider的名字覆盖
    其他命名的参数会被spider同名的属性所覆盖。例如, 当feed被创建时, %(site_id)s 将会被 spider.site_id 属性所覆盖。

下面用一些例子来说明:

  • 存储在FTP,每个spider一个目录:
    • ftp://user:password@ftp.example.com/scraping/feeds/%(name)s/%(time)s.json
  • 存储在S3,每一个spider一个目录:
    • s3://mybucket/scraping/feeds/%(name)s/%(time)s.json

      存储端(Storage backends)

      本地文件系统

      将feed存储在本地系统。
  • URI scheme: file

  • URI样例: file:///tmp/export.csv
  • 需要的外部依赖库: none
    注意: (只有)存储在本地文件系统时,您可以指定一个绝对路径 /tmp/export.csv 并忽略协议(scheme)。不过这仅仅只能在Unix系统中工作。

FTP

将feed存储在FTP服务器。

  • URI scheme: ftp
  • URI样例: ftp://user:pass@ftp.example.com/path/to/export.csv
  • 需要的外部依赖库: none

    S3

    将feed存储在 Amazon S3 。

  • URI scheme: s3

  • URI样例:
    • s3://mybucket/path/to/export.csv
    • s3://aws_key:aws_secret@mybucket/path/to/export.csv
  • 需要的外部依赖库: boto
    您可以通过在URI中传递user/pass来完成AWS认证,或者也可以通过下列的设置来完成:

  • AWS_ACCESS_KEY_ID

  • AWS_SECRET_ACCESS_KEY

标准输出

feed输出到Scrapy进程的标准输出。

  • URI scheme: stdout
  • URI样例: stdout:
  • 需要的外部依赖库: none

设定(Settings)

这些是配置feed输出的设定:

  • FEED_URI (必须)
  • FEED_FORMAT
  • FEED_STORAGES
  • FEED_EXPORTERS
  • FEED_STORE_EMPTY
  • FEED_EXPORT_FIELDS

FEED_URI

Default: None

输出feed的URI。支持的URI协议请参见 存储端(Storage backends) 。

为了启用feed输出,该设定是必须的。

FEED_FORMAT

输出feed的序列化格式。可用的值请参见 序列化方式(Serialization formats) 。

FEED_EXPORT_FIELDS

Default: None

可供导出的字段列表,可选。示例:FEED_EXPORT_FIELDS = ["foo", "bar", "baz"]
使用FEED_EXPORT_FIELDS选项来定义要导出的字段和它们的顺序。
当FEED_EXPORT_FIELDS为空或没有(默认)时,Scrapy使用了在字典中定义的字段或Item子类。
如果导出需要一组固定的字段(这是CSV导出格式的情况),而FEED_EXPORT_FIELDS是空的或没有,那么Scrapy试图从导出的数据中推断字段名——目前它使用的是第一个项目的字段名。

FEED_STORE_EMPTY

Default: False

是否输出空feed(没有item的feed)。

FEED_STORAGES

Default:: {}

包含项目支持的额外feed存储端的字典。 字典的键(key)是URI协议(scheme),值是存储类(storage class)的路径。

FEED_STORAGES_BASE

Default:

1
2
3
4
5
6
7
{
'': 'scrapy.extensions.feedexport.FileFeedStorage',
'file': 'scrapy.extensions.feedexport.FileFeedStorage',
'stdout': 'scrapy.extensions.feedexport.StdoutFeedStorage',
's3': 'scrapy.extensions.feedexport.S3FeedStorage',
'ftp': 'scrapy.extensions.feedexport.FTPFeedStorage',
}

包含Scrapy内置支持的feed存储端的字典。

FEED_EXPORTERS

Default:: {}

包含项目支持的额外输出器(exporter)的字典。 该字典的键(key)是URI协议(scheme),值是 Item输出器(exporter) 类的路径。

FEED_EXPORTERS_BASE
Default:

1
2
3
4
5
6
7
FEED_EXPORTERS_BASE = {
'json': 'scrapy.exporters.JsonItemExporter',
'jsonlines': 'scrapy.exporters.JsonLinesItemExporter',
'csv': 'scrapy.exporters.CsvItemExporter',
'xml': 'scrapy.exporters.XmlItemExporter',
'marshal': 'scrapy.exporters.MarshalItemExporter',
}

包含Scrapy内置支持的feed输出器(exporter)的字典。

Settings

Scrapy设定(settings)提供了定制Scrapy组件的方法。您可以控制包括核心(core),插件(extension),pipeline及spider组件。

设定为代码提供了提取以key-value映射的配置值的的全局命名空间(namespace)。 设定可以通过下面介绍的多种机制进行设置。

设定(settings)同时也是选择当前激活的Scrapy项目的方法(如果您有多个的话)。

指定设定(Designating the settings)

当您使用Scrapy时,您需要声明您所使用的设定。这可以通过使用环境变量: SCRAPY_SETTINGS_MODULE 来完成。

SCRAPY_SETTINGS_MODULE 必须以Python路径语法编写, 如 myproject.settings 。 注意,设定模块应该在 Python import search path 中。

获取设定值(Populating the settings)

设定可以通过多种方式设置,每个方式具有不同的优先级。 下面以优先级降序的方式给出方式列表:

  1. 命令行选项(Command line Options)(最高优先级)
  2. 每个spider的设定
  3. 项目设定模块(Project settings module)
  4. 命令默认设定模块(Default settings per-command)
  5. 全局默认设定(Default global settings) (最低优先级)
    这些设定(settings)由scrapy内部很好的进行了处理,不过您仍可以使用API调用来手动处理。

这些机制将在下面详细介绍。

命令行选项(Command line options)

命令行传入的参数具有最高的优先级。 您可以使用command line 选项 -s (或 --set) 来覆盖一个(或更多)选项。

样例:
scrapy crawl myspider -s LOG_FILE=scrapy.log

每个spider特有设定

每一个spider自己的设置将会覆盖掉一般的设置

项目设定模块(Project settings module)

项目设定模块是您Scrapy项目的标准配置文件。 其是获取大多数设定的方法。例如:: myproject.settings

命令默认设定(Default settings per-command)

每个 Scrapy tool 命令拥有其默认设定,并覆盖了全局默认的设定。 这些设定在命令的类的 default_settings 属性中指定。

默认全局设定(Default global settings)

全局默认设定存储在 scrapy.settings.default_settings 模块, 并在 内置设定参考手册 部分有所记录。

如何访问设定(How to access settings)

设定可以通过Crawler的 scrapy.crawler.Crawler.settings 属性进行访问。其由插件及中间件的 from_crawler 方法所传入:

1
2
3
4
5
6
7
class MyExtension(object):

@classmethod
def from_crawler(cls, crawler):
settings = crawler.settings
if settings['LOG_ENABLED']:
print "log is enabled!"

另外,设定可以以字典方式进行访问。不过为了避免类型错误, 通常更希望返回需要的格式。 这可以通过 Settings API 提供的方法来实现。

设定名字的命名规则

设定的名字以要配置的组件作为前缀。 例如,一个robots.txt插件的合适设定应该为 ROBOTSTXT_ENABLED, ROBOTSTXT_OBEY, ROBOTSTXT_CACHEDIR 等等。

内置设定参考手册

这里以字母序给出了所有可用的Scrapy设定及其默认值和应用范围。

如果给出可用范围,并绑定了特定的组件,则说明了该设定使用的地方。 这种情况下将给出该组件的模块,通常来说是插件、中间件或pipeline。 同时也意味着为了使设定生效,该组件必须被启用。

AWS_ACCESS_KEY_ID

默认: None

连接 Amazon Web services 的AWS access key。 S3 feed storage backend 中使用.

AWS_SECRET_ACCESS_KEY

默认: None

连接 Amazon Web services 的AWS secret key。 S3 feed storage backend 中使用。

BOT_NAME

默认: 'scrapybot'

Scrapy项目实现的bot的名字(也未项目名称)。 这将用来构造默认 User-Agent,同时也用来log。

当您使用 startproject 命令创建项目时其也被自动赋值。

CONCURRENT_ITEMS

默认: 100

Item Processor(即 Item Pipeline) 同时处理(每个response的)item的最大值。

CONCURRENT_REQUESTS

默认: 16

Scrapy downloader 并发请求(concurrent requests)的最大值。

CONCURRENT_REQUESTS_PER_DOMAIN

默认: 8

对单个网站进行并发请求的最大值。

CONCURRENT_REQUESTS_PER_IP

默认: 0

对单个IP进行并发请求的最大值。如果非0,则忽略 CONCURRENT_REQUESTS_PER_DOMAIN 设定, 使用该设定。 也就是说,并发限制将针对IP,而不是网站。

该设定也影响 DOWNLOAD_DELAY: 如果 CONCURRENT_REQUESTS_PER_IP 非0,下载延迟应用在IP而不是网站上。

DEFAULT_ITEM_CLASS

默认: 'scrapy.item.Item'

the Scrapy shell 中实例化item使用的默认类。

DEFAULT_REQUEST_HEADERS

默认:

1
2
3
4
{
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}

Scrapy HTTP Request使用的默认header。由 DefaultHeadersMiddleware 产生。

DEPTH_LIMIT

默认: 0

爬取网站最大允许的深度(depth)值。如果为0,则没有限制。

DEPTH_PRIORITY

默认: 0

整数值。用于根据深度调整request优先级。

如果为0,则不根据深度进行优先级调整。

DEPTH_STATS

默认: True

是否收集最大深度数据。

DEPTH_STATS_VERBOSE

默认: False

是否收集详细的深度数据。如果启用,每个深度的请求数将会被收集在数据中。

DNSCACHE_ENABLED

默认: True

是否启用DNS内存缓存(DNS in-memory cache)。

DNSCACHE_SIZE

Default: 10000

DNS内存缓存大小

DNS_TIMEOUT

Default: 60

DNS查询判断超时的时间长短,支持浮点数

DOWNLOADER

默认: 'scrapy.core.downloader.Downloader'

用于crawl的downloader.

DOWNLOADER_MIDDLEWARES

默认:: {}

保存项目中启用的下载中间件及其顺序的字典。

DOWNLOADER_MIDDLEWARES_BASE

默认:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': 100,
'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware': 300,
'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware': 350,
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': 400,
'scrapy.downloadermiddlewares.retry.RetryMiddleware': 500,
'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': 550,
'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware': 580,
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 590,
'scrapy.downloadermiddlewares.redirect.RedirectMiddleware': 600,
'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': 700,
'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750,
'scrapy.downloadermiddlewares.chunked.ChunkedTransferMiddleware': 830,
'scrapy.downloadermiddlewares.stats.DownloaderStats': 850,
'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware': 900,
}

包含Scrapy默认启用的下载中间件的字典。 永远不要在项目中修改该设定,而是修改 DOWNLOADER_MIDDLEWARES

DOWNLOADER_STATS

默认: True

是否收集下载器数据。

DOWNLOAD_DELAY

默认: 0

下载器在下载同一个网站下一个页面前需要等待的时间。该选项可以用来限制爬取速度, 减轻服务器压力。同时也支持小数:

DOWNLOAD_DELAY = 0.25 # 250 ms of delay
该设定影响(默认启用的) RANDOMIZE_DOWNLOAD_DELAY 设定。 默认情况下,Scrapy在两个请求间不等待一个固定的值, 而是使用0.5到1.5之间的一个随机值 * DOWNLOAD_DELAY 的结果作为等待间隔。

CONCURRENT_REQUESTS_PER_IP 非0时,延迟针对的是每个ip而不是网站。

另外您可以通过spider的 download_delay 属性为每个spider设置该设定。

DOWNLOAD_HANDLERS

默认: {}

保存项目中启用的下载处理器(request downloader handler)的字典。 例子请查看 DOWNLOAD_HANDLERS_BASE 。

DOWNLOAD_HANDLERS_BASE

默认:

1
2
3
4
5
6
{
'file': 'scrapy.core.downloader.handlers.file.FileDownloadHandler',
'http': 'scrapy.core.downloader.handlers.http.HttpDownloadHandler',
'https': 'scrapy.core.downloader.handlers.http.HttpDownloadHandler',
's3': 'scrapy.core.downloader.handlers.s3.S3DownloadHandler',
}

保存项目中默认启用的下载处理器(request downloader handler)的字典。 永远不要在项目中修改该设定,而是修改 DOWNLOADER_HANDLERS

如果需要关闭上面的下载处理器,您必须在项目中的 DOWNLOAD_HANDLERS 设定中设置该处理器,并为其赋值为 None 。 例如,关闭文件下载处理器:

1
2
3
DOWNLOAD_HANDLERS = {
'file': None,
}

DOWNLOAD_TIMEOUT

默认: 180

下载器超时时间(单位: 秒)。

DOWNLOAD_MAXSIZE

Default: 1073741824 (1024MB)

response的下载大小最大限制,不想设置则置为0

DOWNLOAD_WARNSIZE

Default: 33554432 (32MB)

The response size (in bytes) that downloader will start to warn.

If you want to disable it set to 0.

DUPEFILTER_CLASS

默认: 'scrapy.dupefilters.RFPDupeFilter'

用于检测过滤重复请求的类。

默认的 (RFPDupeFilter) 过滤器基于 scrapy.utils.request.request_fingerprint 函数生成的请求fingerprint(指纹)。 如果您需要修改检测的方式,您可以继承 RFPDupeFilter 并覆盖其 request_fingerprint 方法。 该方法接收 Request 对象并返回其fingerprint(一个字符串)。

DUPEFILTER_DEBUG

默认: False

默认情况下, RFPDupeFilter 只记录第一次重复的请求。 设置 DUPEFILTER_DEBUGTrue 将会使其记录所有重复的requests。

EDITOR

默认: depends on the environment

执行 edit 命令编辑spider时使用的编辑器。 其默认为 EDITOR 环境变量。如果该变量未设置,其默认为 vi (Unix系统) 或者 IDLE编辑器(Windows)。

EXTENSIONS

默认:: {}

保存项目中启用的插件及其顺序的字典。

EXTENSIONS_BASE

默认:

1
2
3
4
5
6
7
8
9
10
11
{
'scrapy.extensions.corestats.CoreStats': 0,
'scrapy.telnet.TelnetConsole': 0,
'scrapy.extensions.memusage.MemoryUsage': 0,
'scrapy.extensions.memdebug.MemoryDebugger': 0,
'scrapy.extensions.closespider.CloseSpider': 0,
'scrapy.extensions.feedexport.FeedExporter': 0,
'scrapy.extensions.logstats.LogStats': 0,
'scrapy.extensions.spiderstate.SpiderState': 0,
'scrapy.extensions.throttle.AutoThrottle': 0,
}

可用的插件列表。需要注意,有些插件需要通过设定来启用。默认情况下, 该设定包含所有稳定(stable)的内置插件。

ITEM_PIPELINES

默认: {}

保存项目中启用的pipeline及其顺序的字典。该字典默认为空,值(value)任意。 不过值(value)习惯设定在0-1000范围内。

为了兼容性,ITEM_PIPELINES 支持列表,不过已经被废弃了。

样例:

1
2
3
4
ITEM_PIPELINES = {
'mybot.pipelines.validate.ValidateMyItem': 300,
'mybot.pipelines.validate.StoreMyItem': 800,
}

ITEM_PIPELINES_BASE

默认: {}

保存项目中默认启用的pipeline的字典。 永远不要在项目中修改该设定,而是修改 ITEM_PIPELINES

LOG_ENABLED

默认: True

是否启用logging。

LOG_ENCODING

默认: 'utf-8'

logging使用的编码。

LOG_FILE

默认: None

logging输出的文件名。如果为None,则使用标准错误输出(standard error)。

LOG_FORMAT

Default: '%(asctime)s [%(name)s] %(levelname)s: %(message)s'

log的字符串格式

LOG_DATEFORMAT

Default: '%Y-%m-%d %H:%M:%S'

log的日期格式

LOG_LEVEL

默认: 'DEBUG'

log的最低级别。可选的级别有: CRITICAL、 ERROR、WARNING、INFO、DEBUG。

LOG_STDOUT

默认: False

如果为 True ,进程所有的标准输出(及错误)将会被重定向到log中。例如, 执行 print 'hello' ,其将会在Scrapy log中显示。

MEMDEBUG_ENABLED

默认: False

是否启用内存调试(memory debugging)。

MEMDEBUG_NOTIFY

默认: []

如果该设置不为空,当启用内存调试时将会发送一份内存报告到指定的地址;否则该报告将写到log中。

样例:

1
MEMDEBUG_NOTIFY = ['user@example.com']

MEMUSAGE_ENABLED

默认: False

Scope: scrapy.extensions.memusage

是否启用内存使用插件。当Scrapy进程占用的内存超出限制时,该插件将会关闭Scrapy进程, 同时发送email进行通知。

MEMUSAGE_LIMIT_MB

默认: 0

Scope: scrapy.extensions.memusage

在关闭Scrapy之前所允许的最大内存数(单位: MB)(如果 MEMUSAGE_ENABLED为True)。 如果为0,将不做限制。

MEMUSAGE_NOTIFY_MAIL

默认: False

Scope: scrapy.extensions.memusage

达到内存限制时通知的email列表。

Example:

1
MEMUSAGE_NOTIFY_MAIL = ['user@example.com']

MEMUSAGE_REPORT

默认: False

Scope: scrapy.extensions.memusage

每个spider被关闭时是否发送内存使用报告。

MEMUSAGE_WARNING_MB

默认: 0

Scope: scrapy.extensions.memusage

在发送警告email前所允许的最大内存数(单位: MB)(如果 MEMUSAGE_ENABLED为True)。 如果为0,将不发送警告。

NEWSPIDER_MODULE

默认: ''

使用 genspider 命令创建新spider的模块。

样例:
NEWSPIDER_MODULE = 'mybot.spiders_dev'

RANDOMIZE_DOWNLOAD_DELAY

默认: ·True·

如果启用,当从相同的网站获取数据时,Scrapy将会等待一个随机的值 (0.5到1.5之间的一个随机值 * DOWNLOAD_DELAY)。

该随机值降低了crawler被检测到(接着被block)的机会。某些网站会分析请求, 查找请求之间时间的相似性。

随机的策略与 wget --random-wait 选项的策略相同。

DOWNLOAD_DELAY 为0(默认值),该选项将不起作用。

REDIRECT_MAX_TIMES

默认: 20

定义request允许重定向的最大次数。超过该限制后该request直接返回获取到的结果。 对某些任务我们使用Firefox默认值。

REDIRECT_MAX_METAREFRESH_DELAY

默认: 100

有些网站使用 meta-refresh 重定向到session超时页面, 因此我们限制自动重定向到最大延迟(秒)。 =>有点不肯定:

REDIRECT_PRIORITY_ADJUST

默认: +2

修改重定向请求相对于原始请求的优先级。 负数意味着更多优先级。

ROBOTSTXT_OBEY

默认: False

Scope: scrapy.downloadermiddlewares.robotstxt

如果启用,Scrapy将会尊重 robots.txt策略。

SCHEDULER

默认: 'scrapy.core.scheduler.Scheduler'

用于爬取的调度器。

SPIDER_CONTRACTS

默认:: {}

保存项目中启用用于测试spider的scrapy contract及其顺序的字典。

SPIDER_CONTRACTS_BASE

默认:

1
2
3
4
5
{
'scrapy.contracts.default.UrlContract' : 1,
'scrapy.contracts.default.ReturnsContract': 2,
'scrapy.contracts.default.ScrapesContract': 3,
}

保存项目中默认启用的scrapy contract的字典。 永远不要在项目中修改该设定,而是修改 SPIDER_CONTRACTS

SPIDER_LOADER_CLASS

Default: 'scrapy.spiderloader.SpiderLoader'

spider读取的模块

SPIDER_MIDDLEWARES

默认:: {}

保存项目中启用的下载中间件及其顺序的字典。

SPIDER_MIDDLEWARES_BASE

默认:

1
2
3
4
5
6
7
{
'scrapy.spidermiddlewares.httperror.HttpErrorMiddleware': 50,
'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': 500,
'scrapy.spidermiddlewares.referer.RefererMiddleware': 700,
'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware': 800,
'scrapy.spidermiddlewares.depth.DepthMiddleware': 900,
}

保存项目中默认启用的spider中间件的字典。 永远不要在项目中修改该设定,而是修改 SPIDER_MIDDLEWARES

SPIDER_MODULES

默认: []

Scrapy搜索spider的模块列表。

样例:
SPIDER_MODULES = ['mybot.spiders_prod', 'mybot.spiders_dev']

STATS_CLASS

默认: 'scrapy.statscollectors.MemoryStatsCollector'

收集数据的类。该类必须实现 状态收集器(Stats Collector) API.

STATS_DUMP

默认: True

当spider结束时dump Scrapy状态数据 (到Scrapy log中)。

STATSMAILER_RCPTS

默认: [] (空list)

spider完成爬取后发送Scrapy数据。

TELNETCONSOLE_ENABLED

默认: True

表明 telnet 终端 (及其插件)是否启用的布尔值。

TELNETCONSOLE_PORT

默认: [6023, 6073]

telnet终端使用的端口范围。如果设置为 None0 , 则使用动态分配的端口。

TEMPLATES_DIR

默认: scrapy模块内部的 templates

使用 startproject 命令创建项目时查找模板的目录。

URLLENGTH_LIMIT

默认: 2083

Scope: spidermiddlewares.urllength

爬取URL的最大长度。

USER_AGENT

默认: "Scrapy/VERSION (+http://scrapy.org)"

爬取的默认User-Agent,除非被覆盖。

后续

自己只是记录了一些已经用过或者正需要用的东西,因为官方文档到后续的一些扩展,自己认为还是需要用到的时候再去学习,之后再继续记录。

一分一毛,也是心意。