2014-04-09 30 views
8

我是Python的初學者,我正在使用Scrapy開發人員Web項目。使用中間件忽略Scrapy中的重複項

我使用Scrapy從多個網站反覆提取數據,因此如果在添加鏈接之前鏈接已經存在於數據庫中,我需要檢查每個抓取。我做了一個piplines.py類:

class DuplicatesPipline(object): 
    def process_item(self, item, spider): 
     if memc2.get(item['link']) is None: 
      return item 
     else: 
      raise DropItem('Duplication %s', item['link']) 

但我聽說使用中間件更適合這項任務。

我發現它有點難以在Scrapy中使用中間件,任何人都可以請重定向我一個很好的教程。

意見是歡迎。

感謝,

編輯:

我使用MySQL和memcache。

這是我嘗試根據@Talvalin答案:

# -*- coding: utf-8 -*- 

from scrapy.exceptions import IgnoreRequest 
import MySQLdb as mdb 
import memcache 

connexion = mdb.connect('localhost','dev','passe','mydb') 
memc2 = memcache.Client(['127.0.0.1:11211'], debug=1) 

class IgnoreDuplicates(): 

    def __init__(self): 
     #clear memcache object 
     memc2.flush_all() 

     #update memc2 
     with connexion: 
      cur = connexion.cursor() 
      cur.execute('SELECT link, title FROM items') 
      for item in cur.fetchall(): 
       memc2.set(item[0], item[1]) 

    def precess_request(self, request, spider): 
     #if the url is not in memc2 keys, it returns None. 
     if memc2.get(request.url) is None: 
      return None 
     else: 
      raise IgnoreRequest() 

DOWNLOADER_MIDDLEWARES = { 
    'myproject.middlewares.IgnoreDuplicates': 543, 
    'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware': 500, } 

但似乎爬行時process_request方法被忽略。

由於提前,

+0

本質上講,你需要創建一個實現了'process_response'方法並加載抓取網址,並檢查傳入響應的URL,看是否有匹配一個下載的中間件類。 http://doc.scrapy.org/en/latest/topics/downloader-middleware.html – Talvalin

+0

你用什麼數據庫的方式? – Talvalin

+0

我正在使用MySql和memcache。 感謝您的回覆。 – elhoucine

回答

8

下面是一些例子中間件代碼,從sqlite3的表(Id INT, url TEXT)負載網址爲一組,然後檢查要求,對網址的集合,以確定是否該URL應該被忽略或沒有。使用這個代碼來使用MySQL和memcache應該是相當直接的,但是請讓我知道你是否有任何問題或疑問。 :)

import sqlite3 
from scrapy.exceptions import IgnoreRequest 

class IgnoreDuplicates(): 

    def __init__(self): 
     self.crawled_urls = set() 

     with sqlite3.connect('C:\dev\scrapy.db') as conn: 
      cur = conn.cursor() 
      cur.execute("""SELECT url FROM CrawledURLs""") 
      self.crawled_urls.update(x[0] for x in cur.fetchall()) 

     print self.crawled_urls 

    def process_request(self, request, spider): 
     if request.url in self.crawled_urls: 
      raise IgnoreRequest() 
     else: 
      return None 

在你的導入問題和我一樣,即將衝顯示器截止機會,上面的代碼是在一個middlewares.py文件放置在頂層項目文件夾下面DOWNLOADER_MIDDLEWARES設置

DOWNLOADER_MIDDLEWARES = { 
    'myproject.middlewares.IgnoreDuplicates': 543, 
    'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware': 500, 
} 
+0

您好Talvalin,我測試了您的解決方案,但似乎Scrapy在忽略時忽略了process_request方法,所以它不會忽略重複的鏈接。我檢查了文檔,發現只有process_spider_input,process_spider_output等方法,但沒有process_request。 謝謝 – elhoucine

+1

當您運行您的蜘蛛時,IgnoreDuplicates是否顯示在啓用的中間件下的日誌中? – Talvalin

+0

我想是的。 我運行「scrapy crawl project_name」---------- 2014-04-09 22:36:07 + 0100 [scrapy] INFO:Enabled downloader middlewares:HttpAuthMiddleware,DownloadTimeoutMiddleware,UserAgentMiddleware,RetryMiddleware, IgnoreDuplicates,DefaultHeadersMiddleware,MetaRefreshMiddleware,HttpCompressionMiddleware,RedirectMiddleware,CookiesMiddleware,ChunkedTransferMiddleware,DownloaderStats 2014年4月9日22:36:07 + 0100 [scrapy] INFO:啓用蜘蛛中間件:HttpErrorMiddleware,OffsiteMiddleware,RefererMiddleware,UrlLengthMiddleware,DepthMiddleware – elhoucine