Scrapy - 如何获取正在解析的项目索引?

3 投票
2 回答
1902 浏览
提问于 2025-04-18 17:31

我正在尝试使用Scrapy从数据库加载一些XPATH规则。

到目前为止,我写的代码运行得很好,但经过调试后我发现,Scrapy是异步解析每个项目的,这意味着我无法控制解析的顺序。

我想做的是找出在调用parse()函数时,当前正在解析的是列表中的哪个项目,这样我就可以将这个索引与数据库中的行对应起来,获取正确的XPATH查询。我现在的做法是使用一个叫item_index的变量,并在每次迭代后递增它。但我现在意识到这还不够,我希望能有一些内部功能来帮助我实现这个目标。

有没有人知道正确的跟踪方法?我查阅了文档,但没有找到相关信息。我也查看了Scrapy的源代码,但我似乎无法弄清楚这些URL是如何存储的。

以下是我的代码,以进一步解释我的问题:

# -*- coding: utf-8 -*-

from scrapy.spider import Spider
from scrapy.selector import Selector

from dirbot.items import Product

from dirbot.database import DatabaseConnection

# Create a database connection object so we can execute queries
connection = DatabaseConnection()

class DmozSpider(Spider):
    name = "dmoz"
    start_urls = []
    item_index = 0

    # Query for all products sold by a merchant
    rows = connection.query("SELECT * FROM products_merchant WHERE 1=1")

    def start_requests(self):
        for row in self.rows:
            yield self.make_requests_from_url(row["product_url"])

    def parse(self, response):
        sel = Selector(response)
        item = Product()
        item['product_id'] = self.rows[self.item_index]['product_id']
        item['merchant_id'] = self.rows[self.item_index]['merchant_id']
        item['price'] = sel.xpath(self.rows[self.item_index]['xpath_rule']).extract()

        self.item_index+=1

        return item

任何指导都将非常感激!

谢谢

2 个回答

3

这是我想到的解决办法,以防有人需要。

正如@toothrot所建议的,你需要在Request类中重载方法,这样才能访问meta信息。

希望这能帮到某个人。

# -*- coding: utf-8 -*-

from scrapy.spider import Spider
from scrapy.selector import Selector
from scrapy.http import Request

from dirbot.items import Product

from dirbot.database import DatabaseConnection

# Create a database connection object so we can execute queries
connection = DatabaseConnection()

class DmozSpider(Spider):
    name = "dmoz"
    start_urls = []

    # Query for all products sold by a merchant
    rows = connection.query("SELECT * FROM products_merchant WHERE 1=1")

    def start_requests(self):
        for indx, row in enumerate(self.rows):
            self.start_urls.append( row["product_url"] )
            yield self.make_requests_from_url(row["product_url"], {'index': indx})

    def make_requests_from_url(self, url, meta):
       return Request(url, callback=self.parse, dont_filter=True, meta=meta)

    def parse(self, response):

        item_index = response.meta['index']

        sel = Selector(response)
        item = Product()
        item['product_id'] = self.rows[item_index]['product_id']
        item['merchant_id'] = self.rows[item_index]['merchant_id']
        item['price'] = sel.xpath(self.rows[item_index]['xpath_rule']).extract()

        return item
1

你可以在发送请求的时候,把索引(或者数据库中的行ID)一起传过去,方法是使用 Request.meta。这个东西就像一个字典,你可以在处理响应的时候通过 Response.meta 来访问它。

举个例子,当你在构建请求的时候,可以这样写:

Request(url, callback=self.some_handler, meta={'row_id': row['id']})

你尝试使用计数器的方法是行不通的,因为你无法保证响应处理的顺序。

撰写回答