调试爬虫

本文档解释了调试爬虫最常用的技术。请看下面的 Scrapy 爬虫

import scrapy
from myproject.items import MyItem


class MySpider(scrapy.Spider):
    name = "myspider"
    start_urls = (
        "http://example.com/page1",
        "http://example.com/page2",
    )

    def parse(self, response):
        # <processing code not shown>
        # collect `item_urls`
        for item_url in item_urls:
            yield scrapy.Request(item_url, self.parse_item)

    def parse_item(self, response):
        # <processing code not shown>
        item = MyItem()
        # populate `item` fields
        # and extract item_details_url
        yield scrapy.Request(
            item_details_url, self.parse_details, cb_kwargs={"item": item}
        )

    def parse_details(self, response, item):
        # populate more `item` fields
        return item

这基本上是一个简单的爬虫,它解析两页项目(start_urls)。项目还有一个带有附加信息的详细页面,因此我们使用 cb_kwargs 的功能 Request 来传递一个部分填充的项目。

Parse 命令

检查爬虫输出最基本的方法是使用 parse 命令。它允许在方法级别检查爬虫不同部分的 L行为。它的优点是灵活且易于使用,但不允许调试方法内部的代码。

为了查看从特定 URL 抓取的项目

$ scrapy parse --spider=myspider -c parse_item -d 2 <item_url>
[ ... scrapy log lines crawling example.com spider ... ]

>>> STATUS DEPTH LEVEL 2 <<<
# Scraped Items  ------------------------------------------------------------
[{'url': <item_url>}]

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

使用 --verbose-v 选项,我们可以看到每个深度级别的状态

$ scrapy parse --spider=myspider -c parse_item -d 2 -v <item_url>
[ ... scrapy log lines crawling example.com spider ... ]

>>> DEPTH LEVEL: 1 <<<
# Scraped Items  ------------------------------------------------------------
[]

# Requests  -----------------------------------------------------------------
[<GET item_details_url>]


>>> DEPTH LEVEL: 2 <<<
# Scraped Items  ------------------------------------------------------------
[{'url': <item_url>}]

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

检查从单个 start_url 抓取的项目,也可以通过以下方式轻松实现

$ scrapy parse --spider=myspider -d 3 'http://example.com/page1'

Scrapy Shell

虽然 parse 命令对于检查爬虫的行为非常有用,但除了显示收到的响应和输出外,它对于检查回调内部发生的情况帮助不大。如何调试 parse_details 有时收不到项目的情况?

幸运的是,在这种情况下 shell 是你的得力助手(参见 从爬虫调用 shell 来检查响应

from scrapy.shell import inspect_response


def parse_details(self, response, item=None):
    if item:
        # populate more `item` fields
        return item
    else:
        inspect_response(response, self)

另请参阅: 从爬虫调用 shell 来检查响应

在浏览器中打开

有时你只是想看看某个响应在浏览器中是什么样子,你可以使用 open_in_browser() 函数来实现

scrapy.utils.response.open_in_browser(response: TextResponse, _openfunc: Callable[[str], Any] = <function open>) Any[source]

在本地网页浏览器中打开 response,调整 base 标签,使外部链接生效,例如显示图像和样式。

例如

from scrapy.utils.response import open_in_browser


def parse_details(self, response):
    if "item name" not in response.text:
        open_in_browser(response)

日志

日志是获取爬虫运行信息的另一个有用选项。虽然不如其他方法方便,但它的优点是日志在未来所有运行中都可用,以防再次需要。

def parse_details(self, response, item=None):
    if item:
        # populate more `item` fields
        return item
    else:
        self.logger.warning("No item received for %s", response.url)

有关更多信息,请查看 日志 部分。

Visual Studio Code

要使用 Visual Studio Code 调试爬虫,可以使用以下 launch.json

{
    "version": "0.1.0",
    "configurations": [
        {
            "name": "Python: Launch Scrapy Spider",
            "type": "python",
            "request": "launch",
            "module": "scrapy",
            "args": [
                "runspider",
                "${file}"
            ],
            "console": "integratedTerminal"
        }
    ]
}

此外,请确保启用“用户未捕获异常”(User Uncaught Exceptions),以捕获 Scrapy 爬虫中的异常。