每件物品多页

2024-04-26 20:51:52 发布

您现在位置:Python中文网/ 问答频道 /正文

免责声明:我对刮痧还是个新手。在

把我的问题说清楚:如何从页面上的链接检索项目属性并将结果返回到同一项目中?

给出以下蜘蛛样本:

class SiteSpider(Spider):
    site_loader = SiteLoader
    ...
    def parse(self, response):
        item = Place()
        sel = Selector(response)
        bl = self.site_loader(item=item, selector=sel)
        bl.add_value('domain', self.parent_domain)
        bl.add_value('origin', response.url)
        for place_property in item.fields:
            parse_xpath = self.template.get(place_property)

            # parse_xpath will look like either:
            # '//path/to/property/text()'
            # or
            # {'url': '//a[@id="Location"]/@href', 
            #  'xpath': '//div[@class="directions"]/span[@class="address"]/text()'}
            if isinstance(parse_xpath, dict):  # place_property is at a URL
                url = sel.xpath(parse_xpath['url_elem']).extract()
                yield Request(url, callback=self.get_url_property,
                              meta={'loader': bl, 'parse_xpath': parse_xpath,
                                    'place_property': place_property})
            else:  # parse_xpath is just an xpath; process normally
                bl.add_xpath(place_property, parse_xpath)
        yield bl.load_item()

    def get_url_property(self, response):
        loader = response.meta['loader']
        parse_xpath = response.meta['parse_xpath']
        place_property = response.meta['place_property']
        sel = Selector(response)
        loader.add_value(place_property, sel.xpath(parse_xpath['xpath'])
        return loader

我在多个站点上运行这些spider,它们中的大多数在一个页面上都有我需要的数据,而且运行得很好。但是,有些站点在子页面上有某些属性(例如,“获取方向”链接中存在的“地址”数据)。在

“yielrequest”这一行确实是我遇到问题的地方。我看到这些项在管道中移动,但是它们缺少在其他url上找到的属性(low,那些到达“yield Request”的属性)。get_url_property回调基本上只是在新的response变量中寻找xpath,并将其添加到item loader实例中。在

有没有办法做我想找的,还是有更好的办法?我希望避免使用同步调用来获取我需要的数据(如果这在这里甚至是可能的话),但是如果这是最好的方法,那么这可能是正确的方法。谢谢。在


Tags: selfaddurlget属性parseresponseplace
1条回答
网友
1楼 · 发布于 2024-04-26 20:51:52

如果我没听错的话,你至少有两种不同的情况:

  1. 爬网页面链接到另一个包含数据的页面(需要1+进一步请求)
  2. 爬网页面包含数据(无需进一步请求)

在当前代码中,对于这两种情况都调用yield bl.load_item(),但在{}回调中。请注意,您生成的请求是在稍后的某个时间点执行的,因此该项是不完整的,这就是为什么在第一种情况下该项缺少place_属性键的原因。在

可能的解决方案

一个可能的解决方案(如果我理解正确的话)是利用Scrapy的异步行为。只涉及对代码的微小更改。在

对于第一种情况,您将项目加载器传递给另一个请求,然后另一个请求将生成它。这是您在isinstanceif子句中执行的操作。您需要更改get_url_property回调的返回值,以实际生成加载的项。在

对于第二种情况,您可以直接返回项目, 因此,只需在else子句中生成项目。在

下面的代码包含对示例的更改。 这能解决你的问题吗?在

def parse(self, response):

    # ...

    if isinstance(parse_xpath, dict):  # place_property is at a URL
        url = sel.xpath(parse_xpath['url_elem']).extract()
        yield Request(url, callback=self.get_url_property,
                      meta={'loader': bl, 'parse_xpath': parse_xpath,
                            'place_property': place_property})
    else:  # parse_xpath is just an xpath; process normally
        bl.add_xpath(place_property, parse_xpath)
        yield bl.load_item()

def get_url_property(self, response):

    loader = response.meta['loader']
    # ...
    loader.add_value(place_property, sel.xpath(parse_xpath['xpath'])
    yield loader.load_item()

与这个问题相关的是question of chaining requests,我已经注意到了一个类似的解决方案。在

相关问题 更多 >