Skip to main content

调试蜘蛛

本文解释了调试蜘蛛最常见的技术。考虑下面的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):
        # collect `item_urls`
        for item_url in item_urls:
            yield scrapy.Request(item_url, self.parse_item)

    def parse_item(self, response):
        item = MyItem()
        # populate `item` fields
        # and extract item_details_url
        yield scrapy.Request(item_details_url, self.parse_details, meta={'item': item})

    def parse_details(self, response):
        item = response.meta['item']
        # populate more `item` fields
        return item

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

解析命令

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

为了查看从特定网址抓取的项目:

$ 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壳

虽然 parse 命令对于检查蜘蛛的行为非常有用,但除了显示收到的响应和输出之外,检查回调中发生的事情几乎没有帮助。如何调试当 parse_details 有时没有收到项目的情况?

幸运的是,在这种情况下,shell 是你的面包和黄油(见 从蜘蛛调用shell检查响应):

from scrapy.shell import inspect_response

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

参见:从蜘蛛调用shell检查响应

在浏览器中打开

有时你只想看看一个特定的响应在浏览器中的样子,你可以使用 open_in_browser 函数。这里是一个如何使用它的例子:

from scrapy.utils.response import open_in_browser

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

open_in_browser 将使用Scrapy在此时收到的响应打开浏览器,调整 base tag 以便正确显示图像和样式。

记录

日志记录是获取有关蜘蛛运行信息的另一个有用选项。虽然不是那么方便,但它带来的优点是日志将在所有未来的运行中,如果他们再次需要可用:

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

有关更多信息,请查看 记录 部分。