【问题标题】:How to get/import the Scrapy item list from items.py to pipelines.py?如何从 items.py 获取/导入 Scrapy 项目列表到 pipelines.py?
【发布时间】:2018-10-07 23:15:11
【问题描述】:

在我的items.py

class NewAdsItem(Item):
    AdId        = Field()
    DateR       = Field()
    AdURL       = Field()

在我的pipelines.py

import sqlite3
from scrapy.conf import settings

con = None
class DbPipeline(object):

    def __init__(self):
        self.setupDBCon()
        self.createTables()

    def setupDBCon(self):
        # This is NOT OK!
        # I want to get the items already HERE!
        dbfile = settings.get('SQLITE_FILE')
        self.con = sqlite3.connect(dbfile)
        self.cur = self.con.cursor()

    def createTables(self):
        # OR optionally HERE.
        self.createDbTable()

    ...

    def process_item(self, item, spider):
        self.storeInDb(item)
        return item

    def storeInDb(self, item):
        # This is OK, I CAN get the items in here, using: 
        # item.keys() and/or item.values()
        sql = "INSERT INTO {0} ({1}) VALUES ({2})".format(self.dbtable, ','.join(item.keys()), ','.join(['?'] * len(item.keys())) )
        ...

在执行process_item()(在 pipelines.py 中)之前,如何从 items.py 中获取项目列表名称(如“AdId”等)?


我使用scrapy runspider myspider.py 执行。

我已经尝试像 def setupDBCon(self, item) 这样添加“项目”和/或“蜘蛛”,但这没有用,结果是: TypeError: setupDBCon() missing 1 required positional argument: 'item'


更新:2018-10-08

结果(A):

部分遵循@granitosaurus 的解决方案,我发现我可以通过以下方式将项目 keys 作为列表获取:

  1. 将 (a): from adbot.items import NewAdsItem 添加到我的主要蜘蛛代码中。
  2. 在上述类别中添加 (b):ikeys = NewAdsItem.fields.keys()
  3. 然后我可以通过我的pipelines.py 访问 keys
    def open_spider(self, spider):
        self.ikeys = list(spider.ikeys)
        print("Keys in pipelines: \t%s" % ",".join(self.ikeys) )
        #self.createDbTable(ikeys)

但是,这种方法有两个问题:

  1. 我无法将 ikeys 列表放入 createDbTable()。 (我不断收到关于缺少参数的错误。)

  2. ikeys 列表(已检索)已重新排列,没有保持项目的顺序,因为它们出现在 项目中。 py,这部分地破坏了目的。我仍然不明白为什么这些是乱序的,当所有文档都说 Python3 应该保持字典和列表等的顺序时。同时,当使用 process_item() 并通过以下方式获取项目时:item.keys() 他们秩序保持不变。

结果(B):

最后,修复起来太费力和复杂了(A),所以我只是将相关的items.pyClass导入到我的pipelines.py中,并使用item 列表作为全局变量,像这样:

def createDbTable(self):
    self.ikeys = NewAdsItem.fields.keys()
    print("Keys in creatDbTable: \t%s" % ",".join(self.ikeys) )
    ...

在这种情况下,我只是决定接受获得的列表似乎按字母顺序排序,并通过更改键名来解决此问题。 (作弊!)

这令人失望,因为代码丑陋且扭曲。 任何更好的建议将不胜感激。

【问题讨论】:

    标签: python-3.x scrapy scrapy-pipeline


    【解决方案1】:

    Scrapy 管道有 3 个连接方法:

    process_item(self, item, spider)
    为每个项目管道组件调用此方法。 process_item() 必须:返回带有数据的 dict,返回 Item(或任何后代类)对象,返回 Twisted Deferred 或引发 DropItem 异常。丢弃的项目不再由其他管道组件处理。

    open_spider(self, spider)
    该方法在蜘蛛打开时调用。

    close_spider(self, spider)
    该方法在蜘蛛关闭时调用。

    https://doc.scrapy.org/en/latest/topics/item-pipeline.html

    所以你只能在process_item 方法中访问项目。

    如果你想获取项目类,但是你可以将它附加到蜘蛛类:

    class MySpider(Spider):
        item_cls = MyItem
    
    class MyPipeline:
        def open_spider(self, spider):
            fields = spider.item_cls.fields
            # fields is a dictionary of key: default value
            self.setup_table(fields)
    

    您可以在 process_item 方法本身期间延迟加载:

    class MyPipeline:
        item = None
    
    def process_item(self, item, spider):
        if not self.item:
            self.item = item
            self.setup_table(item)
    

    【讨论】:

    • 我正在尝试第一种方式,使用 open_spider()。所以我在不同的文件中有 MySpiderMyPipeline 类。你为什么把它们放在同一个地方? (似乎不是一种标准的方法。)还有你的意思是:item_cls = MyItem?你的意思是(就我而言):NewAdsItem?
    • 有一个错字:item_cls 应该是items_cls。此外,返回的 dict 会产生次要问题,因为项目 names 不是按原始顺序排列的,而是按字母顺序排列的。知道如何解决这个问题吗?
    • 我的回答只是笼统的,无论您的结构是什么以及您的 Item 被称为什么都不是真正相关的。关于订购问题,您应该打开一个新问题,因为它也不相关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-25
    • 2023-03-05
    • 1970-01-01
    • 2021-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多