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