Scrapy:在Postgres管道中使用ItemLoader的最佳方法是什么?

1 投票
1 回答
1133 浏览
提问于 2025-04-18 12:55

我正在尝试使用 itemLoader 来给 Scrapy 中的空项目设置一个默认值,就像在 items.py 里这样:

prod_specs = Field(
    default=[],
    input_processor=MapCompose(unicode_to_str, strip_tabs_new_lines),
)

所以如果 prod_specs 没有被设置,它应该给一个空对象。但是现在不管用。如果我尝试用 item['prod_specs'] 把字段存储到数据库里,

我收到一个错误,提示我这个键不存在:

exceptions.KeyError: 'prod_specs' 

其他字段如果没有设置也是一样。我觉得是因为我在用 item['prod_specs'],而不是像 items.py 中那样用 itemLoader,这导致了错误。但我不太确定。

你们觉得怎么样?有没有解决办法?

1 个回答

1

编辑:官方文档似乎有点过时,字段的默认值现在不再有效了(可以查看 https://github.com/scrapy/scrapy/issues/560)。所以另一个选择是通过管道为项目分配默认值:

def parse_item(self, item, spider):
    if "prod_specs" not in item: item['prod_specs'] = []
    return item

或者在使用 psycopg2 插入数据时:

def parse_item(self, item, spider):
    cur.execute("insert into mytable(prod_specs) values(%s)",
                item.get('prod_specs',[]))
    return

你正在尝试把 ItemLoader 当作一个 Item 来使用。下面是如何设置你的项目和 ItemLoader 的方法。

items.py

from scrapy.item import Field, Item
from scrapy.contrib.loader.processor import MapCompose

class Product(Item):
    prod_specs = Field(
        default=[],
        input_processor=MapCompose(unicode_to_str, strip_tabs_new_lines)
    )

spider/myspider.py

from scrapy.contrib.loader import ItemLoader
from myproject.items import Product

def parse(self, response):
    l = MyLoader(item=Product(), response=response)
    l.add_xpath('prod_specs', '//div[@class="prod_specs"]')
    return l.load_item()

如果你打算使用很多不同的项目,建议你继承 ItemLoader,并定义默认的处理器。

这样够不够回答你的问题呢?你提到想写一个 Postgres 的管道。我发现最简单的方法是使用 SQLAlchemy,这样你可以通过一个管道向多个数据库写入任意数量的对象。

撰写回答