Pythonを使ったWebスクレイピングを行うために、前回Webにリクエストを送信して情報を取得しました。ここではより意味のある情報として、ブログページのhタグ(見出し)のみを抽出する方法について紹介します。
こんにちは。wat(@watlablog)です。
最近はWebスクレイピングネタを連投していますが、本日は実用編!ブログ記事の見出しだけを抽出する方法を紹介します!
ここで紹介している内容はWebスクレイピングの一例に過ぎません。僕はPython特化型学習サービス「PyQ(パイキュー)」で基礎を覚えました。体系的にPythonプログラミングやWebスクレイピングを覚えたい方は是非「PyQでPython学習!実際に登録してみた感想と気になる料金」の記事をご覧下さい。
HTMLのhタグを抽出してブログ見出し一覧を作ろう!
Webスクレイピングについてのおさらい
Webスクレイピングは過去、「PythonでWebスクレイピング!Requestsで情報取得!」で紹介した通り、情報収集の自動化が出来るようになり、生産性を大きく向上させることができるプログラミング技術です。
しかし、外部のWebサイトから情報を持って来るということは、相手のサイトに負荷をかける以外にも著作権の問題が潜んでいることを説明しました。
法的問題に発展させないためにも、上記記事の注意事項や事例をしっかり読んでおいて下さい。
技術は「正しく」使わないといけません!
マッド・サイエンティストにならないように気を付けましょう!
ブログの見出しを抽出すると記事の概要がわかる
では本題ですが、この記事では「ブログの見出し」を抽出する方法について説明します。
ブログの見出しとは、このページでも本文の書きだしの前に章や節として太字で書いてある内容(この本文の見出しは「ブログの見出しを抽出すると記事の概要がわかる」の部分)です。
この見出しというのは、ブログを書いている人であればかなり気を使って文章を考案している部分になります。
通常、ブログを書いている人、通称ブロガーはSEO(Search Engine Optimization)といって、検索エンジンに最適化するように記事を構成しようとします(読まれたい一心で。例外もあります。)。
その時、タイトルやメタディスクリプション、見出しといった内容にキーワードや要点を書いておくことで、Google等の検索エンジンで上位表示されやすいという仕組みがあります。
特に、見出しは記事の本文に一つ一つついているものであり、まず見出しがあって、次に説明が始まるので、見出しを見て本文の概要がわかるブログが良いブログとされています。
1.〇〇基礎、2.〇〇概要…だけだと良くないという「ブログ論」もありますね。
あまりブログ論に振り回されてもいけませんが、読者としては、時間を有効に使いたいので、目次を見てざっくり内容を知れると良いのではと思います。
ということで、見出しを抽出すれば、その記事の言いたいことがざっくりとわかると言えます!
HTMLについてのおさらい
ブログはHTMLという言語で書かれています。このWATLABブログも、ソースコードを表示するとHTMLタグがひしめき合っている様子が確認できます。
HTMLやHTMLタグについては、「Pythonテキスト処理!文章中からHTMLタグを取り除いてみた」に記載しましたので、あやしい方は是非記事を参照してみて下さい。
そして今回はこの記事に書いてある方法と、これまで学んだことを組み合わせて、Webページから見出し情報だけを抽出する方法を紹介します。
Webページから見出しのみを抽出するPythonコード
Webページにリクエストを送信して情報を取得する方法
それでは、Pythonコードの説明に入ります。全コードは記事の後半に載せますが、まずは説明上、部分部分のコードを載せていきます。
最初はリクエストの送信部分です。
「PythonでWebスクレイピング!Requestsで情報取得!」で習得した通り、requestsメソッドを使ってURLのWebページにアクセスし、適切なエンコードを実施、.text関数で情報をテキストとして取得することができます。
requestsパッケージをインストールしておけば楽勝ですね!
1 2 3 4 5 6 7 8 9 10 |
# python -m pip install requestsが必要 import requests # 取得したい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 # テキストで情報を取得 |
テキスト全体から<h>タグを抽出する関数
次は、テキスト全体から見出し、つまり<h>タグのみを抽出する関数を説明します。これは少々長いコードですが、詳細はコード内のコメントを細かく書きましたので参照下さい。
<h>タグはh1~h6までの範囲で値を取ります。h1→h2→h3→h3…と単純に数値が増加するわけではありません。そのためwhileループを使って、「<h」で始まるワードを検索している所がキーポイントです。
しかし、「<h」で始まるキーワードはhtmlやheadといったタグにもヒットしてしまうため、hの次の文字が数字の文字列かどうかを判定して、見出しタグである場合のみスライスによる抽出を行っています。
検索やスライスについては、「Pythonでテキスト処理!任意の文字列の場所を検索する方法」に詳しく書いていますので、そちらを参照して下さい。
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 |
# テキスト全体から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 |
HTMLからタグ部分を削除する関数
先ほど紹介した関数の中でremove_bracketという関数を呼び出していましたが、その関数も自作していたものです。
この関数は、「Pythonテキスト処理!文章中からHTMLタグを取り除いてみた」の記事で紹介しているものと同一ですので、詳細の説明は記事を参照して下さい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# テキストから<~>で挟まれた部分を削除する関数 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 |
全コード
コピペして使って頂きやすいように、全コードを載せておきます。
最後に抽出した結果をテキストファイルとして保存していますが、この内容を使って各々のテキスト分析をして頂ければと思います。
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)) |
実行結果
以下の画像が実行結果です。保存されたテキストファイルの中身を見ています。
保存されたテキストファイルは見事見出しのみになっていることがわかると思います。
まとめ
本ページではWebスクレイピングの例として、requestsで取得したHTML情報から、見出しタグの内容のみを抽出する方法を紹介しました。
今回は特に便利なライブラリ(BeautifulSoupやSelenium)を使わないで筆者が学習用に自力で作成したスクレイピングコードになります。
おそらくライブラリを使った方がスマートなコードになると思いますので、今後はそちらの学習を進めて行きたいと思います。
Webスクレイピングもなんとなくやり方がわかってきました!次はもっと高度なことにも挑戦していきたい!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!