2012-03-14 14 views
4

カテゴリページ>タイプページ>リストページ>アイテムページのような構造を持つサイトをクロールするために、scrapy crawlspiderを作成しました。カテゴリページには、それぞれにタイプの多いタイプページがあり、それぞれのタイプにはアイテムのリストがあり、最後に各マシンには情報に関するページがあります。Scrapy:ネストされたコールバック内のすべてのリンクを生成しないクロールスプレッド

私のスパイダーは、ホームページからコールバックparsecatpageを定義するカテゴリページに到達するルールを持っています。これはアイテムを生成し、カテゴリを取得してページの各カテゴリに対して新しいリクエストを生成します。私はitem.metaで項目とカテゴリ名を渡し、コールバックはparsetypeページを指定します。

Parsetypepageはresponse.metaからアイテムを取得し、各タイプのリクエストを生成し、item.metaにアイテムとカテゴリおよびタイプの連結を渡します。コールバックはparsemachinelistです。

Parsemachinelistはresponse.metaからアイテムを取得し、リスト上の各アイテムの要求を生成し、item.category.metaを介してitem、category/type、descriptionを最終コールバックparsemachineに渡します。これにより、メタ属性が取得され、ページ内の情報と前のページから渡された情報が使用され、アイテム内のすべてのフィールドに入力され、最後にアイテムが生成されます。

これを1つのカテゴリとタイプ(たとえばcontains[@href, "filter=c:Grinders"]contains[@href, "filter=t:Disc+-+Horizontal%2C+Single+End"]など)に限定すると、それは機能し、最終ページに各マシンのマシン項目があります。問題は、スパイダーがすべてのカテゴリとすべてのタイプを掃除できるようにすると、最終ページの最初のページにあるマシン用の救急措置アイテムだけが返され、スパイダーが終了していないと完了したここで

が、それはディスクが水平わかります(匿名)コード

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() 

したがって、たとえばクモは、カテゴリページのグラインダを見つけるとグラインダー型のページに移動している他のカテゴリなどを取得シングルエンドタイプであれば、そのページに行き、マシンのリストを見つけて各マシンページに行き、最後に各マシンのためのアイテムがあります。グラインダと旋盤を試してみると、それはグラインダをうまく通り抜けますが、旋盤と旋盤のタイプのページがクロールされ、旋盤リストページと最終旋盤ページのリクエストが生成されません。

誰でも助けてもらえますか?複数のカテゴリのマシンがあると、スパイダーが2番目(または3番目など)のマシンリストページに移動しないのはなぜですか?

叙事詩のポストに申し訳ありません、問題を説明しようとしています!

ありがとうございます!

+0

このサイトで有用な回答/質問が見つかった場合は、それらをupvoteしてください – warvariuc

答えて

2

リクエストのURLを印刷して、問題ないことを確認してください。また、あなたは、このバージョン試すことができます。問題は、カテゴリから移動するページ(および以下のページ)を入力するようにウェブサイトが設定されていることだった

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

ご返信いただきありがとうございました。私は何が起こるかを見るためにすべてのコールバックにprintステートメントを入れました。グラインダーページと旋盤ページのurlがparsecatpageで表示され、クロールされていれば、グラインダータイプのURLとparsetypepageのタイプのLatheが表示され、クロールされます。その後、私は旋盤のリストページに記載されているマシンのURLを参照していますが、クロールおよび掻き出しはされていますが、グラインダーのリストページのURLは印刷されず、クロールされたり、削られたりしません。何故なの? – ahc

+0

が印刷されない場合は、URLが抽出されないか、コールバックが呼び出されません。コールバックの先頭にprintを置き、 'print hxs.select( '// a [...]/@ href')。ループの前にextract()'を実行します – warvariuc

+0

私はまたscrap shellとurlでチェックしましたグラインダーリストページのxpathが有効であれば、それはシェル内の正しいURLを返しますが、スパイダーで実行されているときは返しません。私はそれが要求の順序と関係していると思っています。時にはGrinderマシンのアイテムを返しますが、旋盤を実行しないので、マシンの最初のリストの終わりに終わってしまったようです他の人のために戻ってください。 – ahc

0

を示している結果をフィルタを介して起こります。これは、要求がクエリの最初から最後まで深く実行された場合、それは機能します(つまり、カテゴリを選択し、そのカテゴリのすべてのタイプを取得し、次に各タイプのすべてのマシンを取得してから各マシンのページをスクラップする)スパイダーが最初のタイプの各マシンのURLを取得する前に次のタイプのページのリクエストが処理されると、URLは正しくなくなり、スパイダーは間違ったページに達し、次のステップの情報を抽出できなくなります。

問題を解決するために、最初に呼び出されるカテゴリ設定コールバックを定義し、categoriesというすべてのカテゴリのリストを取得した後、単一のカテゴリのみでクロールを開始するカテゴリ設定から呼び出されるカテゴリコールバックcategories.pop()を使用してください。スパイダーがネストされたコールバックの一番下に来て、リスト内のすべてのマシンを掻き取ったら、カテゴリコールバックに戻るコールバックが返されます(Requestにはdont_follow=Trueが必要です)。categories.pop()は、それらがすべて完了するまでリストアップしてください。このように、各カテゴリは、次のカテゴリが開始される前に完全に扱われ、機能します。

最終的なコメントをいただきありがとうございます、私は正しい線に沿って考えてくれました。

関連する問題