Grab:Spiderとは何ですか?

Grabのドキュメントを書き終えることができません。Spiderは非同期スパイダーを作成するためのGrabライブラリの一部です。 オタクの雑誌にドキュメントの一部をレイアウトすることを考えた フィードバックがあれば、物事は速くなると思います。 現時点では、ドキュメントには、Grab:Spiderがどのような獣であるかを概説した紹介文しかありません。 広げました。



Spiderモジュールは、サイトパーサーを一連のハンドラー関数として記述することを可能にするフレームワークです。各ハンドラーは特定のタイプのリクエストを処理します。 たとえば、フォーラムを解析する場合、メインページ、サブフォーラムページ、トピックページ、メンバープロファイルページのハンドラーがあります。 当初、このようなパーサー構造は非同期モードの制限のために開発されましたが、後にそのような構造化された形式(1つの要求-1つの関数)でパーサーを書くことが非常に便利であることがわかりました。



Spiderモジュールは非同期で実行されます。 つまり、プログラムワークフローは常に1つだけです。 複数のリクエストの場合、スレッドもプロセスも作成されません。 作成されたすべてのリクエストは、マルチカールライブラリによって処理されます。 非同期アプローチの本質は、プログラムがネットワーク要求を作成し、これらの要求への応答の準備ができたというシグナルを待機することです。 回答の準備が整うと、ハンドラー関数が呼び出され、特定の要求にバインドされます。 非同期アプローチを使用すると、スレッドまたはプロセスの作成に関連するアプローチよりも多くの同時接続を処理できます。 メモリは1つのプロセスのみによって占有され、プロセッサは多くのプロセスを絶えず切り替える必要がありません。



同期スタイルでの作業に慣れている人にとっては非常に珍しいニュアンスが1つあります。 非同期アプローチにより、ネットワーク応答の準備ができたときに関数ハンドラーを呼び出すことができます。 解析アルゴリズムが複数の連続したネットワーク要求で構成されている場合、ネットワーク要求を作成した理由とその処理に関する情報を格納する場所が必要です。 Spiderでは、この問題を簡単に解決できます。



各ハンドラー関数は、2つの入力引数を受け取ります。 最初の引数はGrabオブジェクトで、ネットワーク応答に関する情報を保存します。 Spiderモジュールの魅力は、同期リクエストを処理するための使い慣れたインターフェイスを保持していることです。 ハンドラー関数の2番目の引数はTaskオブジェクトです。 ネットワーク要求キューに新しいタスクを追加するために、Spideerでタスクオブジェクトが作成されます。 Taskオブジェクトを使用すると、複数のクエリ間の中間データを保存できます。



簡単なパーサーの例を考えてみましょう。 habrahabr.ruにアクセスし、最新ニュースのヘッドラインを読み、各見出しにimages.yandex.ruを使用して画像を検索し、データをファイルに保存するとします。



# coding: utf-8 import urllib import csv import logging from grab.spider import Spider, Task class ExampleSpider(Spider): #  ,   Spider   #         #    initial initial_urls = ['http://habrahabr.ru/'] def prepare(self): #      #  prepare      #   self.result_file = csv.writer(open('result.txt', 'w')) #       #  ,      . self.result_counter = 0 def task_initial(self, grab, task): print 'Habrahabr home page' #        initial # ..   ,     #    self.initial_urls #         #     Grab for elem in grab.xpath_list('//h1[@class="title"]/a[@class="post_title"]'): #   -    #   habrapost #  ,       #  yield -      # -    : # self.add_task(Task('habrapost', url=...)) yield Task('habrapost', url=elem.get('href')) def task_habrapost(self, grab, task): print 'Habrahabr topic: %s' % task.url #  ,     #    ,  #     ,   #    #          post = { 'url': task.url, 'title': grab.xpath_text('//h1/span[@class="post_title"]'), } #       ,  , #     Task   .   #        ,    #      .   ,   #    Task     #         query = urllib.quote_plus(post['title'].encode('utf-8')) search_url = 'http://images.yandex.ru/yandsearch?text=%s&rpt=image' % query yield Task('image_search', url=search_url, post=post) def task_image_search(self, grab, task): print 'Images search result for %s' % task.post['title'] #         ,  #     !     , #           # .      ,   #   ,     `task.post`. image_url = grab.xpath_text('//div[@class="b-image"]/a/img/@src') yield Task('image', url=image_url, post=task.post) def task_image(self, grab, task): print 'Image downloaded for %s' % task.post['title'] #      . #  ,   . path = 'images/%s.jpg' % self.result_counter grab.response.save(path) self.result_file.writerow([ task.post['url'].encode('utf-8'), task.post['title'].encode('utf-8'), path ]) #     ,  #       self.result_counter += 1 if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG) #      -   #  ,     #        ,      bot = ExampleSpider(thread_number=2) bot.run()
      
      







この例では、最も単純なパーサーが考慮され、Spiderが実行できる多くの機能は影響を受けません。 詳細なドキュメントでそれらについて読んでください。 たとえば、Yandexは指定されたリクエストでは何も検出しないため、ハンドラーの一部の機能が失敗することに注意してください。



さらに、さまざまな方法でTaskオブジェクトを作成し、ネットワークエラーを処理し、誤って停止したタスクを繰り返し実行する機能について説明する予定です。



執筆では、Grabに関する質問はメーリングリストでよく聞かれます: groups.google.com/group/python-grab



Grabの改訂版と、GrabとGrab :: Spiderに基づくパーサーを注文できます。こちら: grablab.org



All Articles