2014-06-15 103 views
4

我是一名使用Python編寫的爬蟲程序,它抓取給定域中的所有頁面,作爲特定於域的搜索引擎的一部分。我使用Django,Scrapy和Celery來實現這一點。該方案如下:Scrapy spider在使用芹菜時沒有遵循鏈接

我接收來自用戶的域名,並調用視圖內crawl任務,傳遞域作爲參數:

crawl.delay(domain)

任務本身只是調用一個函數用於啓動過程爬行:

from .crawler.crawl import run_spider 
from celery import shared_task 

@shared_task 
def crawl(domain): 
    return run_spider(domain) 

run_spider開始抓取過程,as in this SO answer,與WebSpider替換MySpider

WebSpider繼承自CrawlSpider,我現在只是用它來測試功能。定義的唯一規則需要一個SgmlLinkExtractor實例和一個回調函數parse_page,它簡單地提取響應url和頁面標題,用它們填充一個新的DjangoItem(HTMLPageItem)並將其保存到數據庫中(我不知道效率如何)。

from urlparse import urlparse 
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor 
from ..items import HTMLPageItem 
from scrapy.selector import Selector 
from scrapy.contrib.spiders import Rule, CrawlSpider 

class WebSpider(CrawlSpider): 
    name = "web" 

    def __init__(self, **kw): 
     super(WebSpider, self).__init__(**kw) 
     url = kw.get('domain') or kw.get('url') 
     if not (url.startswith('http://') or url.startswith('https://')): 
      url = "http://%s/" % url 
     self.url = url 
     self.allowed_domains = [urlparse(url).hostname.lstrip('www.')] 
     self.start_urls = [url] 
     self.rules = [ 
      Rule(SgmlLinkExtractor(
       allow_domains=self.allowed_domains, 
       unique=True), callback='parse_page', follow=True) 
     ] 

    def parse_start_url(self, response): 
     return self.parse_page(response) 

    def parse_page(self, response): 
     sel = Selector(response) 
     item = HTMLPageItem() 
     item['url'] = response.request.url 
     item['title'] = sel.xpath('//title/text()').extract()[0] 
     item.save() 
     return item 

問題是爬蟲抓取唯一的start_urls和不遵循鏈接(或調用回調函數)以下這種情況下,用芹菜時。然而通過python manage.py shell調用run_spider就行了!

另一個問題是項目管道和日誌不能與芹菜一起工作。這使得調試更加困難。我認爲這些問題可能是相關的。

+1

考慮與芹菜寫一個「hello world」程序,並讓日誌工作。沒有看到發生了什麼事情使事情變得困難:) – johntellsall

+0

謝謝!我很快就得到了芹菜測井工作。我正在嘗試使用Scrapy進行日誌記錄,但這不起作用。日誌確實有幫助,我解決了這個問題:),現在將發佈答案。 –

+0

管道仍然無法正常工作 –

回答

2

所以檢查Scrapy的代碼,並使芹菜記錄,通過web_spider.py將這兩行後:

from celery.utils.log import get_task_logger 

logger = get_task_logger(__name__) 

我能夠找到的問題: 在WebSpider初始化函數:

super(WebSpider, self).__init__(**kw) 

CrawlSpider__init__函數調用_compile_rules函數,它簡而言之複製了的規則到self._rules,同時進行一些更改。 self._rules是蜘蛛在檢查規則時使用的。在定義規則之前調用CrawlSpider的初始化函數導致空的self._rules,因此沒有遵循鏈接。

super(WebSpider, self).__init__(**kw)行移動到最後一行WebSpider__init__修復了這個問題。

更新:代碼從the previously mentioned SO answer有一個小錯誤。它會導致反應堆在第二次通話後掛起。解決方法是簡單的,在WebCrawlerScript__init__方法,只需移動這條線:

self.crawler.signals.connect(reactor.stop, signal=signals.spider_closed) 

出來的if語句,如在評論認爲那裏。

更新2:我終於得到了管道工作!這不是芹菜問題。我意識到設置模塊沒有被讀取。這只是一個進口問題。要解決這個問題:

設置環境變量SCRAPY_SETTINGS_MODULE在你的Django項目的設置模塊myproject/settings.py

import os 
os.environ['SCRAPY_SETTINGS_MODULE'] = 'myapp.crawler.crawler.settings' 

在你Scrapy設置模塊crawler/settings.py,添加Scrapy項目路徑sys.path在設置文件中,這樣相對進口將工作:

import sys 
sys.path.append('/absolute/path/to/scrapy/project') 

更改路徑以適合您的情況。

+0

您是使用Django Dynamic Sc​​raper還是隻使用正常的Scrapy?我基本上做了類似於你所做的一些事情,但我需要在我創建的django項目中使用我的scrapy項目中的所有文件。 – loremIpsum1771