簡體   English   中英

如何在Scrapy Spider中訪問管道數據庫池

[英]How to access pipeline database pool in scrapy spider

首先,這是我想做的事情:

我有一個XMLFeedSpider,它通過XML文件中的產品列表(節點),並創建保存在管道中的項目。 第一次看到產品時,我需要創建請求以對產品的url字段進行一些抓取以獲取圖像等。在后續讀取Feed時,如果我看到相同的產品,我不想浪費時間/資源,只是想跳過這些額外的請求。 要查看要跳過哪些產品,我需要訪問我的數據庫以查看該產品是否存在。

這是我想到的各種方法:

  1. 只需為Spider中的每個產品創建一個數據庫請求。 這似乎是個壞主意。
  2. 在我的商品存儲管道中,我已經按如下所示創建數據庫池: dbpool = adbapi.ConnectionPool('psycopg2', cp_max=2, cp_min=1, **dbargs) ,僅使用它似乎效率更高,所以我不是一直在創建新的數據庫連接。 我不知道如何在蜘蛛中訪問實例化的管道類(這可能更多是一個通用的python問題)。
    注意:這個人基本上是在問同樣的問題,但並沒有真正得到他想要的答案。 如何在Scrapy Spider中獲取管道對象
  3. 也許在開始爬網之前,將所有產品url加載到內存中,以便在處理產品時可以進行比較? 在哪里做這件事的好地方?
  4. 還有其他建議嗎?

更新:這是我的數據庫池管道

class PostgresStorePipeline(object):
    """A pipeline to store the item in a MySQL database.
    This implementation uses Twisted's asynchronous database API.
    """

    def __init__(self, dbpool):
        print "Opening connection pool..."
        dispatcher.connect(self.spider_closed, signals.spider_closed)
        self.dbpool = dbpool

    @classmethod
    def from_settings(cls, settings):
        dbargs = dict(
            host=settings['MYSQL_HOST'],
            database=settings['MYSQL_DBNAME'],
            user=settings['MYSQL_USER'],
            password=settings['MYSQL_PASSWD'],
            #charset='utf8',
            #use_unicode=True,
        )
        dbpool = adbapi.ConnectionPool('psycopg2', cp_max=2, cp_min=1, **dbargs)
        return cls(dbpool)

我認為您是按itemURL ,請記住,對於scrapyitem是數據輸出,而pipeline是一種處理這些輸出項的機制。

當然,您不需要打開許多連接即可執行數據庫查詢,但是您將必須執行必要的查詢。 這取決於您的數據庫中有多少條記錄只能執行一個查詢或每個URL進行一次查詢,您應該測試哪種記錄更適合您的情況。

我建議使用以下方式設置自己的DUPEFILTER_CLASS

from scrapy.dupefilters import RFPDupeFilter

class DBDupeFilter(RFPDupeFilter):

    def __init__(self, *args, **kwargs):
        # self.cursor = .....                       # instantiate your cursor
        super(DBDupeFilter, self).__init__(*args, **kwargs)

    def request_seen(self, request):
        if self.cursor.execute("myquery"):          # if exists
            return True
        else:
            return super(DBDupeFilter, self).request_seen(request)

    def close(self, reason):
        self.cursor.close()                         # close  your cursor
        super(DBDupeFilter, self).close(reason)

更新

這里的問題是DUPEFILTER_CLASS沒有在其request_seen對象上提供蜘蛛,甚至沒有進入構造函數,因此我認為最好的選擇是使用Downloader Middleware ,在其中可以引發IgnoreRequest異常。

  1. 實例化Spider上的db連接,您可以在Spider本身(構造函數)上執行此操作,也可以通過中間件或管道上的信號添加它,我們將其添加到中間件上:

     from scrapy.exceptions import IgnoreRequest class DBMiddleware(object): def __init__(self): pass @classmethod def from_crawler(cls, crawler): o = cls() crawler.signals.connect(o.spider_opened, signal=signals.spider_opened) return o def spider_opened(self, spider): spider.dbpool = adbapi.ConnectionPool('psycopg2', cp_max=2, cp_min=1, **dbargs) def process_request(self, request, spider): if spider.dbpool... # check if request.url inside the database raise IgnoreRequest() 
  2. 現在,在管道上,刪除dbpool的實例化,並在必要時從spider參數獲取它,請記住, process_item會接收該項目和spider作為參數,因此您應該能夠使用spider.dbpool檢查數據庫連接。

  3. 記住要激活您的中間件

這樣,您應該只在Spider對象內執行db連接的一個實例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM