这是对问题Scrapy: populate items with item loaders over multiple pages的公认答案的后续问题。我想使用ItemLoader
来收集来自多个请求到单个Item
的值。接受的答案表明,已加载的Item.load_item()
应该通过meta
中的request
字段传递给下一个请求。
但是,在爬网结束时返回加载的对象时,我想将output_processors
应用于单个字段的所有收集值。
ItemLoader
上的meta
实例传递给下一个request
,然后仅替换{{中的selector
或response
元素1}}在添加下一个响应的值或xpath时?示例:
ItemLoader
忽略实际网站的上下文。
答案 0 :(得分:2)
是的,您可以仅传递ItemLoader
实例。
如果很久以前我从irc或github聊天中正确地记得了这一点,那么这样做可能会存在一些潜在的问题,例如内存使用量增加或引用处理泄漏,因为您随身携带了对象引用通过将这些Itemloader实例绑定到那些请求,可以并可能需要很长时间(取决于下载队列的顺序)。 因此请记住这一点,也许要提防在大型爬网中使用此样式,或者进行一些内存调试以确保确定性。
但是,我过去曾广泛使用此方法(并且在使用ItemLoaders时仍会使用此方法),而我自己尚未发现该方法有任何问题。
这是我的操作方式:
import scrapy
from myproject.loader import ItemLoader
class TheLoader(ItemLoader):
pass
class SomeSpider(scrapy.Spider):
[...]
def parse(self, response):
loader = TheLoader(item=TestItems(), response=response)
loader.add_xpath('title1', '//*[@id="firstHeading"]/text()')
request = Request("https://en.wikipedia.org/wiki/2016_Rugby_Championship",
callback=self.parsePage1,
dont_filter=True
)
request.meta['loader'] = loader
yield request
def parsePage1(self, response):
loader = response.meta['loader']
# rebind ItemLoader to new Selector instance
#loader.reset(selector=response.selector, response=response)
# skipping the selector will default to response.selector, like ItemLoader
loader.reset(response=response)
loader.add_xpath('title1', '//*[@id="firstHeading"]/text()')
return loader.load_item()
这需要使用自定义的ItemLoader
类,可以在my scrapy scrapyard中找到该类,
但课程的相关部分在这里:
from scrapy.loader import ItemLoader as ScrapyItemLoader
class ItemLoader(ScrapyItemLoader):
""" Extended Loader
for Selector resetting.
"""
def reset(self, selector=None, response=None):
if response is not None:
if selector is None:
selector = self.default_selector_class(response)
self.selector = selector
self.context.update(selector=selector, response=response)
elif selector is not None:
self.selector = selector
self.context.update(selector=selector)