项目加载器不适用于 response.meta

Item Loader not working with response.meta

我想将两个项目加载到项目加载器中,该项目加载器通过 response.meta 命令实例化。不知何故,标准:

loader.add_xpath('item', 'xpath')

不工作(即没有保存或写入任何值,就像从未创建 'item' 一样),但具有完全相同的表达式:

response.xpath('xpath)
loader.add_value('item',value) 

有效吗?现在有人为什么?完整代码如下:

Spider.py

def parse(self, response):
    for record in response.xpath('//div[@class="box list"]/div[starts-with(@class,"record")]'):
        loader = BaseItemLoader(item=BezrealitkyItems(), selector=record)
        loader.add_xpath('title','.//div[@class="details"]/h2/a[@href]/text()')
        listing_url = record.xpath('.//div[@class="details"]/p[@class="short-url"]/text()').extract_first()
        yield scrapy.Request(listing_url, meta={'loader' : loader}, callback=self.parse_listing)

def parse_listing(self, response):
    loader = response.meta['loader']
    loader.add_value('url', response.url)
    loader.add_xpath('lat','//script[contains(.,"recordGps")]',re=r'(?:"lat":)[0-9]+\.[0-9]+')
    return loader.load_item()

上面的方法不起作用,但当我尝试这个时它起作用了:

    lat_coords = response.xpath('//script[contains(.,"recordGps")]/text()').re(r'(?:"lat":)([0-9]+\.[0-9]+)')
    loader.add_value('lat', lat_coords)

我的item.py没什么特别的:

class BezrealitkyItems(scrapy.Item):
    title = scrapy.Field()
    url = scrapy.Field()
    lat = scrapy.Field()
class BaseItemLoader(ItemLoader):
    title_in = MapCompose(lambda v: v.strip(), Join(''), unidecode)
    title_out = TakeFirst()

澄清一下,我没有收到任何错误消息。只是 'lat' 项目尚未创建,也没有任何内容被删除。其他项目都很好地抓取,包括也是通过 parse_listing 函数添加的 url。

发生这种情况是因为您继承了具有自己的选择器对象的加载程序引用。
在这里,您使用您的参考创建并分配一个选择器参数:

loader = BaseItemLoader(item=BezrealitkyItems(), selector=record)

现在您稍后将此加载器放入您的 Request.meta 属性并将其传递给下一个解析方法。但是,您没有做的是在从元中检索加载程序后更新选择器上下文:

loader = response.meta['loader']
# if you check loader.selector you'll see that it still has html body
# set in previous method, i.e. selector of record in your case
loader.selector = Selector(response)  # <--- this is missing

这可行,但应该避免,因为在 meta 中拥有包含大量引用的复杂对象是一个坏主意,并且可能导致主要与 Twisted 框架相关的各种错误(即 scrapy用于它的并发性)。
然而,您应该做的是在每一步中加载并重新创建项目:

def parse(self, response):
    loader = BaseItemLoader(item=BezrealitkyItems(), selector=record)
    yield scrapy.Request('some_url', meta={'item': loader.load_item()}, callback=self.parse2)

def parse2(self, response):
    loader = BaseItemLoader(item=response.meta['item'], selector=record)