scrapy 在碎片中嵌套项目数据的正确方法

mzsu5hc0  于 2023-03-30  发布在  其他
关注(0)|答案(2)|浏览(122)

嵌套Item数据的正确方法是什么?
例如,我想要一个产品的输出:

{
    'price': price,
    'title': title,
    'meta': {
        'url': url,
        'added_on': added_on
}

我有擦伤。项目:

class ProductItem(scrapy.Item):
    url = scrapy.Field(output_processor=TakeFirst())
    price = scrapy.Field(output_processor=TakeFirst())
    title = scrapy.Field(output_processor=TakeFirst())
    url = scrapy.Field(output_processor=TakeFirst())
    added_on = scrapy.Field(output_processor=TakeFirst())

现在,我这样做的方式是根据新的项目模板重新格式化管道中的整个项目:

class FormatedItem(scrapy.Item):
    title = scrapy.Field()
    price = scrapy.Field()
    meta = scrapy.Field()

管道中:

def process_item(self, item, spider):
    formated_item = FormatedItem()
    formated_item['title'] = item['title']
    formated_item['price'] = item['price']
    formated_item['meta'] = {
        'url': item['url'],
        'added_on': item['added_on']
    }
    return formated_item

这是正确的方法吗?或者有没有一种更直接的方法来解决这个问题,而不破坏框架的哲学?

shyt4zoc

shyt4zoc1#

更新来自评论:看起来嵌套加载器是更新的方法。另一条评论指出这种方法会在序列化过程中导致错误。

最好的方法是创建一个main和一个meta项目类/加载器。

from scrapy.item import Item, Field
from scrapy.loader import ItemLoader
from itemloaders.processors import TakeFirst

class MetaItem(Item):
    url = Field()
    added_on = Field()

class MainItem(Item):
    price = Field()
    title = Field()
    meta = Field(serializer=MetaItem)

class MainItemLoader(ItemLoader):
    default_item_class = MainItem
    default_output_processor = TakeFirst()

class MetaItemLoader(ItemLoader):
    default_item_class = MetaItem
    default_output_processor = TakeFirst()

样品使用:

from scrapy import Spider
from ..items import MainItemLoader, MetaItemLoader
from scrapy.selector import Selector

class DmozSpider(Spider):
    name = "dmoz"
    allowed_domains = ["example.com"]
    start_urls = ["http://example.com"]

    def parse(self, response):
        mainloader = MainItemLoader(selector=Selector(response))
        mainloader.add_value('title', 'test')
        mainloader.add_value('price', 'price')
        mainloader.add_value('meta', self.get_meta(response))
        return mainloader.load_item()

    def get_meta(self, response):
        metaloader = MetaItemLoader(selector=Selector(response))
        metaloader.add_value('url', response.url)
        metaloader.add_value('added_on', 'now')
        return metaloader.load_item()

之后,您可以通过创建更多的“子项”来轻松扩展您的项目

nimxete2

nimxete22#

我认为在spider中构造字典会更简单。这里有两种不同的方法,都能达到相同的结果。这里唯一可能的dealbreaker是处理器应用于item['meta']字段,而不是item['meta']['added_on']和item['meta']['url']字段。

def parse(self, response):
    item = MyItem()
    item['meta'] = {'added_on': response.css("a::text").extract()[0]}
    item['meta']['url'] = response.xpath("//a/@href").extract()[0]
    return item

有没有一个特定的原因,你想构造它的方式,而不是解包的 meta字段?

相关问题