Webデータのクローリングはpythonの議論でよく出てくるトピックです。ウェブデータのクローリングを行う方法はたくさんありますが、****な方法はないようです。DIYのソリューションも非常に人気があります。
このように様々なアプローチがある理由は、データの「スクレイピング」は実際には多くの問題を含んでいるからです。何千ものページからデータをスクレイピングするために同じツールを使う必要はありませんし、同時にウェブワークフローの一部を自動化することもできます。DIYはその柔軟性から気に入っていますが、リクエストを同期させる必要があるため、大量のデータをクロールするには適していません。
この記事では、新しい非同期ライブラリ)に基づいたリクエストの代替を紹介します。このライブラリを使って、非常に高速な小さなデータグラバをいくつか書いてみました。
asyncioの基本概念
asyncio は python 3.4 で導入された非同期 IO ライブラリです。python3.3のpypiからもインストールできます。かなり複雑なので、あまり詳しくは説明しません。代わりに、このライブラリを使って非同期コードを書くために必要なことを説明します。
つまり、「コ・ルーチン」と「イベント・ループ」です。コ・プロシージャーはメソッドのようなものですが、コード内の特定のポイントで一時停止したり継続したりすることができます。コ・プロシージャーは、別のリクエストが実行されている間にIOを待つときに、コ・プログラムを一時停止するために使用できます。yield from キーワードは、コ・プログラムからの戻り値が必要であることを示す状態を設定するために使用されます。また、イベント・ループは、コ・プログラムの実行をスケジュールするために使用されます。
asyncioについてはもっともっとたくさんありますが、ここまでが知っておくべきことです。まだ少し不明な点があるかもしれませんので、コードを見てみましょう。
アイオーティーティーピー
aiohttpasyncioを利用するライブラリで、リクエストAPIによく似たAPIを持っています。しかし、ここにとても便利な例があります。基本的な使い方を説明します。
まず、ページを取得して印刷するためのコ・プログラムが定義されます。メソッドはasyncio.coroutineを使ってコ・プログラムとして装飾されます。aiohttp.stはコ・プログラムなので、読み込み可能なメソッドであり、それらを呼び出すにはfromを使う必要があります。それ以外は、次のコードはかなり直感的に見えます:
@asyncio.coroutine
def print_page(url):
response = yield from aiohttp.request('GET', url)
body = yield from response.read_and_close(decode=True)
print(body)
このように、yield fromを使えば、別の同期プログラムから同期プログラムを呼び出すことができます。同期コードから協調プログラムを呼び出すには、イベントループが必要です。asyncio.get_event_loop()で標準のイベントループを取得し、そのrun_until_complete()メソッドを使ってコプログラムを実行します。つまり、コ・プログラムを実行するには、以下のステップを実行するだけです:
loop = asyncio.get_event_loop()
loop.run_until_complete(print_page('http://.com'))
asyncio.waitという便利なメソッドがあります。このメソッドでコ・プログラムのリストを取得し、それらをすべて含む単一のコ・プログラムを返すことができます:
loop.run_until_complete(asyncio.wait([print_page('http://.com/foo'),
print_page('http://.com/bar')]))
もうひとつはasyncio.as_completedで、これはコ・プログラムのリストを取得することができ、またコ・プログラムを完了順に生成するイテレータを返します。
データクロール
非同期HTTPリクエストのやり方がわかったので、データ・グラバーを書けるようになりました。mlのページを読むには、もう少しツールが必要です。 beautifulsoup< href="javascript:;">lxmlのようなものも実装できます。
まず、リクエストを受け取るために補助的な共同プログラムが必要です:
@asyncio.coroutine
def get(*args, **kwargs):
response = yield from aiohttp.request('GET', *args, **kwargs)
return (yield from response.read_and_close(decode=True))
解析編。この記事はbeautifulsoupの紹介ではないので、この部分は省略します:このページの***磁気リンクを取得しました。
def first_magnet(page):
soup = bs4.BeautifulSoup(page)
a = soup.find('a', title='Download this torrent using magnet')
return a['href']
この相乗効果的な手順では、URLの結果はシードの数でソートされるため、***位の結果は実際には最もシードされています:
@asyncio.coroutine
def print_magnet(query):
url = 'http://.se/search/{}/0/7/0'.format(query)
page = yield from get(url, compress=True)
magnet = first_magnet(page)
print('{}: {}'.format(query, magnet))
***上記のすべてのメソッドを呼び出すには、次のコードを使用します。
distros = ['archlinux', 'ubuntu', 'debian']
loop = asyncio.get_event_loop()
f = asyncio.wait([print_magnet(d) for d in distros])
loop.run_until_complete(f)
#p#
はんけつをくだす
さて、いよいよ本題です。あなたは非同期で動作する小さなクローラーを持っています。つまり、複数のページを同時にダウンロードできるので、この例ではリクエストに同じコードを使うよりも3倍速くなります。これで、同じ方法で独自のグラバーを書くことができるはずです。
生成されたコードはpyqueryご覧いただけます。
これら全てに慣れたら、ドキュメントとasyncioの可能性を示すaiohttpのサンプルを見てみることをお勧めします。
このアプローチの限界のひとつは、フォームを処理するのに使えるスタンドアロン・ライブラリがないことです。機械化されたアプローチには、フォームの送信をとても簡単にしてくれるヘルパーツールがたくさんありますが、もしそれらを使わないのであれば、これらのことを自分で処理しなければなりません。これはいくつかのバグにつながる可能性があるので、その間に私はおそらくそのためのライブラリを書くでしょう。
おまけのアドバイス:サーバーを叩かないでください
同時に3つのリクエストをするのはクールですが、同時に5000のリクエストをするのはあまり面白くありません。同時にたくさんのリクエストをするつもりなら、リンクが切れる可能性があります。ネットワークへのリンクを禁止される可能性もあります。
これを避けるために、これは使用することができます。セマフォは、同時に作業する共同プログラマーの数を制限するために使用できる同期ツールです。ビルドループでセマフォを作成し、引数として許可したい同時リクエスト数を渡します:
sem = asyncio.Semaphore(5)
そして、次のように置き換えるだけです。
page = yield from get(url, compress=True)
セマフォで保護されているものと同じものに置き換えてください。
with (yield from sem):
page = yield from get(url, compress=True)
これにより、最大5つのリクエストが同時に処理されます。
追加推奨:プログレスバー
プログレスバーを生成するための優れたライブラリです。この共同プログラムはasyncio.waitのように動作しますが、完了を表すプログレスバーを表示します。
@asyncio.coroutine
def wait_with_progress(coros):
for f in tqdm.tqdm(asyncio.as_completed(coros), total=len(coros)):
yield from f





