このクローラーは主にBaidu Tiebaのさまざまな投稿の内容をクロールし、投稿の内容を分析して携帯電話番号とメールアドレスを抽出します。主なフローはコードのコメントで詳しく説明されています。
テスト環境:
コードは Windows7 64 ビット、Python 2.7 64 ビット (mysqldb 拡張機能がインストールされている) および centos 6.5、Python 2.7 (mysqldb 拡張機能がインストールされている) 環境でテストされました。
働いています願望 スクリーンショットからわかるように、私の環境は Windows 7 + PyCharm です。 Python環境はPython 2.7 64bitです。初心者向けの開発環境です。次に、easy_install をインストールすることをお勧めします。名前からわかるように、これは一部の拡張パッケージをインストールするために使用されます。たとえば、Python で mysql データベースを操作したい場合、Python はそれをネイティブにサポートしません。 Python が mysql データベースを操作できるようにするには、mysqldb パッケージをインストールする必要があります。 easy_install がある場合、mysqldb 拡張パッケージをすばやくインストールするのに必要なのは、php の Composer や centos の yum と同じくらい便利です。 Ubuntu の apt-get 。
関連するツールは github: cw1997/python-tools にあります。 easy_install をインストールするには、Python コマンド ラインで py スクリプトを実行するだけで、Windows 環境変数が自動的に追加されます。 Windows コマンド 行の最後に easy_install と入力し、エコーがあれば、インストールが成功したことを意味します。環境選択の詳細:
コンピューターハードウェアに関しては、もちろん速いほど良いため、少なくとも8Gのメモリから始めてください。これは、クローラー自体、特にマルチスレッドクローラーの場合、大量の中間データを保存および解析する必要があるためです。 , ページングを使用してクロールする場合 リストと詳細ページ、およびキャプチャされたデータの量が多い場合、キューを使用してクロール タスクを割り当てると、多くのメモリが占有されます。キャプチャしたデータが json を使用している場合もあり、それが mongodb などの nosql データベースに保存されている場合、大量のメモリも消費します。
一部の劣悪な無線ルーターや市販の一般的な民間無線ネットワークカードでは、スレッドが比較的大きく開かれると断続的なネットワーク切断、データ損失、パケットドロップなどが発生するため、ネットワーク接続には有線ネットワークを使用することをお勧めします。
オペレーティングシステムとPythonについては、もちろん64ビットを選択してください。 32 ビット オペレーティング システムを使用している場合は、大きなメモリを使用できません。 32 ビット Python を使用している場合、小規模なデータをキャプチャする場合は問題がないかもしれませんが、大量のデータを格納するリスト、キュー、ディクショナリなど、データ量が大きくなると、原因 Python のメモリ使用量が 2g を超えると、メモリ オーバーフロー エラーが報告されます。
データの保存に mysql を使用する予定がある場合は、mysql5.5 以降のバージョンを使用することをお勧めします。mysql5.5 バージョンでは json データ型がサポートされているため、mongodb を放棄することができます。
Python に関しては、バージョン 3.x が利用可能になりましたが、なぜここではまだ Python2.7 が使用されているのでしょうか?バージョン 2.7 を選択した理由は、昔購入した Python コア プログラミングの本が第 2 版であり、サンプル バージョンとしてまだ 2.7 を使用しているためです。また、バージョン 2.7 はいくつかの点で 3.x とは大きく異なるため、インターネット上には依然として 2.7 を使用するチュートリアル資料が多数あります。2.7 を学習していないと、その原因となるいくつかの微妙な構文の違いが理解できない可能性があります。私たちの理解にズレがあるか、デモコードを理解できません。また、バージョン 2.7 とのみ互換性のある依存パッケージがまだいくつかあります。私の提案は、あなたが Python を学び、その後会社で働きたいと思っていて、その会社に保守する古いコードがない場合、十分な時間があり、Python を持っていない場合は、3.x を直接開始することを検討してもよいということです。非常に体系的な専門家です。インターネット上に散在するブログ記事を頼りに学習できる場合は、まず 2.7 を学習してから 3.x を学習する必要があります。結局のところ、2.7 を学習すればすぐに 3.x を始めることができます。
マルチスレッド クローラーに関連するナレッジ ポイント:
実際、どのソフトウェア プロジェクトでも、このプロジェクトを作成するためにどのようなナレッジ ポイントが必要かを知りたければ、どのパッケージがこのプロジェクトのメイン エントリ ファイルにインポートされるかを観察できます。プロジェクト。
それでは、Python を初めて使用する人にとって、ほとんど使用されたことのないパッケージがいくつかあるかもしれないので、このセクションでは、それらのパッケージの機能について簡単に説明します。 、そこにはどのような知識ポイントがあるのか、そしてこれらの知識ポイントのキーワードは何かが関係します。この記事では基本から始めるのにそれほど時間はかかりません。そのため、Baidu を上手に活用し、これらの知識ポイントのキーワードを検索して自分自身を教育する必要があります。これらの知識ポイントを 1 つずつ分析してみましょう。
HTTP プロトコル:
基本的に、クローラーは継続的に http リクエストを開始し、http レスポンスを取得し、それらをコンピューターに保存することによってデータをキャプチャします。 http プロトコルを理解すると、キープアライブなど、データをクロールするときにクロールを高速化できるいくつかのパラメーターを正確に制御するのに役立ちます。
スレッドモジュール (マルチスレッド):
私たちが通常書くプログラムは、すべてメインスレッドで実行され、このメインスレッドは Python プロセスで実行されます。
マルチスレッドは、スレッドと呼ばれるモジュールを通じて Python に実装されます。以前はスレッド モジュールもありましたが、スレッドの制御がより強力になったため、後にスレッドに切り替えてマルチスレッド プログラミングを実装しました。
簡単に言うと、スレッド モジュールを使用してマルチスレッド プログラムを作成するには、まず自分でクラスを定義し、次にこのクラスが threading.Thread を継承し、各スレッドによって実行される作業コードを run に記述する必要があります。もちろん、スレッドの作成時にスレッド自体が初期化作業を行う必要がある場合は、その初期化作業のために実行されるコードをその __init__ メソッドに記述する必要があります。このメソッドは、PHP のコンストラクター メソッドとまったく同じです。そしてジャワ。
ここでさらに説明すべき点は、スレッド セーフの概念です。通常、シングルスレッドの状況では、各瞬間にリソース (ファイル、変数) を操作しているスレッドは 1 つだけであるため、競合が発生する可能性はほとんどありません。ただし、マルチスレッドの場合、2 つのスレッドが同時に同じリソースを操作し、リソースにダメージを与える可能性があるため、この競合によって引き起こされるダメージを解決するメカニズムが必要であり、これには通常、ロックやその他の操作が含まれます。たとえば、mysql データベースの innodb テーブル エンジンには行レベルのロックなどがあり、ファイル操作には読み取りロックなどがあります。これらはすべて、プログラムの最下位層によって完了します。したがって、通常は、それらの操作、またはスレッド セーフティの問題に対処するプログラムを知るだけで、マルチスレッド プログラミングでそれらを使用できるようになります。このようにスレッドセーフ性を考慮したプログラムを一般に「スレッドセーフ版」と呼びますが、例えばPHPにはTS版があり、このTSとはスレッドセーフのことです。以下で説明する Queue モジュールはスレッドセーフなキュー データ構造であるため、マルチスレッド プログラミングで安心して使用できます。
最後に、スレッドのブロックという重要な概念について説明します。スレッド モジュールを詳細に学習した後は、おそらくスレッドを作成して開始する方法がわかるでしょう。しかし、スレッドを作成してから start メソッドを呼び出すと、プログラム全体がすぐに終了することがわかります。何が起こっているのでしょうか?実際、これはメインスレッド内にサブスレッドを起動するコードしかないためです。つまり、サブスレッドによって実行されるコードに関しては、メインスレッドにはサブスレッドを起動する機能しかありません。それらは本質的にはクラスに書かれた単なるメソッドであり、実際にはメインスレッドで実行されるわけではないため、メインスレッドがサブスレッドを開始すると、すべての作業が完了し、正常に終了します。メインスレッドが終了すると、Python プロセスは終了し、他のスレッドには実行を継続するためのメモリ領域がなくなります。したがって、すべてのサブスレッド兄弟が実行を完了するまでメインスレッド兄弟を待たせてから、メインスレッドを妨害するメソッドはスレッドオブジェクトにあるのでしょうか。スレッド.スリープ?これは確かに解決策ですが、メインスレッドはどのくらいの時間スリープする必要があるのでしょうか?タスクを完了するのにどれくらい時間がかかるか正確に分からないため、この方法は絶対に使用できません。したがって、現時点では、サブスレッドをメインスレッドに「スタック」させる方法があるかどうかをオンラインで確認する必要がありますか? 「スタック」という言葉は下品すぎるように思えますが、より専門的に言うと「ブロッキング」と呼ぶべきなので、検索エンジンを正しく使用すれば、「Python サブスレッドがメインスレッドをブロックする」というクエリを実行できるはずです。はい、この join() メソッドは、サブスレッドが実行を完了していないときにメインスレッドをブロックするために使用されるメソッドです。 join() メソッドを含む行に到達すると、すべてのスレッドの実行が終了するまで、join() メソッドに続くコードは実行されません。
キュー モジュール (キュー):
ある人のブログをクロールする必要があるシナリオがあるとします。この人のブログには 2 つのページがあり、list.php ページにはこのブログのすべての記事が表示されます。もう 1 つは、記事の特定のコンテンツを表示する view.php ページです。
この人のブログ内のすべての記事コンテンツをクロールしたい場合、シングルスレッド クローラーを作成するという考えは次のとおりです。まず、正規表現を使用して、このリスト内のすべてのリンクの a タグの href 属性をクロールします。 php ページを保存し、article_list という名前の配列 (Python では配列とは呼ばれず、リスト、中国語名のリストと呼ばれます) を使用して、article_list 配列を走査し、さまざまな関数を使用して Web ページのコンテンツをキャプチャします。コンテンツを作成し、データベースに保存します。
このタスクを完了するためにマルチスレッド クローラーを作成したい場合は、プログラムが 10 個のスレッドを使用すると仮定して、以前にクロールされたarticle_list を 10 個の等しい部分に分割し、各部分を 1 つに個別に分配する方法を見つける必要があります。子スレッドの。
しかし、ここで問題が発生します。article_list 配列の長さが 10 の倍数ではない場合、つまり、記事の数が 10 の整数倍ではない場合、最後のスレッドには他のスレッドよりも少ないタスクが割り当てられます。そうすればすぐに終わるでしょう。
この種のわずか数千語のブログ記事をクロールするだけであれば、これは問題ないようですが、タスクがある場合 (必ずしも Web ページをクロールするタスクではなく、数学的な計算やグラフィックのレンダリングである可能性があります) 、など、時間がかかります。タスクの実行時間は非常に長く、リソースと時間の多大な無駄が発生します。マルチスレッドの目的は、すべてのコンピューティング リソースと計算時間を可能な限り活用することです。そのため、より科学的かつ合理的にタスクを割り当てる方法を見つける必要があります。
そして、状況も考慮する必要があります。つまり、記事の数が多い場合、記事のコンテンツを素早くクロールし、クロールしたコンテンツをできるだけ早く確認できる必要があります。この要件は多くの場合に発生します。 CMS 収集ステーションに反映されることがよくあります。
たとえば、現在クロールしたいターゲットブログには数千万の記事があります。通常、この場合、ブログはページ分割されます。したがって、上記の従来の考え方に従って、少なくとも list.php のすべてのページをクロールするとします。所要時間はわずか数時間、場合によっては数日です。上司が、クロールされたコンテンツをできるだけ早く表示し、CMS 収集ステーションに表示できるようにすることを望んでいる場合は、list.php を同時にクロールする必要があります。そして、キャプチャしたデータをarticle_list配列に投入し、別のスレッドを使用してarticle_list配列からキャプチャした記事のURLアドレスを抽出し、このスレッドを使用して正規表現を使用して、対応するURLアドレスからブログを取得します。この機能を実装するにはどうすればよいでしょうか?
2 つのタイプのスレッドを同時に開く必要があります。1 つのタイプのスレッドは、具体的には list.php 内の URL を取得し、それをarticle_list 配列にスローする役割を担います。 Article_list から抽出し、対応する view.php ページから抽出して、対応するブログのコンテンツを取得します。
しかし、前に述べたスレッド セーフの概念をまだ覚えているでしょうか?前者のタイプのスレッドは、article_list 配列にデータを書き込み、もう 1 つのタイプのスレッドは、article_list からデータを読み取り、読み取ったデータを削除します。ただし、Python の list はスレッドセーフなバージョンのデータ構造ではないため、この操作では予期しないエラーが発生します。したがって、より便利でスレッドセーフなデータ構造、つまりサブタイトルで言及した Queue キュー データ構造の使用を試みることができます。
同様に、Queue にも join() メソッドがあります。この join() メソッドは、実際には前のセクションで説明したスレッドの join() メソッドと似ていますが、Queue では join() のブロック条件がキューは空ではありません。空の場合にのみブロックされます。空でない場合は、join() の後にコードの実行が続行されます。このクローラーでは、スレッドの join メソッドを通じてメイン スレッドを直接ブロックするのではなく、このメソッドを使用してメイン スレッドをブロックしました。この方法の利点は、まだ存在するかどうかを確認するために無限ループを作成する必要がないことです。現在のタスク キュー内の未完了のタスクを削除し、プログラムをより効率的に実行し、コードをより洗練させます。
もう1つの詳細は、python2.7のキューモジュールの名前はQueueですが、python3では名前がqueueに変更されているという違いです。
getopt モジュール:
C 言語を学習したことがある方は、このモジュールに精通しているはずです。これは、コマンド ラインのコマンドから添付パラメータを抽出する役割を担うモジュールです。たとえば、通常、mysql データベースをコマンドラインで操作する場合、mysql -h127.0.0.1 -uroot -p と入力します。ここで、mysql の後の「-h127.0.0.1 -uroot -p」はパラメータ部分であり、取得できる。
通常、クローラーを作成する場合、mysql のホスト IP、ユーザー名、パスワードなど、ユーザーが手動で入力する必要があるパラメーターがいくつかあります。プログラムをより使いやすく、多用途にするために、一部の構成項目をコード内でハードコーディングする必要はありませんが、実行時にそれらを動的に渡すことで、この機能を実現できます。
ハッシュリブ (ハッシュ):
ハッシュは本質的に数学的アルゴリズムの集合です。この数学的アルゴリズムの特徴は、パラメータを与えると、非常に短い結果ですが、ほぼ一意であるとみなせることです。たとえば、通常、md5、sha-1 などを聞きますが、これらはすべてハッシュ アルゴリズムに属します。一連の数学的演算を行った後、一部の文書やテキストを、100 桁未満の数字と英語が混在した文字列に変換できます。
Python の hashlib モジュールは、これらの数学演算関数をカプセル化しています。これを呼び出すだけでハッシュ演算を完了できます。
このパッケージをクローラーで使用するのはなぜですか?一部のインターフェイス要求では、インターフェイスによって要求されたデータが改ざんされたり紛失したりしていないことを確認するためにサーバーがいくつかの検証コードを取得する必要があるため、これらの検証コードは通常ハッシュ アルゴリズムであるため、この操作を完了するにはこのモジュールを使用する必要があります。 。
json:
多くの場合、私たちがキャプチャするデータは HTML ではなく、一部の JSON データです。json は本質的に、特定の文字列を抽出する必要がある場合、これを変換する必要があります。 json 文字列を便宜上 dict 型に変換します。
re (正規表現):
Web コンテンツをキャプチャすることがありますが、Web ページから一部のコンテンツを特定の形式で抽出する必要がある場合、通常、電子メール アドレスの形式は最初の数文字です。数字と文字、@ 記号、および http://xxx.xxx のドメイン名。この形式をコンピューター言語で記述するには、正規表現と呼ばれる式を使用して、コンピューターが自動的にテキストを照合します。大きな文字列からこの特定の形式に一致します。
sys:
このモジュールは主にいくつかのシステム問題に対処するために使用され、このクローラーでは出力エンコーディングの問題を解決するために使用します。
time:
少し英語を学んだ人なら、このモジュールが時間の処理に使用されていることが推測できるでしょう。このクローラーでは、それを使用して現在のタイムスタンプを取得し、プログラムの最後で現在のタイムスタンプを減算します。メインスレッドの実行開始時のタイムスタンプを取得して、プログラムの実行時間を取得します。
図に示すように、100 ページをクロールするために 50 のスレッドが開かれます (ページあたり 30 件の投稿、3000 件の投稿のクロールに相当)。Tieba の投稿コンテンツと携帯電話のメール アドレスの抽出のこのステップには合計 330 時間がかかります。秒。
urllib と urllib2:
これら 2 つのモジュールは、一部の http リクエストと URL フォーマットを処理するために使用されます。クローラーの http リクエスト部分のコア コードは、このモジュールを使用して完成します。
MySQLdb:
これは、Python で mysql データベースを操作するためのサードパーティ モジュールです。
ここで、細部に注意する必要があります。mysqldb モジュールはスレッドセーフ バージョンではありません。つまり、複数のスレッドで同じ mysql 接続ハンドルを共有することはできません。したがって、私のコードでは、各スレッドのコンストラクターで新しい mysql 接続ハンドルを渡していることがわかります。したがって、各子スレッドは独自の独立した mysql 接続ハンドルのみを使用します。
cmd_color_printers:
これも、関連するコードがオンラインで見つかります。このモジュールは、主にコマンド ラインにカラー文字列を出力するために使用されます。たとえば、通常、クローラでエラーが発生したときに、より目立つ赤いフォントを出力したい場合は、このモジュールを使用する必要があります。
自動クローラのエラー処理:
ネットワーク品質が低い環境でこのクローラを使用すると、図に示すような例外が報告されることがあります。ここには例外処理が書かれていません。
通常、高度に自動化されたクローラーを作成したい場合は、クローラーが遭遇する可能性のあるすべての異常な状況を予測し、これらの異常な状況に対処する必要があります。
例えば、図に示すようなエラーが発生した場合、その時点で処理中のタスクをタスクキューに再挿入する必要があり、そうしないと情報が欠落してしまいます。これは、クローラーの作成において複雑な点でもあります。