Welcome to xpaw 0.12.0¶
Key Features¶
- A web scraping framework used to crawl web pages
- Data extraction tools used to extract structured data from web pages
Installation¶
安装xpaw需要Python 3.5.3或更高版本的环境支持。
可以使用如下命令安装xpaw:
$ pip install xpaw
如果安装过程中遇到lxml安装失败的情况,可参考 lxml installation 。
Table of Contents¶
Make Requests¶
如果我们只是想下载URL对应的网页,但又不想写爬虫这么复杂的东西,那么我们可以直接借助 make_requests()
函数发起请求并获取结果。
from xpaw import make_requests, HttpRequest
if __name__ == '__main__':
requests = ['http://unknown', 'http://python.org', HttpRequest('http://python.org')]
results = make_requests(requests)
print(results)
请求可以是 str
或 HttpRequest
,如果是 str
则认为提供的是 GET
请求的URL。
返回结果是一个 list
,和发起的请求一一对应,可能是 HttpResponse
或 Exception
。
因此可以先通过 isinstance
判断是否是正常返回的结果 HttpResponse
。
其次,如果是 Exception
,则表示请求出现了错误,例如常见的有 ClientError
, HttpError
(非2xx的HTTP状态码)。
使用 make_requests()
可以实现请求的并发执行,并提供了错误重试等诸多可选功能。
Note
make_requests()
在 Spider
中使用会报错。
在 Spider
中处理请求的过程已经是并发的,因而也无需使用 make_requests()
。
-
xpaw.run.
make_requests
(requests, **kwargs)¶ Parameters: - requests (str or
HttpRequest
) – 请求列表 - kwargs – 相关配置参数,详见 Settings
- requests (str or
Tutorial I: First Spider¶
在这个tutorial中,我们的爬取目标为: quotes.toscrape.com ,在此特别感谢 scrapinghub 提供了这个测试爬虫的网站。
我们的需求为爬取网站中所有的quotes并以json的形式保存下来,每个quote包含如下几个字段:
名称 | 含义 |
---|---|
text | quote的内容 |
author | quote作者 |
author_url | 作者的相关链接 |
tags | quote的标签列表 |
例如对于这个quote:

我们得到的json数据为:
{
"text": "“I have not failed. I've just found 10,000 ways that won't work.”",
"author": "Thomas A. Edison",
"author_url": "http://quotes.toscrape.com/author/Thomas-A-Edison",
"tags": ["edison", "failure", "inspirational", "paraphrased"]
}
Spider Overview¶
我们编写的spider需要继承 xpaw.Spider
类,需要实现的功能包括:
- 生成初始入口链接
- 从爬取的网页中提取出所需的数据和后续待爬取的链接
我们首先给出spider的完整代码,然后再逐一进行解释:
from urllib.parse import urljoin
import json
from xpaw import Spider, HttpRequest, Selector, run_spider
class QuotesSpider(Spider):
quotes = []
def start_requests(self):
yield HttpRequest('http://quotes.toscrape.com/', callback=self.parse)
def parse(self, response):
selector = Selector(response.text)
for quote in selector.css('div.quote'):
text = quote.css('span.text')[0].text
author = quote.css('small.author')[0].text
author_url = quote.css('small+a')[0].attr('href')
author_url = urljoin(str(response.url), author_url)
tags = quote.css('div.tags a').text
self.quotes.append(dict(text=text, tags=tags,
author=author, author_url=author_url))
next_page = selector.css('li.next a')
if len(next_page) > 0:
next_page_url = urljoin(str(response.url), next_page[0].attr('href'))
yield HttpRequest(next_page_url, callback=self.parse)
def close(self):
with open('quotes.json', 'w') as f:
json.dump(self.quotes, f, ensure_ascii=False, indent=4)
if __name__ == '__main__':
run_spider(QuotesSpider, log_level='DEBUG')
Start Requests¶
xpaw在加载spider后会调用其 start_requests
函数来获取整个爬取过程的入口链接,我们需要在该函数中生成入口链接并用HttpRequest进行封装。
在这个任务中,我们从网站首页开始即可遍历所有quotes所在的网页,因此入口链接选择网站的首页即可。
def start_requests(self):
yield HttpRequest('http://quotes.toscrape.com/', callback=self.parse)
Note
start_requests
函数的返回值需为可迭代对象,如tuple, list, generator等。
HttpRequest的 callback
用来指定该request对应的response由哪个函数来处理。
Note
callback
只能指定为spider自身的成员函数。
Data & Links¶
xpaw成功获取到response之后,会调用在request中指定的 callback
函数来处理response,如果没有指定则会默认调用spider中名为 parse
的函数,这时如果没有定义 parse
函数,则会抛出异常。
在这个任务中,我们在 parse
函数中提取出quote的各项属性和翻页链接。
Note
- spider中处理response的函数的返回值需为
None
或可迭代对象,如tuple, list, generator等。 - 在提取链接时我们不需要关注提取出URL是否重复了,xpaw会自动帮我们完成URL去重的工作。
HTML Features of Data¶
首先我们关注如何提取网页中的quote。
通过查看网页的源代码,我们发现每个quote是用类似如下的HTML代码进行描述的:
<div class="quote" itemscope itemtype="http://schema.org/CreativeWork">
<span class="text" itemprop="text">“I have not failed.
I've just found 10,000 ways that won't work.”</span>
<span>by <small class="author" itemprop="author">Thomas A. Edison</small>
<a href="/author/Thomas-A-Edison">(about)</a>
</span>
<div class="tags">
Tags:
<a class="tag" href="/tag/edison/page/1/">edison</a>
<a class="tag" href="/tag/failure/page/1/">failure</a>
<a class="tag" href="/tag/inspirational/page/1/">inspirational</a>
<a class="tag" href="/tag/paraphrased/page/1/">paraphrased</a>
</div>
</div>
我们可以发现每个quote都是位于一个 class=quote
的 <div>
标签中,以及quote的各项属性 (text, author, author_url, tags) 所在节点的特征:
- text : 位于
class=text
的<span>
标签中 - author : 位于
class=author
的<small>
标签中 - author_url :
<small>
标签紧邻的<a>
标签的href
属性 - tags : 所有
class=tag
的<a>
标签中
HTML Features of Links¶
接下来我们关注如何提取网页中的链接。
同样的,通过查看网页原代码,我们看到 “Next →” 附近的HTML代码:
<nav>
<ul class="pager">
<li class="previous">
<a href="/page/1/"><span aria-hidden="true">←</span> Previous</a>
</li>
<li class="next">
<a href="/page/3/">Next <span aria-hidden="true">→</span></a>
</li>
</ul>
</nav>
我们发现翻页 “Next →” 的对应着 class=next
的 <li>
标签中的 <a>
标签的 href
属性。
Extracting Data & Links¶
在得到了数据以及链接相关的HTML特征之后,我们将特征用CSS Selector语法对其描述,并借助 Selector
提取quote和翻页的链接:
def parse(self, response):
selector = Selector(response.text)
for quote in selector.css('div.quote'):
text = quote.css('span.text')[0].text
author = quote.css('small.author')[0].text
author_url = quote.css('small+a')[0].attr('href')
author_url = urljoin(str(response.url), author_url)
tags = quote.css('div.tags a').text
self.quotes.append(dict(text=text, tags=tags,
author=author, author_url=author_url))
next_page = selector.css('li.next a')
if len(next_page) > 0:
next_page_url = urljoin(str(response.url), next_page[0].attr('href'))
yield HttpRequest(next_page_url, callback=self.parse)
有关CSS Selector语法的详细信息,可以参考 CSS Selector Reference 。
Storing Data¶
在这个任务中,我们在spider的 close
函数中完整了数据的保存。
当爬取工作完成后,xpaw会调用spider的 close
函数 (如果存在的话),因此我们借机在该函数中将所有爬取到的quotes以json的格式写入到文件中。
def close(self):
with open('quotes.json', 'w') as f:
json.dump(self.quotes, f, ensure_ascii=False, indent=4)
Spider¶
用户自定义的spider需要继承 xpaw.spider.Spider
,并重写如下函数:
start_requests()
:返回初始入口URL构成的HttpRequest
。parse()
:返回从爬取的网页中提取出所需的数据和后续待爬取的HttpRequest
。
Note
parse()
是默认处理 HttpResponse
的函数,如果在每个生成的 HttpRequest
中都通过 callback
指定了相应的处理函数 ,也可以不重写该函数。
Spider API¶
-
class
xpaw.spider.
Spider
¶ 用户自定义的spider需要继承此类。
-
classmethod
from_crawler
(crawler)¶ Parameters: crawler (Crawler) – crawler crawler通过该函数实例化spider,在该函数中会调用spider的构造器
-
logger
¶ 提供纪录日志的logger。
-
log
(message, *args, level=logging.INFO, **kwargs)¶ 通过logger纪录日志。
-
start_requests
()¶ 生成初始请求
Returns: HttpRequest
的可迭代对象。
-
parse
(response)¶ 解析爬取结果
Parameters: response (HttpResponse) – 爬取结果。 Returns: 可迭代对象,可以是新的请求 HttpRequest
,和提取的数据Item
、dict
等。
-
open
()¶ 爬虫开始工作前会调用该函数。
-
close
()¶ 爬虫完成工作时会调用该函数。
-
classmethod
Parsing Data to Callback Functions¶
我们可以通过 HttpRequest
的 callback
指定spider的某个成员函数来处理得到的 HttpResponse
。
例如:
def parse_index_page(self, response):
yield xpaw.HttpRequest("http://www.example.com/some_page.html",
callback=self.parse_some_page)
def parse_some_page(self, response):
# handle the response of "http://www.example.com/some_page.html"
self.log('Visited: %s', response.url)
有些时候,我们同时想传递一些和 HttpRequest
相关的参数并能够在callback函数中获取到。
例如,我们可能希望纪录父级页面的URL,即是由哪个页面跳转而来的。
我们可以通过 HttpRequest
的 meta
实现参数的传递。
以下是一个纪录父级页面的URL的示例:
def parse_index_page(self, response):
request = xpaw.HttpRequest("http://www.example.com/some_page.html",
callback=self.parse_some_page)
request.meta['referer'] = response.url
yield request
def parse_some_page(self, response):
self.log('Visited: %s', response.url)
self.log('Referer: %s', response.meta['referer'])
Note
HttpResponse
的meta
属性即为对应HttpRequest
的meta
属性。- 在使用
HttpRequest
的meta
传递参数时,请避免和中间件使用的关键字冲突。
Request Error Handling in Errback Functions¶
我们可以通过 HttpRequest
的 errback
指定spider的某个成员函数来处理请过程中出现的异常。
下面给出了一个区分不同的异常并进行处理的示例:
class ErrorHandlingSpider(Spider):
start_urls = [
"http://www.python.org/", # 200 OK
"http://www.httpbin.org/status/404", # 404 Not Found
"http://www.httpbin.org/status/500", # 500 Service Not Available
"http://unknown/", # ClientError
]
def start_requests(self):
for url in self.start_urls:
yield HttpRequest(url, errback=self.handle_error)
def parse(self, response):
self.logger.info('Successful response: %s', response)
def handle_error(self, request, error):
if isinstance(error, HttpError):
response = error.response
self.logger.error('HttpError on %s: HTTP status=%s', request.url, response.status)
elif isinstance(error, ClientError):
self.logger.error('ClientError on %s: %s', request.url, error)
if __name__ == '__main__':
run_spider(ErrorHandlingSpider, retry_enabled=False)
Request & Response¶
我们通过 HttpRequest
和 HttpResponse
封装爬取的请求和对应的结果。
通常情况下, HttpRequest
一部分来自于spider中 start_requests()
方法生成的初始请求,另一部分来自于 parse()
方法解析页面得到的新的请求。
针对每个 HttpRequest
,如果请求成功xpaw会生成对应的 HttpResponse
,一般无需我们自己去构造 HttpResponse
。
Request API¶
-
class
xpaw.http.
HttpRequest
(url, method="GET", body=None, params=None, headers=None, proxy=None, timeout=20, verify_ssl=False, allow_redirects=True, auth=None, proxy_auth=None, priority=None, dont_filter=False, callback=None, errback=None, meta=None, render=None)¶ 用户通过此类封装HTTP请求。
Parameters: - url (str or
URL
) – URL地址 - method (str) – HTTP method,
GET
、POST
等 - body (bytes or str or dict) – 请求发送的数据。如果类型为
dict
,会默认为发送json格式的数据。 - params (dict) – 请求参数
- headers (dict or
HttpHeaders
) – HTTP headers - proxy (str) – 代理地址
- timeout (float) – 请求超时时间
- verify_ssl (bool) – 是否校验SSL
- allow_redirects (bool) – 是否自动重定向
- auth (tuple) – 认证信息,用户名和密码
- proxy_auth (tuple) – 代理认证信息,用户名和密码
- priority (float) – 请求的优先级
- dont_filter (bool) – 是否经过去重过滤器
- callback (str or method) – 请求成功时的回调函数,必须是spider的成员函数,也可以传递递函数名称
- errback (str or method) – 请求失败时的回调函数,必须是spider的成员函数,也可以传递函数名称
- meta (dict) –
meta
属性的初始值,用于存储请求相关的元信息 - render – 是否使用浏览器渲染
-
url
¶ URL地址
-
method
¶ HTTP method,
GET
、POST
等
-
body
¶ 请求发送的数据
-
headers
¶ HTTP headers
-
proxy
¶ 代理地址
-
timeout
¶ 请求超时时间
-
verify_ssl
¶ 是否校验SSL
-
allow_redirects
¶ 是否自动重定向
-
auth
¶ 认证信息,用户名和密码
-
proxy_auth
¶ 代理认证信息,用户名和密码
-
priority
¶ 请求的优先级
-
dont_filter
¶ 是否经过去重过滤器。xpaw会根据此属性决定该请求是否经过去重过滤器,如果经过去重过滤器,被认定为重复的请求会被忽略。
-
callback
¶ 请求成功时的回调函数,必须是spider的成员函数,也可以传递递函数名称。
-
errback
¶ 请求失败时的回调函数,必须是spider的成员函数,也可以传递函数名称。
-
render
¶ 是否使用浏览器渲染
-
copy
()¶ 复制request
-
replace
(**kwargs)¶ 复制request并替换部分属性
- url (str or
-
class
xpaw.http.
HttpHeaders
¶ 同
tornado.httputil.HTTPHeaders
。
Response API¶
-
class
xpaw.http.
HttpResponse
(url, status, body=None, headers=None, request=None, encoding=None)¶ Parameters: - url (str) – URL地址
- status (int) – HTTP状态码
- body (bytes) – HTTP body
- headers (dict or
HttpHeaders
) – HTTP headers - request (HttpRequest) – 爬虫请求
- encoding (str) – HTTP body的编码格式
-
url
¶ URL地址,如果是xpaw生成的response则类型为
URL
。
-
status
¶ HTTP状态码
-
body
¶ HTTP body
-
encoding
¶ 指定HTTP body的编码,如果没有指定,则会根据response的header和body进行自动推断。
-
headers
¶ HTTP headers,如果是xpaw生成的response则类型为
HttpHeaders
。
-
request
¶ 对应的
HttpRequest
-
meta
¶ 只读属性,即为对应的
HttpRequest
的meta
属性。
-
copy
()¶ 复制response。
-
replace
(**kwargs)¶ 复制response并替换部分属性。
Selector¶
Selector是基于 lxml 和 cssselect 封装的网页内容选择器,用于定位数据所在的网页节点,并对数据进行提取。 Selector相关API可以参考 Selector API 。
Selector Usage¶
我们通过一个实例来说明Selector的使用方法,相关代码位于 examples/selector_usage.py 。
下面给出的是 quotes.toscrape.com 的简化版网页,我们需要提取网页中展示的quote。
<html>
<head>
<title>Quotes to Scrape</title>
<link rel="stylesheet" href="/static/main.css">
</head>
<body>
<div class="quote" itemscope itemtype="http://schema.org/CreativeWork">
<span class="text" itemprop="text">“I have not failed. I've just found 10,000 ways that won't work.”</span>
<span>by <small class="author" itemprop="author">Thomas A. Edison</small>
<a href="/author/Thomas-A-Edison">(about)</a>
</span>
<div class="tags">
Tags:
<a class="tag" href="/tag/edison/page/1/">edison</a>
<a class="tag" href="/tag/failure/page/1/">failure</a>
<a class="tag" href="/tag/inspirational/page/1/">inspirational</a>
<a class="tag" href="/tag/paraphrased/page/1/">paraphrased</a>
</div>
</div>
<div class="quote" itemscope itemtype="http://schema.org/CreativeWork">
<span class="text" itemprop="text">“It is our choices, Harry, that show what we truly are, far more than our abilities.”</span>
<span>by <small class="author" itemprop="author">J.K. Rowling</small>
<a href="/author/J-K-Rowling">(about)</a>
</span>
<div class="tags">
Tags:
<a class="tag" href="/tag/abilities/page/1/">abilities</a>
<a class="tag" href="/tag/choices/page/1/">choices</a>
</div>
</div>
</body>
</html>
Constructing Selectors¶
假设上面的网页内容存储在变量 text
中,我们可以通过如下的方式构造Selector:
from xpaw import Selector
selector = Selector(text)
Locating Elements¶
我们可以使用CSS Selector语法或XPath语法定位数据所在的节点。
有关CSS Selector语法的详细信息,可以参考 CSS Selector Reference 。 有关XPath语法的详细信息可以参考 XPath Syntax 。
首先我们需要观察数据所在节点的在标签层次上的特征,然后再将这种特征通过CSS Selector语法或XPath语法进行描述。
例如,我们可以观察到每个quote都在一个 class=quote
的 <div>
标签中,每个quote的内容都在一个 class=text
的 span
标签中。
接下来,我们可以用CSS Selector语法对这些特征进行描述,并借助Selector来提取quote的内容:
print('# CSS Selector, content of quotes:')
for quote in selector.css('div.quote'):
print(quote.css('span.text')[0].text)
# CSS Selector, content of quotes:
“I have not failed. I've just found 10,000 ways that won't work.”
“It is our choices, Harry, that show what we truly are, far more than our abilities.”
也可以用XPath语法对这些特征进行描述,并借助Selector来提取quote的内容:
print('# XPath, content of quotes:')
for quote in selector.xpath('//div[@class="quote"]'):
print(quote.xpath('.//span[@class="text"]')[0].text)
# XPath, content of quotes:
“I have not failed. I've just found 10,000 ways that won't work.”
“It is our choices, Harry, that show what we truly are, far more than our abilities.”
根据观察的特征不同,我们可能会写出不同的表达式。
例如,我们也可以认为每个quote的内容在 itemprop="text"
的 span
标签中:
for quote in selector.css('div.quote'):
print(quote.css('span[itemprop="text"]')[0].text)
css
和 xpath
是可以级联使用的,例如:
for t in selector.css('div.quote').css('span.text'):
print(t.text)
css
和 xpath
也可以混合使用,例如:
for t in selector.xpath('//div[@class="quote"]').css('span.text'):
print(t.text)
Extracting Data¶
除了前面展示的可以通过 text
属性获取节点中不包含标签的文本,我们还可以通过 string
属性获取完整的带标签的内容:
print('# CSS Selector, content of quotes, with HTML tags:')
for quote in selector.css('div.quote'):
print(quote.css('span.text')[0].string)
# CSS Selector, content of quotes, with HTML tags:
<span class="text" itemprop="text">“I have not failed. I've just found 10,000 ways that won't work.”</span>
<span class="text" itemprop="text">“It is our choices, Harry, that show what we truly are, far more than our abilities.”</span>
对于选择出的节点列表,同样可以采用这样的方式获取数据,得到的即为数据的列表。 例如我们获取每个quote下面所有的tag:
print('# CSS Selector, quote tags')
for quote in selector.css('div.quote'):
print(quote.css('a.tag').text)
# CSS Selector, quote tags
['edison', 'failure', 'inspirational', 'paraphrased']
['abilities', 'choices']
如果需要获取节点属性值,则可以使用 attr()
。
例如我们获取quote作者的链接:
print('# CSS Selector, author urls')
for quote in selector.css('div.quote'):
print(quote.css('small+a')[0].attr('href'))
# CSS Selector, author urls
/author/Thomas-A-Edison
/author/J-K-Rowling
Selector API¶
-
class
xpaw.selector.
Selector
(text=None, root=None, text_type=None)¶ 节点和数据的选择器。
Parameters: - text (str) – HTML或XML文本
- root – 根节点,
text
和root
只需指定其中一个,当指定text
时,会自动创建root
。 - text_type (str) –
html
或xml
,默认为html
。
-
root
¶ 根节点
-
css
(css, **kwargs)¶ 使用CSS Selector语法选择节点。
Parameters: css (str) – CSS Selector语法描述 Returns: 选择的节点对应的 SelectorList
-
xpath
(xpath, **kwargs)¶ 使用XPath语法选择节点。
Parameters: xpath (str) – XPath语法描述 Returns: 选择的节点对应的 SelectorList
-
string
¶ 获取节点包括标签在内的全部内容。
-
text
¶ 获取节点去掉标签后的文本内容。
-
attr
(name)¶ 获取节点的属性。
Parameters: name (str) – 属性名称
-
class
xpaw.selector.
SelectorList
¶ SelectorList
是由Selector
组成的list
。-
css
(css, **kwargs)¶ 对其中的每一个
Selector
使用CSS Selector语法选择节点。Parameters: css (str) – CSS Selector语法描述 Returns: 选择的节点对应的 SelectorList
-
xpath
(xpath, **kwargs)¶ 对其中的每一个
Selector
使用XPath语法选择节点。Parameters: xpath (str) – XPath语法描述 Returns: 选择的节点对应的 SelectorList
-
string
¶ 获取各个节点包括标签在内的全部内容,返回
list
。
-
text
¶ 获取各个节点去掉标签后的文本内容,返回
list
。
-
attr
(name)¶ 获取各个节点的属性,返回
list
。Parameters: name (str) – 属性名称
-
Settings¶
爬虫相关配置项可以通过如下几种方式设定:
- 命令行 - 直接在命令行中设定的配置项。
- 命令行配置文件 - 在命令行中通过参数
-c, --config
指定的配置文件中的配置项。 - 工程配置文件 - 在工程的配置文件
config.py
中设定的配置项。 - 默认配置 - 默认的配置项。
配置的优先级为: 命令行 > 命令行配置文件 > 工程配置文件 > 默认配置 ,对于同一配置项,高优先级的配置会覆盖低优先级的配置。
在 make_requests
、 run_spider
等函数中传递的关键字参数的优先级视为和命令行参数一致。
接下来我们会按类别依次给出爬虫相关的各个配置项。
Running¶
Downloading¶
chrome_renderer_options¶
- Type:
dict
Chrome渲染器的配置,以 'NAME': {'arguments': [], 'experimental_options': {}}
的方式进行配置,其中 NAME
表示渲染器类别的名称。
user_agent¶
- Default:
:desktop
指定HTTP请求头的User-Agent字段。
以 :
开头表示命令模式,命令分为终端类型和浏览器类型, 终端类型包括 desktop
、mobile
,浏览器类型包括 chrome
。
多个命令之间用逗号 ,
隔开,如 :mobile,chrome
表示移动端的Chrome浏览器。
其他字符串则直接视为User-Agent。
Note
只有当 default_headers 中没有设置 User-Agent
时, user_agent 配置才会生效。
random_user_agent¶
- Default:
False
随机设定HTTP请求头的User-Agent字段。
当 user_agent 为命令模式时,随机生成符合其约束的User-Agent;当 user_agent 为普通字符串时,则会覆盖其设置。
Retry¶
retry_http_status¶
- Default:
None
- Type:
list
,tuple
进行重试的HTTP状态码。
可以用 x
表示通配,例如 20x
表示 200
、 202
等所有 20
开头的状态码, 4xx
表示所有 4
开头的状态码。
前面加 !
表示取反,例如 !2xx
表示所有不是以 2
开头的状态码。
Spider Behaviour¶
Errors¶
Built-in Errors¶
这里给出了内置的错误类型。
-
class
xpaw.errors.
NotEnabled
¶ 在加载组件的时候抛出的异常,表示该组件未启用。
-
class
xpaw.errors.
ClientError
¶ 在downloader发起请求过程中抛出的异常,例如服务器无法访问等。
-
class
xpaw.errors.
HttpError
¶ 非2xx响应抛出的异常。
-
class
xpaw.errors.
IgnoreRequest
¶ 在处理
HttpRequest
时抛出的异常,表示忽略该request,例如到达了一定的重试次数等。
-
class
xpaw.errors.
IgnoreItem
¶ 在处理
Item
时抛出的异常,表示忽略该item。
-
class
xpaw.errors.
UsageError
¶ xpaw相关命令使用方法不正确时抛出的异常。
-
class
xpaw.errors.
CloseCrawler
¶ 在spider的处理
HttpResponse
的回调函数中可以抛出该异常,主动停止crawler。
Architecture Overview¶
这里我们会对xpaw的结构进行简要的介绍。
首先我们会给出爬虫运行过程中的数据流图,接着我们会对数据流中呈现的各个组件进行简要的介绍。
Data Flow¶
数据流以crawler为核心,并由crawler进行控制和驱动:

- crawler从spider中获取初始请求
HttpRequest
。 - crawler将得到
HttpRequest
放入到queue中。 - crawler不停地从queue中获取待处理的
HttpRequest
。 - crawler将
HttpRequest
交由downloader处理。 - downloader完成下载后生成
HttpResponse
返回给crawler。 - crawler将得到的
HttpResponse
交由spider处理。 - spider处理
HttpResponse
并提取数据Item
和新的请求HttpRequest
。 - crawler将得到的
HttpRequest
放入到queue中。
爬虫会持续运行直到所有生成的requests都被处理完且不再生成新的requests为止。
Core API¶
Crawler API¶
通常用户自定义的组件可以在class中定义类似如下的函数,来达到获取配置的目的:
@classmethod
def from_crawler(cls, crawler):
return cls(crawler.config)
对于用户自定义的组件,xpaw会首先检查是否存在名为 from_crawler
的函数,如果存在则会通过调用 from_crawler
来实例化对象:
foo = FooClass.from_crawler(crawler)
如果不存在该函数,则会调用默认的不含参数的构造器来实例化:
foo = FooClass()
对于spider来讲,由于强制要求继承 Spider
类,且在该类中已经实现了 from_crawler
函数,我们可以直接在spider中通过 self.config
来获取配置,通过 self.crawler
来获取crawler。
from_crawler
提供了获取crawler的途径,通过crawler我们不仅可以获取到 config
,也可以获取到其他的我们需要使用的crawler的属性。
-
class
xpaw.crawler.
Crawler
(config)¶ 本地模式的crawler
Parameters: config (Config) – 爬虫相关的配置项 -
config
¶
爬虫相关的配置项,对于
config
的使用可以参考 Config API 。-
Config API¶
-
class
xpaw.config.
Config
(__values=None, **kwargs)¶ 管理爬虫配置的类。
-
get
(name, default=None)¶ 获取配置
Parameters: - name (str) – 参数名称
- default – 缺省值
-
getbool
(name, default=None)¶ 获取
bool
型参数,如果值不能转换为bool
类型,返回None
。
-
getint
(name, default=None)¶ 获取
int
型参数,如果值不能转换为int
类型,返回None
。
-
getint
(name, default=None) 获取
float
型参数,如果值不能转换为float
类型,返回None
。
-
getlist
(name, default=None)¶ 将参数值封装为
list
并返回。 如果参数值是str
,则会根据,
分隔为多个参数值。
-
set(name, value):
设置参数值
Parameters: - name (str) – 参数名称
- value – 参数值
-
update(values):
更新参数
Parameters: values (dict or Config
) – 新的参数
-
delete(name):
删除参数
Parameters: name – 参数名称
-
copy
()¶ 复制配置
-
Specific Problems¶
Cron Job¶
可以使用 @every
实现定时任务,每隔设定的时间会重复执行被修饰的 start_requests
函数:
from xpaw import Spider, HttpRequest, Selector, every, run_spider
class CronJobSpider(Spider):
@every(seconds=10)
def start_requests(self):
yield HttpRequest("http://news.baidu.com/", callback=self.parse, dont_filter=True)
def parse(self, response):
selector = Selector(response.text)
hot = selector.css("div.hotnews a").text
self.log("Hot News:")
for i in range(len(hot)):
self.log("%s: %s", i + 1, hot[i])
if __name__ == '__main__':
run_spider(CronJobSpider)
@every
可传入的参数:
hours
: 间隔的小时数minutes
: 间隔的分钟数seconds
: 间隔的秒数
注意需要通过参数 dont_filter=True
来设置 HttpRequest
不经过去重过滤器,否则新产生的 HttpRequest
会视为重复的请求。
Dynamic Webpages¶
一种解决方案是借助Chrome的调试工具找到动态内容请求的接口,然后在爬虫中直接从接口拿数据。
另一种方案是在 HttpRequest
中设置 render=True
,则会默认使用Chrome浏览器对页面进行渲染。
from xpaw import Spider, HttpRequest, Selector, run_spider
class RenderingSpider(Spider):
def start_requests(self):
yield HttpRequest('http://quotes.toscrape.com/js/', callback=self.parse, render=True)
def parse(self, response):
selector = Selector(response.text)
for quote in selector.css('div.quote'):
text = quote.css('span.text')[0].text
author = quote.css('small.author')[0].text
self.log(author + ": " + text)
if __name__ == '__main__':
run_spider(RenderingSpider)
Note
如果需要使用渲染功能,则需要提前装好Chrome驱动。
Changelog¶
0.12.0 (2019-08-10)¶
- 移除爬虫工程初始化相关功能,推荐使用单文件spider或指定爬虫启动脚本
- 统一middleware、pipeline、extension等概念,统一由
extensions
配置爬虫的拓展
0.11.2 (2019-08-06)¶
- 重构Chrome渲染器,由每次新建Chrome进程变为维护每个Chrome进程的tab
- 添加
chrome_renderer_options
配置项,实现同时运行多个具有不同设置的Chrome渲染器 - 修复爬虫工程的配置模版
0.11.1 (2019-07-29)¶
- 移除
HttpRequest
中的params
属性,但在构建HttpRequest
时依然可以传入params
0.11.0 (2019-07-11)¶
- 移除对aiohttp的依赖,改由tornado实现HTTP请求,新增pycurl依赖
- 添加基于Selenium和Chrome driver的渲染器
- 添加Docker镜像
jadbin/xpaw
,便于构建爬虫运行环境 - 暂时移除对cookies和cookie jar的支持
- 组件cluster更名为crawler,包含cluster命名的模块、对象、函数、配置等均作出了相应的替换
- 运行爬虫工程的
run_crawler
接口更名为run_spider_project
- 非2xx的HttpResponse将视为请求失败并抛出
HttpError
异常进入错误处理流程 - RetryMiddleware不再raise IgnoreRequest,即因达到重试次数上限而导致请求失败时不再封装为IgnoreRequest,将保留原有的HttpResponse或异常
- HttpRequest
proxy
,timeout
,verify_ssl
,allow_redirects
,auth
,proxy_auth
由在meta
中配置改为直接作为HttpRequest的属性 - Selector之前在遇到异常时会返回空数组,现在改为直接抛出异常
- 修改ProxyMiddleware的配置格式
- 移除ImitatingProxyMiddleware
- 修改SpeedLimitMiddleware的配置格式
- 移除 config.py 中的
downloader_timeout
,verify_ssl
,allow_redirects
配置项 - 移除
xpaw.FormData
,xpaw.URL
- 移除
xpaw.MultiDict
,xpaw.CIMultiDict
, 改由xpaw.HttpHeaders
替代承载headers的功能 - 移除请求超时错误TimeoutError,统一由ClientError表示downloader抛出的异常
default_headers
默认为None
, 浏览器默认的HTTP header改由UserAgentMiddleware根据设定的浏览器类型进行设置xpaw.downloadermws
模块更名为xpaw.downloader_middlewares
,xpaw.spidermws
模块更名为xpaw.spider_middlewares
@every
装饰器移至xpaw.decorator
模块- 移除对
dump_dir
的支持
0.10.4 (2018-11-06)¶
- 在生成初始请求过程中,捕获单个请求抛出的异常并记录日志
0.10.3 (2018-09-01)¶
- ProxyMiddleware不会覆盖用户在HttpRequest
meta
中设置的proxy
- CookiesMiddleware不会覆盖用户在HttpRequest
meta
中设置的cookie_jar
- NetworkError更名为ClientError,同时请求超时改由TimeoutError表示
0.10.2 (2018-08-28)¶
- Field添加
type
参数,表示该字段的类型,在获取该字段的值时会进行类型转换 - 添加
allow_redirects
配置项,控制是否允许重定向,默认为True
- HttpRequest
meta
添加verify_ssl
和allow_redirects
字段,用于精确控制单次请求的相关行为 - 添加
StopCluster
异常,用于在spider在回调函数中停止cluster - 添加
request_ignored
事件 user_agent
默认值设置为:desktop
- 运行spider之后不会再移除主程序已经设置的signal handler
0.10.1 (2018-07-18)¶
- 新增
make_requests
函数,用于发起请求并获取对应的结果,详见 Make Requests log_level
支持小写字母配置,如debug
。
0.10.0 (2018-07-15)¶
xpaw crawl
支持直接运行spider,支持指定配置文件,添加了更多的功能选项- 添加
daemon
配置项,支持以daemon模式运行爬虫 - 添加
pid_file
配置项,支持将爬虫所在进程的PID写入文件 - 添加
dump_dir
配置项,支持爬虫的暂停与恢复 - 运行spider结束时移除配置的log handler,避免先后多次运行spider时打印多余的日志
- 移除爬虫工程的入口文件setup.cfg,直接通过工程根目录下的config.py完成配置
- 重构ProxyMiddleware配置项
- 通过
speed_limit_enabled
控制限速中间件SpeedLimitMiddleware的开启/关闭,默认为关闭状态 - 配置项
verify_ssl
的默认值更改为False
- 配置项
queue_cls
更名为queue
- 配置项
dupe_filter_cls
更名为dupe_filter
- cluster的
stats_center
更名为stats_collector
,配置项stats_center_cls
更名为stats_collector
- 调整了中间件加载顺序权值
- HttpRequest对
auth
,cookie_jar
,proxy
,proxy_auth
的配置移至meta
属性中 - SetDupeFilter更名为HashDupeFilter
- 修改aiohttp的版本限制为>=3.3.2
0.9.1 (2018-04-16)¶
- 修复了setup.py中读取README的编码设置问题
- 不再只依赖于通过定时轮询判定job是否结束,单次下载完成后即判定job是否结束
- 修改依赖库的版本限制
0.9.0 (2017-11-13)¶
- 中间件的加载细分为内置中间件和用户自定义中间件两部分,内置中间件自动加载,用户中间件的加载由配置项确定
- 中间件加载的顺序由配置的权值确定,权值越大越贴近downloader/spider
- 添加
NotEnabled
异常,在中间件/拓展的构造函数中控制抛出该异常来实现开启或禁用该中间件/拓展。 - 添加UserAgentMiddleware,支持选择PC端或移动端的User-Agent,支持随机User-Agent
- 支持配置日志写入指定文件
- 修复了HttpRequest的fingerprint计算时没有考虑端口号的bug
- 移除ResponseNotMatchMiddleware
- 移除ProxyAgentMiddle,原有功能并入ProxyMiddleware
- 修改了RetryMiddleware,ProxyMiddleware,DepthMiddleware的参数配置方式
- ForwardedForMiddleware更名为ImitatingProxyMiddleware,用于设置HTTP请求头的
X-Forwarded-For
和Via
字段 - 系统配置
downloader_verify_ssl
更名为verify_ssl
,downloader_cookie_jar_enabled
更名为cookie_jar_enabled
- 更新了downloader和spider相关的错误处理流程
- 更新了判定job结束的逻辑
0.8.0 (2017-11-5)¶
- spider的
start_requests
和parse
函数支持async类型和python 3.6中的async generator类型 - spider中间件的handle_*函数支持async类型
- 添加事件驱动相关的eventbus和events模块,支持事件的订阅/发送,可通过
cluster.event_bus
获取event bus组件 - 捕获SIGINT和SIGTERM信号并做出相应处理
- 添加extension模块,支持用户自定义拓展
- 添加statscenter模块,用于收集,管理系统产生的各项统计量,可通过
cluster.stats_center
获取stats center组件; 系统配置添加stats_center_cls
项,用于替换默认的stats center的实现 - SetDupeFilter添加
clear
函数 - 系统配置添加
downloader_verify_ssl
项,用于开启或关闭SSL证书认证 - HttpRequest的
body
参数支持bytes
,str
,FormData
,dict
等形式 - HttpRequest添加
params
,auth
,proxy_auth
,priority
等属性 - 添加深度优先队列LifoQueue,以及优先级队列PriorityQueue,默认
queue_cls
更改为xpaw.queue.PriorityQueue
- 支持设定HTTP请求的优先级并按优先级进行爬取
- 添加item,pipeline模块,支持spider在处理response时返回BaseItem的实例或dict,并交由用户自定义的item pipelines进行处理
- 实例化中间件的classmethod
from_config
更改为from_cluster
,现在config
参数可以通过cluster.config
获取 - queue组件的
push
,pop
函数,以及dupefilter组件的is_duplicated
函数改为async类型 - 移除queue组件和dupefilter组件的基类,RequestDequeue更名为FifoQueue
- 系统不再默认调用dupefilter组件和queue组件的
open
和close
函数,如果自定义的组件包含这些函数,可通过订阅相关事件的方式进行调用 - 系统配置
dupefilter_cls
更名为dupe_filter_cls
,cluster的dupefilter
属性更名为dupe_filter
- RequestHeadersMiddleware更改为DefaultHeadersMiddleware,配置字段
request_headers
更改为default_headers
,功能由覆盖headers变为设置默认的headers - 修改了MaxDepthMiddleware更改为DepthMiddleware的参数配置方式,功能变为记录request的depth并对max depth加以限制
- 修改了ProxyMiddleware和ProxyAgentMiddleware的参数配置方式
- 移除CookieJarMiddleware,通过
downloader_cookie_jar_enabled
配置是否启用cookie - 重写了SpeedLimitMiddleware,通过
rate
(采集速率) 和burst
(最大并发数) 来限制采集速率 - 更新了
request_fingerprint
的计算方式 - 修改aiohttp的版本限制为>=2.3.2
0.7.1 (2017-10-25)¶
- 通过
@every
实现定时任务功能 - HttpRequest添加
dont_filter
字段,为True
时表示该请求不会被过滤 xpaw.run
模块中添加run_spider
函数,便于在python代码中直接运行Spider类xpaw.utils.run
模块中run_crawler
函数移动至xpaw.run
模块- 原utils, commands, downloadersmws, spidermws各合并为一个模块
0.7.0 (2017-10-24)¶
- 使用继承Dupefilter的去重过滤器来实现去重功能,系统配置添加
dupefilter_cls
项,用于替换默认的去重过滤器 xpaw.utils.run
模块中添加run_crawler
函数,便于在python代码中控制开启爬虫- 使用config.py替代config.yaml作为配置文件,移除对pyyaml的依赖
- ForwardedForMiddleware移动到
xpaw.downloadermws.headers
模块下 - 修改aiohttp的版本限制为>=2.2.0
- 更新了downloader和spider相关的错误处理流程
- 不再采用中间件的形式实现请求的去重功能,并移除相关的中间件
- ProxyAgentMiddleware的
proxy_agent
配置下面addr
字段更名为agent_addr
0.6.5 (2017-05-09)¶
- HttpRequest添加
errback
字段,表示无法正常获取到HttpResponse时触发的函数 - ResponseMatchMiddleware的配置修改为列表
- middleware的顺序修改为依次向downloader/spider靠近,层层包裹
- 移除任务配置中随机生成的
task_id
0.6.4 (2017-05-05)¶
- HttpResponse中的
url
字段源于aiohttp返回的ClientResponse中的url
字段,实际应为yarl.URL
对象 - LocalCluster启动时不再新建一个线程
- 优化日志工具中设置日志的接口
0.6.2 (2017-03-30)¶
- HttpResponse添加
encoding
和text
字段,分别用于获取网页的编码及字符串形式的内容 - 添加ResponseMatchMiddleware,用于初步判断得到的页面是否符合要求
- 添加CookieJarMiddleware,用于维护请求过程中产生的cookie,同时HttpRequest
meta
中添加系统项cookie_jar
作为发起请求时使用的cookie jar - HttpRequest
meta
添加timeout
字段,用于精确控制某个请求的超时时间 - 系统配置添加
queue_cls
项,用于替换默认的请求队列
0.6.1 (2017-03-23)¶
- 中间件添加
open
和close
两个钩子函数,分别对应开启和关闭爬虫的事件 - RetryMiddleware中可以自定义需要重试的HTTP状态码
- 添加SpeedLimitMiddleware,用于爬虫限速
- 添加ProxyMiddleware,用于为请求添加指定代理
- 移除MongoDedupeMiddleware及对pymongo的依赖
- 修改ProxyAgentMiddleware,RetryMiddleware在配置文件中的参数格式
- DepthMiddleware更名为MaxDepthMiddleware
0.6.0 (2017-03-16)¶
- First release