補章1 Pythonとクローラー
はじめに
ここでは、Scrapyを使わずにクローラーを作る方法をまとめておきます。Scrapyを使わない場合、基本的にはBeautiful SoupやSeleniumなどのライブラリを使うことになるかと思いますが、ここでは、lxmlライブラリを使用します。lxmlライブラリは、Pythonでxml、htmlを扱うためのライブラリで、Beautiful Soupなどに比べ、より速く、柔軟にhtmlを解析できる特長があるそうです。
今回、クローラーを走らせるサイトは、これまでも使ってきた架空のオンライン書店のサイトです。
単一のページからURLを取得し、それを拡張して複数ページのURLを取得。そして、詳細ページの情報を抽出し、MySQLに保存するまで、段階を追ってクローラーを作成していきます。関数ごとに役割を分けています。その理由は、リクエストしてスクレイピングする際に、スクレイピングでエラーが出ると、また初めのリクエストからとなると、相手のサーバーに余分な負荷をかけることになるので、役割を分けておくことで、無駄を省けます。
ここで紹介する方法以外に、もっと効率のよい方法があると思いますので、参考程度にしていただければと思います。例えばジェネレータとかも使えれば良いんだろうけど、まだ使いこなせてない。
pip install requests
pip install lxml
pip install requests
単一ページから書籍URLを抽出
まずはTOPページから書籍の詳細ページへのURLを抽出するコードを書いていきます。ファイル名はbooks_crawler.pyとします。基本的には、おのおの役割を持つ関数を作って、それをmain()で実行します。
fetch()はURLを引き受けてHTTPリクエストを送り、HTTPレスポンスを受け取って、HTMLを返します。そして、book_link_extractor()にHTMLを渡して、各書籍のURLを取得します。
import requests
import lxml.html
import pprint
def main():
start_url = 'http://books.toscrape.com'
html = fetch(start_url)
urls = book_link_extractor(html)
pprint.pprint(urls)
def fetch(url):
req = requests.get(url)
html = lxml.html.fromstring(req.text)
return html
def book_link_extractor(html):
urls = []
for book in html.findall('.//*[@class="product_pod"]/h3/a'):
url = book.get('href')
urls.append(url)
return urls
if __name__ == '__main__':
main()books_crawler.pyを実行すると、トップページにある20個の書籍のURLが返されます。
このままでは、50ページあるサイトの各書籍のURLを取得できていないので、改良していきましょう。
複数ページから書籍URLを抽出
複数ページから書籍のURLを抽出できるようにループを回して、ページを進めていきます。もちろんURLのページ番号をfor-loopで回す方法でも良いのですが、ここでは各ページに「次ページ」へのボタンがあるかどうかを判断してクローラーを進めていきます。
そのため、ここでは新たにnextpage_link_extractor()と、少し改良したbook_link_extractor()を定義しています。nextpage_link_extractor()は、引き受けたHTMLに「次ページ」へのリンクがあるかを判定します。この関数がページのURLを返す限り、各書籍のURLを抽出するbook_link_extractor()は実行され続けるようにwhile-loopを使用します。
クローラーが想定通りに、動くかどうかテストしてみます。ここでは、49ページと50ページの書籍URLを取得します。合計で40個のリンクが返ってきているので、問題ないですね。
詳細ページから情報を抽出
各ページの書籍URLを抽出できる状態になったので、そのURLを使ってHTTPリクエストを送り、書籍の詳細ページから情報を抽出します。
詳細ページの情報はscrape()で行い、ここでは書籍のタイトルを抽出することにします。この関数の説明は不要かと思いますが、ざっくりと説明するとHTTPリクエストを送り、詳細ページからタイトルを抽出する関数です。
実行すると下記のように各書籍のタイトルが返されます。
MySQLに情報を保存
最後はデータベースに保存するsave()を新たに作って、クローラーを走らせます。まずは、データベースscrapingにテーブルbooksを作成します。MySQLにインサートする方法は第7章で扱っているので、詳細はそちらを参照ください。
save()はMySQLへのコネクションをつくり、scrape()から得られる書籍のタイトルをインサートします。
スタートするページを1ページ目に戻し、最後の50ページまでクローラーを走らせます。これを実行すると、下記のようにMySQLのテーブルに1000冊分の書籍のタイトル情報がインサートされます。
MySQLのテーブルも確認しておきます。1000件全ての書籍タイトルが取得できています。
ここまでScrapyを使わずクローラーを作ってみましたが、ここからさらに、Scrapyのsettings.pyの内容を実装するとなると、考えるだけでも大変ですし、Scrapyのありがたみがわかりますね。
最終更新
役に立ちましたか?