为什么ItemLoader从单个元素创建列表

时间:2017-02-20 23:26:23

标签: python scrapy

我认为我的问题是由对某些scrapy概念的误解引起的。如果有人可以向我解释这一点,我将感激不尽。

让我们想象一下我有以下蜘蛛:

# -*- coding: utf-8 -*-
import scrapy
from scrapy.loader import ItemLoader
from reddit.items import RedditItem
from scrapy.loader.processors import TakeFirst


class RedditspiderSpider(scrapy.Spider):
    name = "redditspider"
    allowed_domains = ["wwww.reddit.com"]
    start_urls = [
        'https://www.reddit.com/r/starcraft/comments/5t8v7i/community_feedback_update_widow_mines_carriers/?st=iz7ba37h&sh=b7e9bd35']

    def parse(self, response):
        l = ItemLoader(item=RedditItem(), response=response)

        comments = response.xpath(
            '//div[contains(@class,"usertext-body may-blank-within md-container ")]/div')
        comments = comments[1:]
        for comment_it in comments:
            comment = comment_it.extract()
            l.add_value('comment', comment)
            yield l.load_item()

以下列方式定义RedditItem

from scrapy.item import Item, Field
from w3lib.html import remove_tags
from scrapy.loader.processors import TakeFirst


def _remove_tags(input):
    return input


class RedditItem(Item):
    comment = Field(input_processor=_remove_tags, output_processor=TakeFirst())

所以一切都简单明了。现在,我的问题。在第一个代码示例中,l加载器具有字段comments。据我所知,当我l.add_value('comment', comment)时,会触发此字段的输入处理器。 这是正确的吗?

据我所知,这是正确的。在l.add_value('comment', comment) comment中是字符串,而不是列表。但是,当我在_remove_tags中设置断点时,我发现input实际上是长度为1的列表。所以我的主要问题是它为什么会发生?为什么我会通过一个字符串并在那里看到一个列表?

我查看了scrapy源代码,发现这是_add_value(第90行):value = arg_to_iter(value)。这使事情变得非常清楚,这似乎是我在那里看到长度1列表的原因。

这条线背后的设计理由是什么?这是因为在scrapy我可以在不同的xpath / css请求中填充项目中的相同字段吗?如果是这样,那对我来说是有道理的。然后问题是:我该如何解决这个问题?我只是在输入处理器中应用map(_remove_tags, input)吗?这会是一个推荐的解决方案还是我出错了?

由于

1 个答案:

答案 0 :(得分:2)

是的,scrapy加载器设计用于处理同一领域中的多个插入,您可以使用以下方法进行测试:

from scrapy.loader.processors import Identity

class RedditItem(Item):
    comment = Field(input_processor=Identity(), output_processor=Identity())

l = ItemLoader(item=RedditItem(), response=response)
l.add_value('comment', 'first comment')
l.add_value('comment', 'second comment')

print l.output_value('comment') # ['first comment', 'second comment']

现在,正因为如此,您可以检查here scrapy程序员使用的输入和输出(default_output_processordefault_input_processor内部)的推荐处理器。

正如您所看到的,他们有一个名为MapCompose的处理器,它接受当前值的每个条目并应用定义为参数的每个方法。