[英]How to access pipeline database pool in scrapy spider
首先,這是我想做的事情:
我有一個XMLFeedSpider,它通過XML文件中的產品列表(節點),並創建保存在管道中的項目。 第一次看到產品時,我需要創建請求以對產品的url字段進行一些抓取以獲取圖像等。在后續讀取Feed時,如果我看到相同的產品,我不想浪費時間/資源,只是想跳過這些額外的請求。 要查看要跳過哪些產品,我需要訪問我的數據庫以查看該產品是否存在。
這是我想到的各種方法:
dbpool = adbapi.ConnectionPool('psycopg2', cp_max=2, cp_min=1, **dbargs)
,僅使用它似乎效率更高,所以我不是一直在創建新的數據庫連接。 我不知道如何在蜘蛛中訪問實例化的管道類(這可能更多是一個通用的python問題)。 更新:這是我的數據庫池管道
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)
我認為您是按item
指URL
,請記住,對於scrapy
, item
是數據輸出,而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
異常。
實例化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()
現在,在管道上,刪除dbpool
的實例化,並在必要時從spider
參數獲取它,請記住, process_item
會接收該項目和spider作為參數,因此您應該能夠使用spider.dbpool
檢查數據庫連接。
記住要激活您的中間件 。
這樣,您應該只在Spider對象內執行db連接的一個實例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.