Scrapy 终端
Scrapy 终端是一个交互式终端,您可以在其中非常快速地尝试和调试爬取代码,而无需运行整个爬虫。它旨在用于测试数据提取代码,但实际上您可以将其用于测试任何类型的代码,因为它也是一个常规的 Python 终端。
该终端用于测试 XPath 或 CSS 表达式,查看它们的工作原理以及从您尝试爬取的网页中提取了哪些数据。它允许您在编写爬虫时交互式地测试表达式,而无需为了测试每一个细微改动而重新运行爬虫。
一旦您熟悉了 Scrapy 终端,您会发现它是开发和调试爬虫的得力助手。
配置终端
如果您安装了 IPython,Scrapy 终端将使用它(而不是标准 Python 控制台)。IPython 控制台功能强大得多,并提供智能自动补全和彩色输出等功能。
我们强烈建议您安装 IPython,尤其是如果您在 Unix 系统上工作(这是 IPython 的强项)。有关更多信息,请参阅 IPython 安装指南。
Scrapy 还支持 bpython,并在 IPython 不可用时尝试使用它。
通过 Scrapy 的设置,您可以将其配置为使用 ipython、bpython 或标准 python 终端中的任何一个,而不管安装了哪一个。这可以通过设置 SCRAPY_PYTHON_SHELL 环境变量来实现;或者在您的 scrapy.cfg 中进行定义。
[settings]
shell = bpython
启动终端
要启动 Scrapy 终端,您可以像这样使用 shell 命令
scrapy shell <url>
其中 <url> 是您要爬取的 URL。
shell 也适用于本地文件。如果您想玩玩网页的本地副本,这会很方便。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 的文件。再次强调,请明确路径。
使用终端
Scrapy 终端只是一个常规的 Python 控制台(如果您安装了 IPython,则为 IPython 控制台),它为方便起见提供了一些额外的快捷函数。
可用快捷方式
shelp()- 打印包含可用对象和快捷方式列表的帮助信息fetch(url[, redirect=True])- 从给定的 URL 获取新的响应,并相应地更新所有相关对象。您可以选择通过传递redirect=False来要求不跟随 HTTP 3xx 重定向fetch(request)- 从给定的请求中获取新的响应,并相应地更新所有相关对象。view(response)- 在本地网络浏览器中打开给定的响应以供检查。这会向响应正文添加一个 <base> 标签,以便外部链接(如图像和样式表)能正确显示。但请注意,这将在您的计算机中创建一个临时文件,且不会自动删除。
可用的 Scrapy 对象
Scrapy 终端会自动从下载的页面创建一些方便的对象,例如 Response 对象和 Selector 对象(用于 HTML 和 XML 内容)。
这些对象是:
终端会话示例
这是一个典型终端会话的示例,我们首先爬取 https://scrapy.net.cn/ 页面,然后继续爬取 https://old.reddit.com/ 页面。最后,我们将 (Reddit) 请求方法修改为 POST 并重新获取它,结果得到了一个错误。我们通过键入 Ctrl-D(在 Unix 系统中)或 Ctrl-Z(在 Windows 中)结束会话。
请记住,当您尝试时,此处提取的数据可能不尽相同,因为这些页面不是静态的,在您测试时可能已经发生了变化。此示例的唯一目的是让您熟悉 Scrapy 终端的工作原理。
首先,我们启动终端
scrapy shell 'https://scrapy.net.cn' --nolog
注意
请记住,在命令行运行 Scrapy 终端时,始终要用引号括起 URL,否则包含参数(即 & 字符)的 URL 将无法正常工作。
在 Windows 上,请改用双引号
scrapy shell "https://scrapy.net.cn" --nolog
然后,终端会获取 URL(使用 Scrapy 下载器)并打印可用对象和有用快捷方式的列表(您会注意到这些行都以 [s] 前缀开头)
[s] Available Scrapy objects:
[s] scrapy scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s] crawler <scrapy.crawler.Crawler object at 0x7f07395dd690>
[s] item {}
[s] request <GET https://scrapy.org>
[s] response <200 https://scrapy.org/>
[s] settings <scrapy.settings.Settings object at 0x7f07395dd710>
[s] spider <DefaultSpider 'default' at 0x7f0735891690>
[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()").get()
'Scrapy | A Fast and Powerful Scraping and Web Crawling Framework'
>>> fetch("https://old.reddit.com/")
>>> response.xpath("//title/text()").get()
'reddit: the front page of the internet'
>>> request = request.replace(method="POST")
>>> fetch(request)
>>> response.status
404
>>> from pprint import pprint
>>> pprint(response.headers)
{'Accept-Ranges': ['bytes'],
'Cache-Control': ['max-age=0, must-revalidate'],
'Content-Type': ['text/html; charset=UTF-8'],
'Date': ['Thu, 08 Dec 2016 16:21:19 GMT'],
'Server': ['snooserv'],
'Set-Cookie': ['loid=KqNLou0V9SKMX4qb4n; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 08-Dec-2018 16:21:19 GMT; secure',
'loidcreated=2016-12-08T16%3A21%3A19.445Z; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 08-Dec-2018 16:21:19 GMT; secure',
'loid=vi0ZVe4NkxNWdlH7r7; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 08-Dec-2018 16:21:19 GMT; secure',
'loidcreated=2016-12-08T16%3A21%3A19.459Z; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 08-Dec-2018 16:21:19 GMT; secure'],
'Vary': ['accept-encoding'],
'Via': ['1.1 varnish'],
'X-Cache': ['MISS'],
'X-Cache-Hits': ['0'],
'X-Content-Type-Options': ['nosniff'],
'X-Frame-Options': ['SAMEORIGIN'],
'X-Moose': ['majestic'],
'X-Served-By': ['cache-cdg8730-CDG'],
'X-Timer': ['S1481214079.394283,VS0,VE159'],
'X-Ua-Compatible': ['IE=edge'],
'X-Xss-Protection': ['1; mode=block']}
从爬虫中调用终端以检查响应
有时您想要检查在爬虫的某个特定点正在处理的响应,哪怕只是为了检查您预期的响应是否已经到达那里。
这可以通过使用 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):
# 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.
当您运行爬虫时,您会得到类似这样的结果
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"]')
[]
不,它不行。所以您可以在网络浏览器中打开响应,看看它是否是您预期的响应
>>> view(response)
True
最后,您按下 Ctrl-D(在 Windows 中为 Ctrl-Z)退出终端并恢复爬取
>>> ^D
2014-01-23 17:50:03-0400 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://example.net> (referer: None)
...
请注意,您在此处无法使用 fetch 快捷方式,因为 Scrapy 引擎被终端阻塞了。但是,在您离开终端后,爬虫将从停止的地方继续爬取,如上所示。