Item Loader不与response.meta一起使用

时间:2017-01-26 18:14:23

标签: python scrapy scrapy-spider

我想将两个项目加载到项目加载器中,该项目加载器通过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。

1 个答案:

答案 0 :(得分:1)

之所以发生这种情况,是因为您携带的是具有自己的选择对象的加载程序引用 在这里,您可以使用引用创建并指定一个selector参数:

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

现在稍后您将此加载器放入Request.meta属性并将其转移到下一个解析方法。你没有做的是从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)