web-dev-qa-db-ja.com

500万のWebページをスクレイピングする最も効率的な(時間、コスト)方法は?

結果のデータをスクレイピングして解析し、データベースに保存する必要があるWebページのリストがあります。合計は約5,000,000です。

これにアプローチする最良の方法の私の現在の想定は、最大100のEC2インスタンスをデプロイし、各インスタンスに50,000ページを提供してスクレイピングし、それを実行したままにし、プロセスが完了したらデータベースをマージすることです。実行には約1日かかります(各ページの読み込み、解析、保存に600ミリ秒)。

限られた時間内に大量のページスクレイピングを行った経験がある人はいますか?私は以前(1.5m)に多数を行ったことがありますが、それは単一のマシンからのものであり、完了するまでに1週間ほどかかりました。

私の状況のボトルネックはページのダウンロードであり、解析は2ミリ秒もかからないので、ページのダウンロードプロセスを合理化できるものが私が探しているものです。

8
sam

ダウンロード時間(したがって帯域幅の使用量)が制限要因であるという仮定に基づいて、次のことを提案します。

まず、m1.largeインスタンスを選択します。 I/Oパフォーマンス(帯域幅を含む)の3つの「レベル」のうち、m1.largeおよびm1.xlargeインスタンスはどちらも「高い」I/Oパフォーマンスを提供します。タスクはCPUバウンドではないため、これらの中で最も安価なものをお勧めします。

次に、インスタンスは、どのサイトでもページを提供できるよりもはるかに速くダウンロードできます-特定のインスタンスで一度に1つのページをダウンロードせずに、タスクを同時に実行します-少なくとも20ページを同時に実行できるはずです(ただし、 、おそらく50〜100は問題なく実行できると思います)。 (コメントからのフォーラムからのダウンロードの例を見てみましょう-これは、サーバーの生成に時間がかかる動的ページであり、そのサイトの帯域幅を使用している他のユーザーなどがあります)。インスタンスの帯域幅の制限に達するまで、並行性を増やし続けます。 (もちろん、同じサイトに対して複数の同時リクエストを行わないでください)。

パフォーマンスを最大化しようとしている場合は、地理的に適切なゾーンでインスタンスを起動してレイテンシを最小限に抑えることを検討してください(ただし、すべてのURLを地理的に特定する必要があるため、実用的ではない場合があります)。

注意すべき点の1つは、インスタンスの帯域幅が可変であることであり、場合によってはより高いパフォーマンスが得られ、他の場合にはより低いパフォーマンスが得られます。小さいインスタンスでは、物理リンクがより多くのサーバーで共有され、それらのいずれかが使用可能な帯域幅を減少させる可能性があるため、パフォーマンスの変動はより大きくなります。 EC2ネットワーク(同じアベイラビリティーゾーン)内のm1.largeインスタンス間では、理論上のギガビットスループットに近いはずです。

一般に、AWSでは、複数の小さなインスタンスではなく、大きなインスタンスを使用する方が効率的です(フェイルオーバーなど、複数のインスタンスが必要な場合を除いて)。

私はあなたの設定が何を必要とするのかわかりませんが、以前にこれを試みたとき(100万から200万のリンク、定期的に更新)、私のアプローチは、リンクが見つかったときに新しいリンクを追加し、プロセスを分岐するリンクのデータベースを維持することでしたページをこすって、解析します。 URLが(ランダムに)取得され、データベースで進行中としてマークされます。スクリプトはページをダウンロードし、成功した場合、URLをデータベースにダウンロード済みとしてマークし、ページを解析した別のスクリプトにコンテンツを送信します。新しいリンク見つかったときにデータベースに追加されました。ここでのデータベースの利点は一元化でした。複数のスクリプトがデータベースに同時にクエリを実行でき、(トランザクションがアトミックである限り)各ページが一度だけダウンロードされることが保証されます。

いくつかの追加の指摘-一度に実行できるオンデマンドインスタンスの数には制限があります(20と思います)-これらの制限を超える予定がある場合は、AWSにアカウントの増加をリクエストする必要があります制限。スポットインスタンスを実行し、スポット価格が低いときに数値をスケールアップすることは、はるかに経済的です(おそらく、すべてを整理しておくための1つのオンデマンドインスタンスと、残りのスポットインスタンス)。

時間の方がコストよりも優先度が高い場合、クラスターコンピューティングインスタンスは10 Gbpsの帯域幅を提供し、ダウンロード帯域幅が最大になります。

まとめ:(多くの小さなインスタンスの代わりに)いくつかの大きなインスタンスを試して、各インスタンスで複数の同時ダウンロードを実行します-帯域幅が制限されている場合はインスタンスを追加し、CPU /メモリが制限されている場合は大きなインスタンスに移動します。

7
cyberx86

私たちは同じようなことをしようとしました、そしてここに私の5セントがあります:

  1. 2〜3台の安価な非従量制サーバーを取得します。帯域幅の代金を払わないでください。

  2. python with asyncoreを使用します。Asyncoreは古い方法ですが、他のどの方法よりも高速に動作します。欠点は、DNSルックアップがブロックされている、つまり「並列」ではないことです。asyncoreの使用単一のXEON 4コア、8 GB RAMを使用して、1MのURLを40分間スクレイピングできました。サーバーの平均負荷は4未満でした(4コアの場合は優れています)。

  3. Asyncoreが気に入らない場合は、geventを試してください。 DNSノンブロッキングも行います。 geventを使用して、1Mは同じハードウェアで約50分間ダウンロードされました。サーバーの平均負荷は非常に大きかった。

多くのPythonライブラリ、grequests、curl、liburl/liburl2などのライブラリをテストしましたが、Twistedはテストしませんでしたです。

  1. 私たちはテストを行いましたPHP + curl +複数のプロセス、それは約1時間仕事をしましたが、サーバーの平均負荷は巨大でした。
4
Nick