Как получить/импортировать список элементов Scrapy из items.py в pipes.py?

В моем 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())) )
        ...

Как я могу получить имена списков элементов (например, «AdId» и т. д.) из items.py до выполнения process_item()pipelines.py)?


Я использую scrapy runspider myspider.py для выполнения.

Я уже пытался добавить "предмет" и/или "паук" подобным образом def setupDBCon(self, item), но это не сработало и привело к следующему результату: TypeError: setupDBCon() missing 1 required positional argument: 'item'


ОБНОВЛЕНИЕ: 08.10.2018

Результат (А):

Частично следуя решению @granitosaurus, я обнаружил, что могу получить элемент keys в виде списка:

  1. Добавление (а): from adbot.items import NewAdsItem к моему основному коду паука.
  2. Добавление (b): ikeys = NewAdsItem.fields.keys() в указанном выше классе.
  3. Затем я мог получить доступ к ключам из моего pipelines.py через:
    def open_spider(self, spider):
        self.ikeys = list(spider.ikeys)
        print("Keys in pipelines: \t%s" % ",".join(self.ikeys) )
        #self.createDbTable(ikeys)

Однако у этого метода было 2 проблемы:

  1. Мне не удалось получить список ikeys в папку createDbTable(). (Я продолжал получать сообщения об отсутствующих аргументах то здесь, то там.)

  2. Список ikeys (полученный) был переупорядочен и не сохранил порядок элементов, как в items.py, что частично разрушило цель. Я до сих пор не понимаю, почему они не по порядку, когда во всех документах говорится, что Python3 должен сохранять порядок диктов, списков и т. Д. В то же время при использовании process_item() и получении элементов через: item.keys() их порядок остается неизменным.

Результат (Б):

В конце концов, это оказалось слишком трудоемким и сложным для исправления (A), поэтому я просто импортировал соответствующий items.py класс в свой pipelines.py и использовал элемент list как глобальную переменную, например:

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

В этом случае я просто решил признать, что полученный список похоже отсортирован по алфавиту, и решил проблему, просто изменив имена ключей. (Мошенничество!)

Это разочаровывает, потому что код уродлив и искажен. Любые лучшие предложения будут высоко оценены.


person not2qubit    schedule 07.10.2018    source источник


Ответы (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)
person Granitosaurus    schedule 08.10.2018
comment
Я пытаюсь сделать это первым способом, используя open_spider(). Итак, у меня есть классы MySpider и MyPipeline в разных файлах. Почему ты поставил их в один ряд? (Кажется, это нестандартный способ сделать это.) И что вы имеете в виду под: item_cls = MyItem? Вы имеете в виду (в моем случае): NewAdsItem? - person not2qubit; 08.10.2018
comment
Есть опечатка: item_cls, вероятно, должно быть items_cls. Кроме того, возвращаемый словарь создает вторичную проблему, так как элементы names расположены не в исходном порядке, а, похоже, расположены в алфавитном порядке. Есть идеи, как это исправить? - person not2qubit; 08.10.2018
comment
Я просто отвечаю в общем, какой бы ни была ваша структура и как бы ни назывался ваш предмет, это не имеет большого значения. Что касается проблемы с заказом, вы должны открыть новую проблему, поскольку она также не связана. - person Granitosaurus; 08.10.2018