2012-03-14 52 views
4

我已經編寫了scrapy crawlspider來抓取具有類似頁面>類型頁面>列表頁面>項目頁面的結構的站點。在類別頁面上有許多類別的機器,每類機器都有一個類型很多的類型頁面,每種不同類型都有一個項目列表,最後每臺機器都有一個包含它的信息的頁面。Scrapy:抓取頁面不會生成嵌套回調中的所有鏈接

我的蜘蛛有一個規則,從主頁獲取到我定義回調parsecatpage的類別頁面,這會生成一個項目,抓取該類別併爲頁面上的每個類別生成一個新請求。我通過request.meta傳遞項目和類別名稱,並指定回調爲parsetype頁面。

Parsetypepage從response.meta獲取項目,然後爲每個類型生成請求並傳遞該項目,並將request.meta中的類別和類型連接在一起。回調是parsemachinelist。

Parsemachinelist從response.meta獲取項目,然後爲列表中的每個項目生成請求,並通過request.meta將項目,類別/類型,描述傳遞給最終回調parsemachine。這將獲取元屬性,並使用頁面上的信息和前一頁傳遞的信息填充項目中的所有字段,最後生成一個項目。

如果我將其限制爲單個類別並鍵入(例如contains[@href, "filter=c:Grinders"]contains[@href, "filter=t:Disc+-+Horizontal%2C+Single+End"]),那麼它就起作用,並且最終頁面上的每臺機器都有一個機器項目。問題在於,一旦我允許蜘蛛對所有類別和所有類型進行scrapy處理,它就會在返回的最後一頁的第一個頁面中返回機器的scrapy項目,一旦它完成,蜘蛛就完成了,獲得其他類別等

這裏是(匿名)代碼

from scrapy.selector import HtmlXPathSelector 
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor 
from scrapy.contrib.spiders import CrawlSpider, Rule 
from scrapy.http import Request 
from myspider.items import MachineItem 
import urlparse 


class MachineSpider(CrawlSpider): 
    name = 'myspider' 
    allowed_domains = ['example.com'] 
    start_urls = ['http://www.example.com/index.php'] 

    rules = (
     Rule(SgmlLinkExtractor(allow_domains=('example.com'),allow=('12\.html'),unique=True),callback='parsecatpage'), 
     ) 

    def parsecatpage(self, response): 
     hxs = HtmlXPathSelector(response) 
#this works, next line doesn't categories = hxs.select('//a[contains(@href, "filter=c:Grinders")]') 
     categories = hxs.select('//a[contains(@href, "filter=c:Grinders") or contains(@href, "filter=c:Lathes")]') 
     for cat in categories: 
      item = MachineItem() 
      req = Request(urlparse.urljoin(response.url,''.join(cat.select("@href").extract()).strip()),callback=self.parsetypepage) 
      req.meta['item'] = item 
      req.meta['machinecategory'] = ''.join(cat.select("./text()").extract()) 
      yield req 

    def parsetypepage(self, response): 
     hxs = HtmlXPathSelector(response) 
#this works, next line doesn't types = hxs.select('//a[contains(@href, "filter=t:Disc+-+Horizontal%2C+Single+End")]') 
     types = hxs.select('//a[contains(@href, "filter=t:Disc+-+Horizontal%2C+Single+End") or contains(@href, "filter=t:Lathe%2C+Production")]') 
     for typ in types: 
      item = response.meta['item'] 
      req = Request(urlparse.urljoin(response.url,''.join(typ.select("@href").extract()).strip()),callback=self.parsemachinelist) 
      req.meta['item'] = item 
      req.meta['machinecategory'] = ': '.join([response.meta['machinecategory'],''.join(typ.select("./text()").extract())]) 
      yield req 

    def parsemachinelist(self, response): 
     hxs = HtmlXPathSelector(response) 
     for row in hxs.select('//tr[contains(td/a/@href, "action=searchdet")]'): 
      item = response.meta['item'] 
      req = Request(urlparse.urljoin(response.url,''.join(row.select('./td/a[contains(@href,"action=searchdet")]/@href').extract()).strip()),callback=self.parsemachine) 
      print urlparse.urljoin(response.url,''.join(row.select('./td/a[contains(@href,"action=searchdet")]/@href').extract()).strip()) 
      req.meta['item'] = item 
      req.meta['descr'] = row.select('./td/div/text()').extract() 
      req.meta['machinecategory'] = response.meta['machinecategory'] 
      yield req 

    def parsemachine(self, response): 
     hxs = HtmlXPathSelector(response) 
     item = response.meta['item'] 
     item['machinecategory'] = response.meta['machinecategory'] 
     item['comp_name'] = 'Name' 
     item['description'] = response.meta['descr'] 
     item['makemodel'] = ' '.join([''.join(hxs.select('//table/tr[contains(td/strong/text(), "Make")]/td/text()').extract()),''.join(hxs.select('//table/tr[contains(td/strong/text(), "Model")]/td/text()').extract())]) 
     item['capacity'] = hxs.select('//tr[contains(td/strong/text(), "Capacity")]/td/text()').extract() 
     relative_image_url = hxs.select('//img[contains(@src, "custom/modules/images")]/@src')[0].extract() 
     abs_image_url = urlparse.urljoin(response.url, relative_image_url.strip()) 
     item['image_urls'] = [abs_image_url] 
     yield item 

SPIDER = MachineSpider() 

因此,例如,蜘蛛會發現類別頁面上磨牀,並轉到磨牀類型的頁面,它會找到光盤水平Single End類型,然後它將進入該頁面並找到機器列表並轉到每個機器頁面,最後每個機器都會有一個項目。如果您嘗試去磨牀和車牀,雖然它將通過磨牀磨合,但它會抓取車牀和車牀類型頁面,並在那裏停止,而不會產生對車牀列表頁面和最終車牀頁面的請求。

任何人都可以幫忙嗎?爲什麼一旦有多於一種類型的機器,蜘蛛就不會進入第二個(或第三個)機器列表頁面?

對不起,史詩般的文章,只是試圖解釋問題!

謝謝!

+0

如果您在本網站上發現任何有用的答案/問題,請立即投訴 – warvariuc 2012-03-16 12:03:56

回答

2

您應該打印請求的網址,以確保無誤。你也可以嘗試這個版本:

def parsecatpage(self, response): 
    hxs = HtmlXPathSelector(response) 
    categories = hxs.select('//a[contains(@href, "filter=c:Grinders") or contains(@href, "filter=c:Lathes")]') 
    for cat in categories: 
     item = MachineItem() 
     cat_url = urlparse.urljoin(response.url, cat.select("./@href").extract()[0]) 
     print 'url:', cat_url # to see what's there 
     cat_name = cat.select("./text()").extract()[0] 
     req = Request(cat_url, callback=self.parsetypepage, meta={'item': item, 'machinecategory': cat_name}) 
     yield req 
+0

感謝您的回覆,並請求使用meta!我已經在所有回調中放置了打印語句以查看會發生什麼。我可以看到磨牀頁面和解析頁面中的車牀頁面的網址,然後他們被抓取,然後我可以在parsetypepage中看到磨牀類型和車牀類型的網址,然後他們被抓取。之後,在parsemachinelist中,我查看了在「車牀」列表頁面上列出的機器的網址,這些機器被抓取並被抓取,但來自Grinders列表頁面的網址不會被打印,抓取或抓取。爲什麼不? – ahc 2012-03-15 12:33:57

+0

如果未打印,則不提取任何url或未調用回調。在回調開始處放置一個打印文件,並在循環之前執行'print hxs.select('// a [...]/@ href')。extract()' – warvariuc 2012-03-15 12:39:13

+0

我還檢查了scrapy shell和url在xpath有效的Grinders列表頁面中,它確實會在shell中返回正確的url,但不會在spider中運行時返回正確的url。我認爲這與請求的順序有關,有時它返回Grinder機器的項目,但不會執行Lathes,所以它看起來像在它已經到達第一個機器列表的末尾而沒有去完成回其他人。 – ahc 2012-03-15 12:49:10

0

的問題是,該網站被設置成從類別移動到頁面類型(和下頁)通過過濾所顯示的結果發生。這意味着如果請求是先執行到查詢底部的深度,那麼它就起作用(即選擇一個類別,然後獲取該類別的所有類型,然後獲取每種類型的所有機器,然後刮取每臺機器的頁面)但如果在蜘蛛獲得第一種類型的每臺機器的url之前處理了下一個類型頁面的請求,那麼這些url不再正確,並且蜘蛛達到不正確的頁面,並且無法提取下一步的信息。

爲了解決這個問題,我定義了一個叫做第一次的類別設置回調,並且獲得了一個名爲categories的所有類別的列表,然後是一個從類別設置中調用的類別回調,它只用一個類別開始抓取使用categories.pop()。一旦蜘蛛到達嵌套回調的底部並且抓取列表中的所有機器,就會有一個回調再次回到類別回調(Request中需要dont_follow=True),其中categories.pop()再次用直到他們全部完成。通過這種方式,每個類別在下一個開始之前都會被完全處理,並且它可以工作

感謝您的最終評論,這讓我思考着正確的思路,並將我引向解決方案!