Grabの使用:Webサイトの解析のためのSpider

みなさんこんにちは!



私は、オープンソースフレームワークGrabitforgeがすでにここここでそれについて書いています )とGrabLabプロジェクトの半分 (フレームワーク自体の商業運用に従事している )のアクティブユーザーです。 なぜなら 多くの場合、サイトを解析しますが、ルールとタスクは互いに完全に異なるため、典型的なプロジェクト解析の構築における経験を共有したいと思います。



私の仕事に役立つツールについて少し


稼働中のブラウザーとして、FireFoxとHttpFoxプラグイン(着信/発信HTTPトラフィックの分析)、 XPather (xpath式のチェックを許可)、 SQLite Manager (sqliteテーブルの表示)、emacsコードを入力します。よく使用するスニペット(YASnippets)構造。



フレームワークの仕様により、原則として、最初の段階では、サイトは完全に(または、その後の開発の便宜のために部分的に大量のデータがある場合)、mongodbに基づいてローカルキャッシュに保存されます。 ページの読み取りはキャッシュから取得されます。





原則として(json / xmlではあまりありません)SQLデータベースを使用するには、ORM-SQLAlchemyを使用してデータを分解する必要があります。



実際、Grabフレームワーク自体は、プロジェクトの構築とそのアクションの制御に大きな柔軟性を提供します。 ただし、最後のいくつかのプロジェクトは次の構造に適切に配置されており、Web開発に従事している人々にはよく知られています。



1)models.py-データモデルについて説明します

2)config.py-dzhanga、設定、orm初期化の世界のsettings.pyの類似物。

3)/spiders/*.py-スパイダーのコード

4)spider.pyまたはproject_name.py-メインプロジェクトファイルは通常、さまざまなスパイダーを起動するためのコマンドラインインターフェイスを組み合わせて実装します。 多くの場合、サイトは部分的に解析されます。



実生活とあまり離婚していない例として、オープンソースのGitHubの要塞からパーサー「Trending projects」と「Most Popular Python projects」を作成します。



例の完全なコードは、 ここにあります



最初に、 モデルを説明する必要があります。



class Item(Base): __tablename__ = 'item' sqlite_autoincrement = True id = Column(Integer, primary_key=True) title = Column(String(160)) author = Column(String(160)) description = Column(String(255)) url = Column(String(160)) last_update = Column(DateTime, default=datetime.datetime.now)
      
      







次に、config.pyファイルで、初期orm初期化が実行され、テーブル、定数が作成され、設定(default_spider_params)に応じてスパイダーを起動するためのパラメーターを構築する関数が見つかります。これは通常、プロジェクト内のすべてのスパイダーに共通です。



 def init_engine(): db_engine = create_engine( 'sqlite+pysqlite:///data.sqlite', encoding='utf-8') Base.metadata.create_all(db_engine) return db_engine db_engine = init_engine() Session = sessionmaker(bind=db_engine) def default_spider_params(): params = { 'thread_number': MAX_THREADS, 'network_try_limit': 20, 'task_try_limit': 20, } if USE_CACHE: params.update({ 'thread_number': 3, 'use_cache': True, 'cache_db': CACHE_DB, 'debug_error' :True, }) return params
      
      







ほとんどの場合、サーバーでmongodbを使用する必要はないため、キャッシュを無効にすると便利です。 プロジェクトをデプロイするとき、USE_CACHE = Falseに設定するだけで、すべて正常に機能します。 SAVE_TO_DBは、データベースへのデータの書き込みを有効/無効にするために使用されます。



実際、最も興味深い部分に目を向けます。2aのクモがあり、1つ目は「Top Trending」プロジェクトの5つのリポジトリを解析し、2つ目は「Most watched Python」を解析します。



これらのスパイダーには共通の部分があり、それらを個別の基本クラスに取り出して継承する必要があることは明らかです。これにより、コードが削減され、サポートが簡素化され、プログラムが読みやすくなります。 多かれ少なかれ複雑なプロジェクトで、互いにわずかに異なる多数のページがある場合、機能の一部をスーパークラスに転送する必要が絶えず発生します。



OOPを無視せず、2aのsave()およびlog_progress()メソッドを定義するBaseHubSpiderを記述しません。



 class BaseHubSpider(Spider): initial_urls = ['http://github.com'] items_total = 0 def save(self, data): if not SAVE_TO_DB: return session = Session() if not session.query(Item).filter_by(title=data['title']).first(): obj = Item(**data) session.add(obj) session.commit() def log_progress(self, str): self.items_total += 1 print "(%d) Item scraped: %s" % (self.items_total, str)
      
      







実際のアプリケーションでは、いくつかのパラメーターに依存するページ解析機能が存在する可能性が非常に高くなります-各ページで異なるフィールドの名前と、それらへのxpathパスはほぼ同じなどです。



たとえば、次のようなものです(これは実際の例ではなく、理解を深めるための単なる例です)。



  XPATH = u'//table[@class="standart-table table"]' + \ u'//tr[th[text() = "%s"]]/td' values = ( ('title', u' '), ('rating', u''), ('categories', u' '), ('description', u''), ) for db_field, field_title in values: try: data[db_field] = get_node_text(grab.xpath( XPATH % field_title, None)).strip() except AttributeError: data[db_field] = ''
      
      







https://github.com/istinspring/grab-default-project-example/blob/master/spiders/lang_python.py



最も人気のある20のPythonプロジェクトを解析してデータベースに保存するスパイダーコード。



注意してください


  repos = grab.xpath_list( '//table[@class="repo"]//tr/td[@class="title"]/..') for repo in repos: data = { 'author': repo.xpath('./td[@class="owner"]/a/text()')[0], 'title': repo.xpath('./td[@class="title"]/a/text()')[0],}
      
      





repos = grab.xpath_list( '')-lxmlオブジェクトのリストを返します。たとえば、grab.xpath( '')は最初の要素を返します。 この場合のxpathはグラブオブジェクトメソッドです。 repo.xpath( './ h3 / a [1] / text()')ループで動作し、lxmlがxpathを見つけられなかった場合、リストまたは例外を取得します。 簡単に言えば、グラブオブジェクトからのxpathとlxmlオブジェクトからのxpathは異なるものです。最初の場合は最初の要素が返され(デフォルトまたは例外をスロー)、2番目の場合は要素のリスト['something']が返されます。



^^読むことは理解できませんが、実際にこれに遭遇したらすぐに、この段落を覚えておいてください。



情報がお役に立てば幸いです。 同志のitforgeはオープンソースのGrab製品の開発に精力的に取り組んでいます。grabのドキュメントはロシア語で入手可能ですが、grab:spiderについては残念ながら導入部分のみが入手可能です



フレームワークに関する質問については、 grablab @ conference.jabber.ruでjabber会議があります。



All Articles