Scrapy:在Postgres管道中使用ItemLoader的最佳方法是什么?
我正在尝试使用 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,这样你可以通过一个管道向多个数据库写入任意数量的对象。