Pythonでスクレイビング・クローリングするときの手法ヒント集
どうも、お久しぶりです。絶賛就活中で記事を書くのが難しくなっている今日この頃です。そんな状況でも修論を書かなくてはいけないわけです。自分の研究は自然言語処理分野なのですが、ちょっと学習データを求めてWebサイト群からクローリングしようということになりました。これまでも色々クローリングして来たので、今回はクローリングに使える基本的な記述法を主に自分用にまとめていこうと思います。
今回は、Python3で主にButifulSoupを使ってやっていきたいと思います。また今回はコードの記述スピードを優先で書いているため、処理的には優秀ということではありません。おそらく賢い方法はいくらでもあるので、この記事はあくまで参考程度にご覧ください。
Contents
. URLからHTMLの取得
まずは基本中の基本である「URLでHTMLの取得」です。あと、取得したHTMLからBeautifulSoupのインスタンスを作成します。
1 2 |
html = urllib.request.urlopen('URL').read().decode('utf-8') soup = BeautifulSoup(html, 'lxml') |
. 取得したHTMLの無駄な部分を削除
上記では、取得したHTMLをそのまま使用していますが、クローリングするページによっては無駄な部分を削除した方がその後の処理が簡単になる場合がたくさんあります。さて、ではどうやって無駄を削除するかですが、正直クローリングするページによって大きく異なると思います。というわけで、汎用的で単純な方法を載せておこうと思います。
1 2 3 4 5 |
# 単純に無駄な部分を削除 html = html.replace('削除したい文字列', '') # ~以降を取得, ~より前を取得 html = html.spslit('~')[1] html = html.spslit('~')[0] |
やっていることは極めて単純です。ブラウザの「このページのソースを表示」なんかで対象ページのHTMLを確認し、目的の要素を効率的に取得できるように分割するのがいいと思います。ちなみに、”split”によってHTMLタグやbodyタグがなくなってもBeautifulSoupのインスタンスを作成するときにそれとなく対応してくれるので問題はないと思います。
. リンクの取得
ページ内のアンカータグ(<a href=”XXX”></a>)に記述されているリンクを取得します。
1 2 3 |
left_words = soup.select('[css selector] a') for lw in left_words: word_detail = lw.get('href') |
“[css selector]”という部分ではCSSにおけるセレクタをを記述することで、対応するアンカータグを取得することができます。この部分を書かなければ、ページ内の全てのリンクを取得することができます。
. よく使うCSSセレクタ
CSSセレクタを利用すると、操作したい要素を細かく指定することができます。Webサイトをよく作る人なんかは結構使っているのではないでしょうか。今回はクローリングですが、このセレクタを使う・使わないで雲泥の差があるので、是非使ってみてください。というわけで、いかによく使うセレクタをまとめておきます。
span.c_name | | c_nameクラスのspanタグ |
.c_name span | | c_nameクラスの中にあるspanタグ |
span[***=’…’] | | ***属性が”…”のspan |
もっともよく使うのがこれらですが、他にもたくさんあります。これに関してはこちらのサイト様が参考になるので、みてみてください。
. アンカータグの削除
先ほどはアンカーの内容を取得しましたが、次は逆に無駄なアンカーを削除する方法です。
1 2 3 4 5 |
import re # タグ内の文章は残す html = re.sub(r'<a +.*?>(.*?)</a>', r'\1', html) #タグごと削除する html = re.sub(r'<a +.*?>(.*?)</a>', '', html) |
今回は正規表現を使って書いてみました。
. 情報の取得
さて、ここまで来てやっと情報の取得です。もちろん取得する情報の位置や種類はクローリングするページによって大きく異なります。ここでは、単純に指定したタグの内容を出力してみます。
1 2 3 |
words = soup.select('[css selector] span') for w in words: print(w) |
. <table>から情報を取得
次はテーブルタグの情報を取得してみます。やっていることは上で書いた方法と変わリません。
1 2 3 4 5 6 7 8 9 |
table = soup.findAll('table')[0] for tr in table.findAll('tr'): tds = tr.findAll('td') if tds == None: continue for td in tds: print(td.text, end=",") else: print() |
やっていることは、tableタグ、trタグ、tdタグと順々に取得しているだけです。ちなみに上記のコードではページ内の1番目に出てくるテーブルだけを取得しています。これは一行目のfindAllをしているところで、”[0]”と記述しているからです。もしページ内の全ての表を取得したければ、この部分を消してしまえば大丈夫です。その時はtableがリスト形式で帰ってくるため、もう一つfor文を噛ませなくてはいけないと思います。
. URLを指定してファイルをダウンロード
今回はテキストをメインにクローリングしていましたが、以前ページ内にリンクがあるファイルをダウンロードするコードも書いたことがあるので、ここに一緒に載せておこうと思います。一応関数っぽく仕上げておきました。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
def download_file(url): FILE_NAME = 'ダウンロードするファイルの名前' print('downLD : '+ url, flush=True) try: req = urllib.request.Request(url) req.add_header("User-agent", "Mozilla/5.0") with open(FILE_NAME, "wb") as myfile: myfile.write(urllib.request.urlopen(req).read()) except urllib.error.ContentTooShortError: pass except urllib.error.HTTPError: pass return False |
普通にリクエストしてもいいのですが、そうするとWebページによってはサーバー側で弾かれてしまうようなので、それっぽい偽装ヘッダを付与してからダウンロードします。あとコードないのFILE_NAMEは適当に書き換えてください(拡張子をお忘れなく)。
. ページを移動する
さて、ページ内の情報を取得できるようになったので、次はページ推移をしたいと思います。基本的には、上記の方法でurlopen、アンカータグからリンクを取得して、BeautifulSoupの解析を(&次のリンクを取得)して、urlopen……という流れになると思います。
1 2 3 4 5 6 7 8 9 |
now_url = '[クローリングを始めるURL]' while True: html = urllib.request.urlopen(now_url).read() soup = BeautifulSoup(html, 'lxml') # ページの解析的な処理 a_list = soup.select('[css selector] a') # 次のページに繋がるリンクを取得 now_url = a_list[0].get('href') |
ここではかなりテキトーな例を書きました。このコードを実行しても何もすることはできません。とてつもなく単純な骨組みをお考えください。
. ページングされたページをクロール
クローリングをしていると検索結果みたいにページが数分けれているものがたくさんあります。それらのページに対してクローリングするには、(単純ですが)ちょっとした工夫が必要です。ようは、必要なリンクをうまく取得すればいいだけの話なのです。
さて、ページングされたページをうまくクローリングするには、これまた対象によって大きく異なります。もし対象ページのページングがURLの末尾の数値が増えていくだけだったら以下のコードのように一つずつurlopen先を変えていけばいいだけです。
1 2 3 4 5 6 7 8 |
page = 1 while True: html = urllib.request.urlopen('http://[対象ページ]/[検索結果的なDIR]/%d'%page).read() soup = BeautifulSoup(html, 'lxml') # 何らかの解析的な処理 page += 1 |
このようにループを回せばとりあえずクローリングすることはできます。問題点としては、上記のコードでは、終了処理を書いていないのでページが終わってもずっと進んでいきます。サイトによっては404エラーなんかで強制終了されます。問題はページがないという、エラーページを返してくれるサイトなのですが、これに対しては別途終了処理を付け加える必要があります。終了条件としてはクローリング対象のタグ(または ID,クラス)の有無や「ページが存在しません」という文字が含まれているか否かが考えられます。
また、ページの進み方として考えられるのが「次へ」のボタンのリンクを取得することです。もし、「次へ」のボタンがアンカータグだったら、上記の方法で簡単に次のページのURLを取得することができます。
. おまけ ブラウザ自動操作を使ってみる
クローリングするサイトにはJavascriptなんかのスクリプトによってページを表示したり、更新したりするものがあると思います。その時はURLでHTMLを取得してくるだけでは不十分である場合があると思います。そこでご提案するのがブラウザを操作してページを表示してしまえばいいじゃないかということです。個人的には使いやすかったSeleniumというテストツールでブラウザ操作を行うのが簡単でした。Seleniumの紹介を始めると長くなるので、以前に書いた本サイトのSelenium記事を参照ください。Seleniumが使えるようになったら、あとはブラウザからHTMLのソースを取得し、あとは上記の方法で必要な情報を持って来れば大丈夫だと思います。
おわりに
さて色々書いて来ましたが、自動的にクローリングするようなコードが書けるようになると色々と作業を捗らせることができます。すごーい、たっのしー。では今回はこんなかんじで。
コーディングで分からないことがあれば
プログラミングや環境構築で分からないことがあったら『teratail』というエンジニア特化型のQ&Aサービスがオススメです。自分もどうしても分からないことがあったら、時々質問しにいきますが、かなりニッチな質問にも意外と早く回答がつくのでとても頼もしいです。という宣伝でした。