本文为译文,原文见地址:https://docs.scrapy.org/en/latest/topics/shell.html
Scrapy shell
Scrapy shell是一个交互式的shell,你可以在其中非常快速地尝试和调试你的抓取代码,而不必运行爬虫。它本来是用来测试数据提取代码的,但实际上你可以用它来测试任何类型的代码,因为它也是一个常规的Python shell。
这个shell用来测试XPath和CSS表达式,并查看它们是如何工作的,以及它们从你试图获取的web页面中提取什么数据。它允许你在编写爬虫时交互式地测试表达式,而不必运行爬虫来测试每个测试。
一旦你对Scrapy shell熟悉了,你会发现它是开发和调试爬虫的一个非常宝贵的工具。
配置shell
如果已经安装了IPython,那么Scrapy shell将使用它(而不是标准的Python控制台)。IPython控制台更加强大,它提供了智能自动补全和彩色输出等功能。
我们强烈推荐你安装IPython,特别是使用Unix系统(IPython更加优秀的平台)。详情查看IPython installation guid获取更多信息。
Scrapy也支持bpython,并且会在IPython不可用时尝试使用它。
通过Scrapy的设置,你可以将其配置为使用ipython、bpython或者其他的标准python shell的任意一种,而不管安装的是哪种。这是通过设置SCRAPY_PYTHON_SHELL环境变量完成的,或者在你的scrapy.cfg文件中定义它:
[settings]
shell = bpython
登录shell
为了登录Scrapy shell,你可以使用shell命令:
scrapy shell <url>
是你希望爬取的URL地址。
shell也可以同本地文件一起工作。如果你想要处理web页面的本地副本,这可能非常方便。shell理解本地文件的以下语法:
# UNIX-style
scrapy shell ./path/to/file.html
scrapy shell ../other/path/to/file.html
scrapy shell /absolute/path/to/file.html
# File URI
scrapy shell file:///absolute/path/to/file.html
当使用相对文件路径时,要显式地使用./来指定。scrapy shell index.html不会像人们期望的那样工作(这是设计如此,不是bug)。
因为shell更喜欢HTTP URL而不是文件URI,index.html在语法上与example.com相似,shell将视index.html为域名,并触发DNS查找错误:
$ scrapy shell index.html
[ ... scrapy shell starts ... ]
[ ... traceback ... ]
twisted.internet.error.DNSLookupError: DNS lookup failed:
address 'index.html' not found: [Errno -5] No address associated with hostname.
shell不会预先测试index.html文件是否存在于当前路径。所以再次提醒,需要显示使用./来指定相对文件路径。
使用shell
Scrapy shell只是一个常规的Python控制台(如果使用IPython则是IPython控制台),它提供了一些便利的附加快捷方式。
可用的快捷方式
- shelp() - 打印可用对象和快捷方式的列表。
- fetch(url[, redirect=True]) - 从给定的URL获取一个新的响应,并且依次更新所有相关对象。你可以通过传递redirect=False来选择请求不遵从HTTP 3xx的重定向。
- fetch(request) - 从给定的请求中获取一个新的响应,并且依次更新所有相关对象。
- view(response) - 在你本地web浏览器中打开给定的响应,以供检查。这将向响应正文添加一个标签,以便正确显示外部链接(比如图片和样式表)。但需要注意的是,这样做会在你的计算机中创建一个临时文件,并且并不会自动删除这个文件。
可用的Scrapy对象
Scrapy shell会从下载的页面中自动创建一些方便的对象,比如Response对象和Selector对象(用于HTML和XML内容)。
这些对象是:
- crawler - 当前的Crawler对象。
- spider - 已知的处理URL的爬虫,或者如果当前URL并没有对应的爬虫则返回一个Spider对象。
- request - 最后获取的页面的Request对象。你可以通过replace()修改这个请求,或者使用fetch快捷方式来获取一个新的request(不用离开当前shell)。
- response - 一个Response对象,包含了最后获取的页面。
- settings - 当前Scrapy的设置项。
shell会话的示例
这里是一个典型的shell会话示例,我们先爬取https://docs.scrapy.org/en/latest/topics/shell.html#available-shortcuts页面,然后继续爬取https://itchat.readthedocs.io/zh/latest/页面。最后,我们修改(Reddit)请求函数来POST它,并且重新获得它,结果得到一个错误。我们使用Ctrl-D(在Unix系统中)或者Ctrl-Z(在Windows系统中)来结束会话。
请记住,当你尝试的时候,提取的数据可能与这里不一致,这是因为这些页面不是静态的,可能会随着时间的推移而有些变化。这些示例的唯一目的是为了让你熟悉Scrapy shell的工作方式。
首先,我们登录shell:
scrapy shell https://docs.scrapy.org/en/latest/topics/shell.html#available-shortcuts --nolog
然后,shell会获取URL(使用Scrapy的下载器)并且打印一组可用的对象和有用的快捷方式(你可以注意到每一行都由[s]开始):
[s] Available Scrapy objects:
[s] scrapy scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s] crawler <scrapy.crawler.Crawler object at 0x0000022D1B00FA90>
[s] item {}
[s] request <GET https://docs.scrapy.org/en/latest/topics/shell.html#available-shortcuts>
[s] response <200 https://docs.scrapy.org/en/latest/topics/shell.html>
[s] settings <scrapy.settings.Settings object at 0x0000022D1B00F8D0>
[s] spider <DefaultSpider 'default' at 0x22d1b2bb7b8>
[s] Useful shortcuts:
[s] fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed)
[s] fetch(req) Fetch a scrapy.Request and update local objects
[s] shelp() Shell help (print this help)
[s] view(response) View response in a browser
>>>
在这之后,我们可以开始使用这些对象:
>>> response.xpath('//title/text()').extract_first()
'Scrapy shell — Scrapy 1.5.1 documentation'
>>> fetch('https://itchat.readthedocs.io/zh/latest/')
>>> response.xpath('//title/text()').extract()
['项目简介 - itchat']
>>> request = request.replace(method='POST')
>>> fetch(request)
>>> response.status
405
>>> from pprint import pprint
>>> pprint(response.headers)
{b'Content-Type': [b'text/html'],
b'Date': [b'Sat, 29 Dec 2018 09:21:45 GMT'],
b'Server': [b'nginx/1.14.0 (Ubuntu)']}
>>>
从爬虫调用shell来检查响应
有时候,你希望检查在爬虫的某个点上正在处理的响应,如果只是为了检查预期的响应是否达到该点。
通过scrapy.shell.inspect_response函数可以实现这个功能。
这里有一个示例,演示了如何在你的爬虫中调用它:
import scrapy
class MySpider(scrapy.Spider):
name = 'myspider'
start_urls = [
'http://example.com',
'http://example.org',
'http://example.net',
]
def parse(self, response):
# 我们希望检查一个特定的响应
if '.org' in response.url:
from scrapy.shell import inspect_response
inspect_response(response, self)
# 剩余的解析代码
当你运行这个爬虫,你将得到一些类似于下面的东西:
2014-01-23 17:48:31-0400 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://example.com> (referer: None)
2014-01-23 17:48:31-0400 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://example.org> (referer: None)
[s] Available Scrapy objects:
[s] crawler <scrapy.crawler.Crawler object at 0x1e16b50>
...
>>> response.url
'http://example.org'
然后,你就可以检查提取代码是否工作:
>>> response.xpath('//h1[@class="fn"]')
[]
你也可以在你的网页浏览器中打开响应,看看这是不是你希望的响应:
>>> ^D
2014-01-23 17:50:03-0400 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://example.net> (referer: None)
...
注意,这里不能使用fetch快捷方式,因为Scrapy引擎被shell阻塞了。但是,在你离开shell之后,爬虫将继续在它停止的地方爬行,如上所示。