PythonでWebにリクエストを送信し情報を取得した後、意味のある解析を行うためには適切にHTMLから情報を削ぎ落さなければなりません。ここではBeautifulSoup4を使った簡単なWebスクレイピング技術を紹介します。
こんにちは。wat(@watlablog)です。
Webスクレイピングを身に付けて情報収集を自動化します!ここではBeautifulSoupというライブラリパッケージを使うとこんなに簡単にスクレイピングできる、ということを示します!
ここで紹介している内容はWebスクレイピングの一例に過ぎません。僕はPython特化型学習サービス「PyQ(パイキュー)」で基礎を覚えました。体系的にPythonプログラミングやWebスクレイピングを覚えたい方は是非「PyQでPython学習!実際に登録してみた感想と気になる料金」の記事をご覧下さい。
Webスクレイピングは自力でやると非常に大変
Webから情報を取得する方法のおさらい
当WATLABブログでは、「PythonでWebスクレイピング!Requestsで情報取得!」の記事からWebスクレイピングについて扱ってきました。
日常の情報収集作業を自動化できる画期的な技術であるため、他にもいくつか記事を書き、深堀をしていこうと思っています。
しかしWebからプログラム的に情報を取得する場合は、サーバー負荷や著作権等、法的問題に発展する危険性がありますので、是非先ほどの記事に記載の注意点を先に読んで頂ければと思います。
スクレイピングを自作するとこんなに大変!
スクレイピングとは、「削ぎ落す」という意味がありますが、まさにWebから情報をとってきて意味のある情報にするためには、この削ぎ落し技術を多用しなければいけません。
前回紹介した「Pythonテキスト処理!文章中からHTMLタグを取り除いてみた」の記事では、本記事で紹介するBeautifulSoupを使わないで、自力でHTMLの森から見出しという<h>タグで囲まれた文章を抽出して来ました。
そして「PythonでWebスクレイピング!ブログの見出しを抽出する方法!」ではさらに発展させて、HTMLの大森林から全ての<h>タグを抽出し、タグ部分を排除して文章だけにするコードを紹介しました。
コードを以下に再掲してみます。コメントやファイル保存等も含めていますが、ざっと65行ほどのコードになりました。これは長い!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# python -m pip install requestsが必要 import requests # テキストから<~>で挟まれた部分を削除する関数 def remove_bracket(text): check = True # whileループの終了条件に使用 word_s = '<' # タグの先頭<を検索する時に使用 word_e = '>' # タグの末尾>を検索する時に使用 # 「<>」のセットが無くなるまでループ while check == True: start = text.find(word_s) # <が何番目の指標かを検索 # もしword_sが無い場合はcheckをFにしてwhileを終了 if start == -1: check = False # word_sが存在する場合 else: end = text.find(word_e) # >が何番目の指標かを検索 # もしword_eが無い場合はcheckをFにしてwhileを終了 if end == -1: check = False # word_sとword_eの両方がセットである場合は<と>で囲まれた範囲を空白に置換(削除)する。 else: remove_word = text[start:end + 1] # 削除するワード(<と>で囲まれた所)をスライス text = text.replace(remove_word, '') # remove_wordを空白に置換 return text # テキスト全体からhタグ(見出しタグ)の内容(<hn>~</hn>)を抽出する関数 def h_extraction(text): check = True # whileループの終了条件に使用 data_sc = [] # 検索にヒットした文字列だけを入れるリストを定義 nums = ['1', '2', '3', '4', '5', '6'] # hの次が数字文字列なのかどうか判定する時に使用する文字列リスト while check == True: # word_sが見つからなくなるまでループ word_s = '<h' # hタグの先頭を検索する時に使用(<htmlや<headもヒットする) word_e = '/h' # hタグの末尾を検索する時に使用 start = text.find(word_s) # word_sの開始指標を取得 # もしword_sが見つからなければcheck=Fとしてwhileループ終了 if start == -1: check = False # word_sが見つかった場合 else: # <hの次の文字が数字の文字列であれはhタグであるため、scrに抽出結果を入れるための処理を行う if text[start + 2:start + 3] in nums: # hの次の文字が文字列の数字かどうか判定 h_index = text[start + 2:start + 3] # hの次の文字である数字を定義 end = text.find(word_e + h_index) # </hn (nは数字)の位置を計算 temp = remove_bracket(text[start:end + 4]) # HTML文書からタグ(<~>を取り除く関数を実行 data_sc.append(temp) # <hn から </hn>までをスライスしてリストに追加 text = text[end + 1:] # 次の検索にこれまでの文章はいらないので削除する # <hの次の文字が数値でない場合はhtmlかheadタグなので、抽出はしない else: text = text[start + 1:] # hの次が数字で無い場合は、そこまでの文章を削除して次に移る return data_sc # 取得したいURLやweb上のファイル url = "https://watlab-blog.com/2019/08/03/text-search/" # HTTPリクエストを送信して情報を取得 response = requests.get(url) response.encoding = response.apparent_encoding # 適切なエンコードを適用する file = response.text # テキストで情報を取得 text = h_extraction(file) # hタグ(見出し)部分のみを抽出する関数を実行 # 抽出結果をテキストファイルに保存(withで書けばcloseを自動的にしてくれるから便利) with open('h_tag.txt', mode='w', encoding='utf-8') as f: f.write("\n".join(text)) |
ちなみに、本コードはHTMLとにらめっこしながら2時間ほど考えて作りました…。学習のために「やってみよう!」と思って取り掛かりましたが、正直これは「車輪の再発明」ですよね。
しかし、BeautifulSoupという外部のライブラリパッケージを使えば、もっと簡略化したスマートなコードにすることができます。
BeautifulSoupを使ったスクレイピングコード
BeautifulSoupの概要とパッケージのインストール方法
先ほどから紹介しているBeautifulSoupとは、HTML言語の構文を解析するためのパッケージです。先に紹介した面倒なコードを、HTMLタグ毎に作らなくても良いように作られています。
HTMLの構文を解析することを「パース(parse)」すると言います。そして解析するプログラムの事を「パーサー(parser)」と呼びます。この後コード内でパーサーを使うので、覚えておいて下さい。
BeautifulSoupは2019年8月現在、バージョン4が最も使われています。このパッケージはコマンドプロンプトから、
「python -m pip install beautifulsoup4」
を打ち込み実行することでインストールできます。
ブログのタイトルをスクレイピングするコード
ではh1タグ、つまりブログのタイトルだけを抽出するプログラムを以下に紹介します。
soupの手前までは過去の記事で紹介した内容とほぼ同じです。BeautifulSoup関数に先ほど説明したパーサーを明示的に指定して実行することで、HTML構文が解析されます。パーサーを指定しなくても動きますが、Webページ毎に異なる挙動をすることがありますので、指定しておくと良いでしょう。
パーサーにはその他にも種類がありますが、当ブログで使う時に再度紹介しますので、ここでは「html.parser」だけを覚えましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import requests # python -m pip install requestsでインストール可能 from bs4 import BeautifulSoup # python -m pip install beautifulsoup4でインストール可能 # 取得したいURLやweb上のファイル url = "https://watlab-blog.com/2019/08/03/text-search/" # HTTPリクエストを送信して情報を取得 response = requests.get(url) response.encoding = response.apparent_encoding # 適切なエンコードを適用する file = response.text # テキストで情報を取得 soup = BeautifulSoup(file, 'html.parser') # パーサーを指定してBeautifulSoupによる解析を実行 h_tag = soup.find('h1') # h1タグを抽出 print(h_tag.text) |
実行結果は以下のようになります。
1 |
Pythonでテキスト処理!任意の文字列の場所を検索する方法 |
「<>」を指定して検索したり、面倒な関数を作ってタグを排除しなくても綺麗に文章だけが抽出されていますね!
感動!!!
あれ、でも結局h1, h2, …と全て持って来るためにはwhileループは必須かな?
試しにh1の所をh2にしてみると、1つしか検索されません。どうやら複数のリスト形式で抽出するということまではやってくれないようです。となると、判定分やらなんやらは必要ですね。
それでも、BeautifulSoupを使えば、色々な括弧を排除していく作業や、タグの文字数に合わせてスライスする位置を調整したりすることは必要無くなるので、大変便利なパッケージであることには変わりはありませんね。
まとめ
自力で作ったスクレイピングのコードはスライスの位置調整やタグの排除といった細かいテクニックが必要でしたが、BeautifulSoupを使えばあっと言う間にHTML構文を解析し、綺麗に文章を抽出してくれることがわかりました。
これは使える!これを使えば情報収集の鬼になることが出来そうですね(法の範囲内で)!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!
コメント