Как получить / импортировать список элементов Scrapy из items.py в pipelines.py? - PullRequest
0 голосов
/ 08 октября 2018

В моем 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'


ОБНОВЛЕНИЕ : 2018-10-08

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

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

  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() ихПорядок остается без изменений.

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

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

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

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

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

1 Ответ

0 голосов
/ 08 октября 2018

Трубопроводы 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)
...