如何以正确的顺序导入 Scrapy item keys?

How to import Scrapy item keys in the correct order?

我正在将 Scrapy 项目密钥从 items.py 导入 pipelines.py。 问题是导入项目的 order 与它们在 items.py 文件中的定义不同。

我的 items.py 文件:

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

在我的 pipelines.py:

from adbot.items import NewAdsItem
...
def open_spider(self, spider):
     self.ikeys = NewAdsItem.fields.keys()
     print("Keys in pipelines: \t%s" % ",".join(self.ikeys) )
     #self.createDbTable(ikeys)

输出为:

Keys in pipelines:  AdId,AdURL,DateR

而不是预期的:AdId,DateR,AdURL

如何保证导入的顺序不变?

注意: 这可能与 有关,但完全不清楚发生了什么,因为 Python3 文档指出列出和听写应该保留他们的顺序。另请注意,当使用 process_item() 和使用 item.keys() 时,顺序将保留!但是我需要访问 keys 以便 before item 被抓取。

一个简单的解决方法是在 Item class:

中定义 keys() 方法
class MyItem(Item):
    foo = Field()
    bar = Field()
    gar = Field()
    cha = Field()

    def keys(self):
        # in your preferred order
        return ['cha', 'gar','bar','foo']

我能让它工作的唯一方法是按以下方式使用 this solution

我的items.py文件:

from scrapy.item import Item, Field
from collections import OrderedDict
from types import FunctionType

class StaticOrderHelper(type):
    # Requires Python3
    def __prepare__(name, bases, **kwargs):
        return OrderedDict()

    def __new__(mcls, name, bases, namespace, **kwargs):
        namespace['_field_order'] = [
                k
                for k, v in namespace.items()
                if not k.startswith('__') and not k.endswith('__')
                    and not isinstance(v, (FunctionType, classmethod, staticmethod))
        ]
        return type.__new__(mcls, name, bases, namespace, **kwargs)

class NewAdsItem(metaclass=StaticOrderHelper):
    AdId        = Field()
    DateR       = Field()
    AdURL       = Field()

然后将 _field_order 项导入到您的 piplines.py 中:

...
from adbot.items import NewAdsItem
...
class DbPipeline(object):
    ikeys = NewAdsItem._field_order
    ...
    def createDbTable(self):
        print("Creating new table: %s" % self.dbtable )
        print("Keys in creatDbTable: \t%s" % ",".join(self.ikeys) )
        ...

我现在可以按照正确的出现顺序创建新的数据库表,而不必担心 Python 以意想不到的方式对字典进行排序的奇怪方式。