Python
Python3
PythonDay 12

Python3.5のAsync構文を利用してスクレイピングを行う

More than 3 years have passed since last update.

Pythonでスクレイピングする方法としては既存のライブラリであるScrapyやdemiurge等を利用するという方法がありますが、

今回はPython3.5から追加されているAsync構文を利用して自作してみようと思います。

なおasync・awaitとはなんぞやという説明は行いません。

async・await構文の使い方はこちらの記事が参考になりました。



環境


  • Python3.5.0

  • beautifulsoup4==4.4.1


How To

まずはWebサイトのダウンロード部分から

import asyncio

import urllib.request

class Downloader:
def __init__(self, urls):
self.urls = urls

def run(self):
loop = asyncio.get_event_loop()
return loop.run_until_complete(self.fetch())

async def fetch(self):
return await asyncio.wait([self.download(i, url) for i, url in enumerate(self.urls)])

async def download(self, n, url):
request = urllib.request.Request(url)
html = urllib.request.urlopen(request).read()
print("{0} {1} download finish...".format(n, url))
return html

if __name__ == "__main__":
downloader = Downloader([
"https://www.python.org/",
"https://www.python.org/about/",
"https://www.python.org/downloads/"
])

downloader.run()

結果

1 https://www.python.org/about/ download finish

2 https://www.python.org/downloads/ download finish
0 https://www.python.org/ download finish

コードで特出すべきところとしては、downloadメソッドを並列に実行していることです。

同期的に1つずつダウンロードするのではなく、非同期でダウンロードできていることが確認できると思います。


スクレイピング

これだけだとHTMLをダウンロードしただけで、パースが面倒なのでパーサーを追加するためにコードを修正します。

今回はBeautifulSoupを使い、WebサイトのTitleタグの中身を取得します。

import asyncio

import urllib.request
from bs4 import BeautifulSoup

class Scraping:
def __init__(self, urls):
self.urls = urls

def run(self):
loop = asyncio.get_event_loop()
return loop.run_until_complete(self.fetch())

async def fetch(self):
return await asyncio.wait(
[self.scraping(url) for url in self.urls]
)

async def scraping(self, url):
request = urllib.request.Request(url)
html = urllib.request.urlopen(request).read()
bs = BeautifulSoup(html, "html.parser")
print(bs.title.string)

if __name__ == "__main__":
scraping = Scraping([
"https://www.python.org/",
"https://www.python.org/about/",
"https://www.python.org/downloads/"
])

scraping.run()

結果

Welcome to Python.org

Download Python | Python.org
About Python™ | Python.org



まとめ

と簡単にはですが、これで自作のスクレイピング処理が実装できました。

後はクローリング機能を実装することで立派なフレームワークになります。

クローリングについては、、、クローラー/Webスクレイピング Advent Calendar等を参考にすると良いのではないでしょうか(丸投げ

Async構文の3.4との比較ですが、

* コルーチンを定義する際に@asyncio.coroutineデコレータを付ける必要がなくなり、async defと完結になった。

* yield from とジェネレータと混同しやすかった構文がawait文になりシンプルでわかりやすくなった。

かなと思います。

今回のコードは全てGithubに公開しているので何かあればそちらを参照してください。


参考