
Scrapy shell交互式抓取控制台的用法、配置与源码级工作原理【免费下载链接】scrapyScrapy, a fast high-level web crawling scraping framework for Python.项目地址: https://gitcode.com/GitHub_Trending/sc/scrapy本文基于 Scrapy 官方文档docs/topics/shell.rst系统讲解 Scrapy shell交互式抓取控制台的定位与用法如何启动 shell、如何配置交互式解释器、shell 内可用的对象与快捷函数、如何自定义 shell 变量、如何在 Spider 运行时中断检查响应并结合scrapy/shell.py、scrapy/commands/shell.py等源码解析 shell 背后的引擎调用链。读完后你将能够熟练使用scrapy shell调试 XPath/CSS 提取代码并理解 shell 与 Scrapy 下载引擎之间的协作机制。一、Scrapy shell 是什么Scrapy shell 是一个交互式 Shell你可以用它在没有运行 Spider 的情况下快速试验和调试抓取代码。它的设计初衷是测试数据提取代码但由于它本质上就是一个普通的 Python 控制台Console你实际上可以在其中运行任何 Python 代码。典型使用场景是在编写 Spider 的过程中交互式地试验 XPath 或 CSS 表达式观察它们在目标网页上实际提取出什么数据而无需为每一次表达式改动都完整运行一遍 Spider。文档原话是熟悉 Scrapy shell 之后你会发现自己开发、调试 Spider 离不开这个工具。从源码结构看shell 由两部分构成命令行入口 Command负责解析参数、创建 Crawler、启动下载引擎核心类 Shell负责拉取页面、维护 shell 中的变量命名空间、启动交互式控制台。二、配置 shell 使用的解释器Scrapy shell 支持四种交互式 Python 控制台优先级从高到低源码中 DEFAULT_PYTHON_SHELLS 的顺序解释器特性安装 extraptpython语法高亮、智能自动补全等ptpythonipython智能自动补全、彩色化输出等ipythonbpython增强型 REPLbpythonpython标准 Python 解释器永远作为兜底无需安装即若安装了ptpythonextrashell 优先使用 ptpython否则尝试 IPython再否则尝试 bpython全都不可用时退回标准 Python shell。也可以通过 Scrapy 的配置显式指定使用其中任意一种与本地实际安装了什么无关。方式有两种设置环境变量SCRAPY_PYTHON_SHELL或在scrapy.cfg的[settings]段中定义shell[settings] shell bpython各 extra 的版本要求可参见 pyproject.tomlbpython0.7.1、ipython8.15.0、ptpython3.0.23。源码中的解释器选择逻辑Shell.start() 展示了完整的优先级决策过程首先读取环境变量SCRAPY_PYTHON_SHELL其值支持逗号分隔的多个 shell 名按顺序尝试若环境变量未设置则读取全局scrapy.cfg如~/.config/scrapy.cfg或~/.scrapy.cfg中[settings]段的shell选项两者都没有时按DEFAULT_PYTHON_SHELLS的默认顺序ptpython → ipython → bpython逐一尝试最后始终把标准python追加为兜底选项。随后调用 start_python_console()它会逐个尝试导入对应包第一个导入成功的解释器被嵌入启动导入抛ImportError则继续尝试下一个。测试 tests/test_command_shell.py 中的test_shell_from_cfg、test_shell_ipython用 pexpect 真实启动了交互式 shell验证scrapy.cfg的shell python配置确实生效、SCRAPY_PYTHON_SHELLipython确实嵌入了 IPython。三、启动 shell使用shell命令启动scrapy shell url其中url即你希望抓取的 URL。命令描述见 Command.short_desc()为 Interactive scraping console参数语法为[url|file]。命令行选项从 Command.add_options() 可以看到shell命令支持的选项-c CODE在 shell 中执行一段代码打印结果后直接退出非交互模式适合脚本化验证提取逻辑--spider SPIDER指定使用该 Spider影响 shell 中spider对象的类型--no-redirect不处理 HTTP 3xx 状态码原样输出重定向响应此外还有通用选项如--nolog关闭日志输出、--set临时修改设置。抓取本地文件shell同样支持本地文件——当你想在一个网页的本地副本上练习时非常有用。支持的语法# UNIX 风格 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而index.html在语法上与example.com这类域名相似于是 shell 把它当作域名去做 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的文件。请显式书写路径。从源码看这一行为的入口是 Command.run()url args[0] if args else None if url: # first argument may be a local file url guess_scheme(url)guess_scheme() 的判定逻辑是参数看起来像文件系统路径POSIX 绝对/相对路径、Windows 盘符路径时补file://scheme否则补http://。由于裸的index.html不匹配任何路径特征它会被补成http://index.html并触发 DNS 查询。对应的测试见 test_local_file / test_local_nofile / test_dns_failures。四、shell 中的对象与快捷函数Scrapy shell 就是一个普通 Python 控制台如果可用则是 IPython 控制台但额外提供了一些便捷的对象和快捷函数。快捷函数Available Shortcutsshelp()—— 打印帮助列出所有可用对象和快捷函数fetch(url[, redirectTrue])—— 从给定 URL 拉取新响应并同步更新所有相关对象。传redirectFalse可以选择不跟随 HTTP 3xx 重定向fetch(request)—— 从给定的scrapy.Request拉取新响应并同步更新所有相关对象view(response)—— 在本地 Web 浏览器中打开指定响应以便检查。该函数会向响应正文中注入一个base标签使外部资源图片、样式表能正常显示注意它会在磁盘上创建一个不会自动删除的临时文件。自动创建的 Scrapy 对象Available Scrapy objectsshell 会基于下载到的页面自动创建一组便捷对象见 Shell.populate_vars()变量说明scrapyscrapy 模块本身包含scrapy.Request、scrapy.Selector等crawler当前的 Crawler 对象itemDEFAULT_ITEM_CLASS实例化的空 item默认{}request最近一次抓取页面的 Request 对象。可用request.replace()修改它或用fetch快捷函数不离开 shell发起新请求response包含最近抓取页面内容的 Response 对象settings当前的 Scrapy 设置spider已知能处理该 URL 的 Spider若没有匹配的 Spider则是一个普通的scrapy.Spider对象fetchfetch()快捷函数仅在 shell 运行于独立线程、引擎可访问时可用viewview()快捷函数即 open_in_browser()shelpshelp()快捷函数启动时打印的[s]前缀横幅由 Shell.get_help() 生成长这样[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[, redirectTrue]) 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 browserspider的选取逻辑在 Command.run()若指定了--spider加载对应 Spider 类否则根据 URL 通过spidercls_for_request()按allowed_domains匹配都匹配不到时退回DefaultSpider。五、添加自定义对象update_vars如果你想在 shell 中定义额外的对象或希望在每次fetch之后自动运行一段代码正确做法是编写一个自定义项目命令在一个名为shell的模块中覆盖shell命令并重写其update_vars方法。该方法在 shell 启动时以及每次fetch之后都会被调用参数是变量名 → 对象的映射对照 Shell 构造函数 与 populate_vars() 中的self.update_vars(self.vars)调用from scrapy.commands.shell import Command as ShellCommand class Command(ShellCommand): def update_vars(self, vars): from myproject.utils import parse_product vars[parse_product] parse_product if vars[response] is not None: vars[product] parse_product(vars[response])当不带 URL 启动 shell 时即scrapy shell直接启动response为None因此上面的代码做了判空保护。六、一次完整的 shell 会话示例以下是一个典型的 shell 会话先抓取https://scrapy.org/再跳转到https://old.reddit.com/然后把Reddit 的请求方法改成 POST 重新抓取从而得到一个错误响应最后输入 Ctrl-DUnix 系统或 Ctrl-ZWindows结束会话。请注意示例中提取到的数据在你运行时可能不一样因为那些页面不是静态的这个示例的唯一目的是让你熟悉 shell 的工作方式。首先启动 shellscrapy shell https://scrapy.org --nolog提示在命令行中始终用引号把 URL 包起来否则含查询参数即字符的 URL 会失效。Windows 上使用双引号scrapy shell https://scrapy.org --nolog。shell 使用 Scrapy 下载器抓取该 URL 后打印可用对象与快捷函数列表均以[s]前缀开头见上一节然后进入交互提示符。接着就可以随意摆弄对象了 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(methodPOST) fetch(request) response.status 404 from pprint import pprint pprint(response.headers) {Accept-Ranges: [bytes], Cache-Control: [max-age0, must-revalidate], Content-Type: [text/html; charsetUTF-8], ... }这段示例覆盖了 shell 的三个核心工作流response.xpath()提取数据、fetch(url)换页、request.replace()fetch(request)修改请求并重新抓取。七、在 Spider 中调用 shell 检查响应inspect_response有时你需要检查 Spider 在某个处理点上实际拿到的响应——哪怕只是想确认你期望的响应真的被送到了。这可以用scrapy.shell.inspect_response函数实现。在 Spider 中的调用示例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.运行 Spider 后终端会出现类似这样的输出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[classfn]) []不对。于是可以把响应在浏览器里打开看看它是否是你期望的响应 view(response) True最后按 Ctrl-DWindows 上为 Ctrl-Z退出 shell抓取继续 ^D 2014-01-23 17:50:03-0400 [scrapy.core.engine] DEBUG: Crawled (200) GET http://example.net (referer: None) ...注意在 Spider 内弹出的 shell 中不能使用fetch快捷函数因为 Scrapy 引擎正被 shell 阻塞。退出 shell 后Spider 会从停下的地方继续抓取。从源码看inspect_response() 做了两件事保存并在 shell 关闭后恢复SIGINT处理器然后直接Shell(spider.crawler, looploop).start(responseresponse, spiderspider)。Shell.start()在收到response参数时会走 populate_vars() 分支——只填充变量、不发起新的下载。这也解释了为何此时fetch不可用Shell.__init__中通过self._inthread判断当前线程是否为引擎线程Shell.start()在 Spider 回调线程内同步执行fetch_available为Falsepopulate_vars只有在self.fetch_available为真时才会把fetch放进变量表源码 L260-L261。八、源码纵深shell 如何驱动下载引擎这一节从源码层面还原scrapy shell url的完整调用链scrapy/shell.py 文件头部有一段官方架构注释本节以其为基础展开。线程与引擎的分工scrapy.commands.shell.Command.run()的流程通过crawler_process._create_crawler(spidercls)创建 Crawler 并_apply_settings()。这里不经过常规crawl方法因为Shell 手动接管了抓取引擎按TWISTED_REACTOR_ENABLED设置走两条初始化路径之一Reactor 模式Command._init_with_reactor()在主线程创建引擎、_schedule_coro(crawler.engine.start_async(_start_request_processingFalse))完成引擎初始化但不开始处理请求然后用守护线程运行crawler_process.start()reactor 跑在该线程里无 Reactor 模式Command._init_without_reactor()引擎初始化通过asyncio.run_coroutine_threadsafe挪到事件循环线程中执行。最后Shell(crawler, update_vars..., codeopts.code, looploop).start(urlurl, redirectnot opts.no_redirect)启动 shell。fetch() 的完整路径交互式 shell 中调用fetch()时Shell.fetch()若参数是 URLany_to_uri()规范化后构造Request(url, dont_filterTrue, **kwargs)重定向行为通过 meta 控制redirectTrue时设置handle_httpstatus_list SequenceExclude(range(300, 400))即屏蔽 3xx 的处理逻辑让默认的重定向中间件生效redirectFalse时设置handle_httpstatus_all True让 3xx 响应原样到达回调由于 shell 线程与引擎线程不同请求经threads.blockingCallFromThread(reactor, ...)reactor 模式或asyncio.run_coroutine_threadsafe无 reactor 模式发送到引擎线程执行 _schedule()首次调用会 _open_spider()engine.open_spider_async(close_if_idleFalse)随后engine.crawl(request)把请求排入引擎响应通过 _request_deferred() 回传该函数把请求原本的callback/errback摘下来挂进一个 Deferred再把 Deferred 的callback/errback方法劫持到请求上。这样请求下载完成、回调被引擎执行时Deferred 随之触发shell 线程阻塞等待拿到Response最后populate_vars(response, request, self.spider)用新响应/请求刷新 shell 中的response、request等变量。这套把回调劫持进 Deferred的机制也解释了为何测试里有专门用例 test_fetch_request_with_callbacks 验证带callback/errback的fetch请求正常工作。shell 命令的默认设置Command.default_settings 表明 shell 启动的 Crawler 默认DUPEFILTER_CLASS scrapy.dupefilters.BaseDupeFilter不做去重所以fetch同一 URL 多次不会互相干扰请求本身也带dont_filterTrue、LOGSTATS_INTERVAL 0关闭周期性统计日志、REMOTE_CONTROL_ENABLED False关闭远程控制台扩展。view() 的实现细节view(response)即 open_in_browser()对HtmlResponse它在正文中定位!doctype ...声明若有之后插入base href...标签——浏览器会把head之前的base移入head而放在 doctype 之后可避免触发 quirks mode该 base 标签会覆盖响应自身可能存在的 base 标签对TextResponse直接写.txt其他类型按Content-Type推断扩展名。写入tempfile.mkstemp临时文件后用webbrowser.open(ffile://{fname})打开——这就是文档所说会创建一个不会自动删除的临时文件的来源。非交互模式的 -c 选项shell -c CODE走 Shell.start() 中的print(eval(self.code, globals(), self.vars))分支在 shell 变量命名空间里eval这段代码并打印结果后退出不启动交互式控制台。测试套件里大量用例依赖它例如 test_response_selector_html 用shell url -c response.xpath(//p[class\one\]/text()).get()断言输出为 Workstest_redirect_not_follow_302 则验证--no-redirect使 302 响应原样返回。九、适用前提与限制小结scrapy shell需要一个可运行的下载引擎环境测试表明它在 reactor 模式默认、asyncio reactor--set TWISTED_REACTORasyncio reactor path与TWISTED_REACTOR_ENABLEDFalse的无 reactor 模式下均可工作见 test_shell_fetch_async / test_shell_fetch_no_reactorSpider 内inspect_response()打开的 shell 不支持fetch引擎被阻塞退出后 Spider 继续抓取不带 URL 启动scrapy shell时response为None自定义update_vars需判空本地文件路径必须显式书写./file.html或完整路径 /file://URI裸文件名会被当作域名解析命令行中的 URL 建议加引号避免被 shell 环境吞掉。以上全部行为的依据文件为 docs/topics/shell.rst、scrapy/shell.py、scrapy/commands/shell.py、scrapy/utils/console.py、scrapy/utils/response.py、scrapy/utils/url.py 与 tests/test_command_shell.py。【免费下载链接】scrapyScrapy, a fast high-level web crawling scraping framework for Python.项目地址: https://gitcode.com/GitHub_Trending/sc/scrapy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考