perlでHTMLを解析して欲しい情報を抽出するためのコードをメモ

HTMLファイルから特定のタグに囲まれている情報だけを抽出したり、リンクだけを抽出したりしたいと思ったので、それを実現するコードを色々調べてperlで作成してみたのでメモしておきます。いわゆるスクレイピングするためのコードです。このコードでは、perlのHTML::TreeBuilderを使いました。

#2014/1/25追記
以下にメモしたコードそのままでは、HTML5で記述されたhtmlファイルから情報を抽出できません。HTML5にも対応したコードはperlでHTML5を解析して情報を抽出するコード(HTML::TagParser版)にメモしたので、見て頂ければと思います。

実行環境と使用したperlモジュール

実行環境はUbuntu12.04 64bit です。
使用したのは以下の2つのモジュールです。これらのインストールはcpanmで行いました。

  • HTML::TreeBuilder
  • LWP::UserAgent(Webサイトからhtmlファイルを取得する場合に必要)

ubuntuのPerl環境の構築手順については、以下のサイトが参考になりました。


HTML::TreeBuilderについて

ここではperlの「HTML::TreeBuilder」というモジュールを使用してhtmlファイルから必要な情報を抽出しました。HTML::TreeBuilderはどんなモジュールかというと、読み込んだhtmlファイルを解析して木構造形式のオブジェクトに変換してくれるモジュールです。

HTML::TreeBuilderに用意された関数を使用することで、htmlファイル内の全てのリンクを取得したり、特定のclass要素やid要素を持つタグに囲まれたテキストやリンクだけを取得することができます。以降に実際に作成したperlコードとその実行例を載せます。

perlのコード

今回作成したコードは、このサイトのトップページのhtmlファイルの冒頭部分から、新着順に並んだ投稿記事に関する以下の情報を抽出してターミナル上に表示します。

  • ① 投稿日 → <span class=”entry-day”>の中
  • ② URL → <div class=”entry-title”>の中
  • ③ 識別番号 → <div class=”entry-title”>のURLの中
  • ④ タイトル → <div class=”entry-title”>の中
  • ⑤ 説明 → <div class=”entry-content clearfix”>の<p>の中

htmlファイルで見ると、以下の画像の赤線部分になります。
virment_html_mod

今回使用したこのサイトのトップページのhtmlファイルを一応以下に載せておきます。以下のhtmlファイルは、このサイトのトップページにある新着記事3個分を抜粋したhtmlファイルになります。


そして以下が作成したperlコードです。下記のperlコードが置いてある同じディレクトリに上記のhtmlファイルを「virtualiment.html」という名前で保存してあります。ただし、以下のコードはperl初心者の私が色々なサイトを参考にして合体させて作成したコードであり、perl的にもプログラム的にも間違っている、良くないコードの可能性が十分にあります。現状では以下のコードで望みの動作を確認できているだけです。以下のコードはあくまで参考程度にして頂き、自己責任での使用をお願い致します。また、間違いなどがあればぜひ指摘して下さい。

上記のコードで使用している関数とその説明メモを以下に載せます。

look_down

look_downを使うことで、class要素の値、id要素の値やタグ名を指定して情報を抽出できます。以下にそれぞれの場合についてメモします。

id要素を使った抽出

上記コードの20行目の部分でid要素を使った抽出をしています。具体的には、id要素で値として「qr/post-\d{3,4}/」をもつ部分を抽出しています。この「qr/post-\d{3,4}/」は正規表現のリファレンスであり、「post-3桁以上4桁以下の数字」を意味します。つまり、この行ではid要素で値として「post-3桁以上4桁以下の数字」を持つ部分を木構造で取得します。

「qr/post-\d{3,4}/」について分からない方は、正規表現とメタ文字について以下のサイトに詳しく説明されており分かりやすいので参考になると思います。


class要素の値を指定して抽出

23行目では、class属性の値が「entry-date-top」であり、さらにその中でclass属性の値が「entry-day」である部分のテキストを取得しています。このように、look_downを続けて記述することで、木構造の階層を下へ下へと検索できます。なお、指定した部分の中からテキストを取得するために、「as_text」を使います。

タグ名を指定して抽出

35行目では、class属性の値が「entry-content clearfix」であり、さらにその中で「pタグ」の部分のテキストを取得しています。

extract_linksを使ってリンクを抽出

26行目では、class属性の値が「entry-title」であり、さらにその中にある<a href=>のリンク部分をextract_linksによって抽出しています。extract_linksはリファレンスの配列を返すので、そのリファレンスが指し示す先にある値を取得するために「->[0]」が2回続いています。ただ、正直ここらへんが書き方と意味を十分に理解していないので、本来こんな書き方はしない、また間違っている可能性があります。一応これで動くことを確認しています。なお、配列、リファレンスについては以下のサイトを参考になりました。

「配列の配列」の基礎のサンプル | サンプルコードによるPerl入門


grepとsplit

29行目では、grepとsplitを使って、$urlの中から3桁以上4桁以下の数字を抽出して取得しています。grepは、変数の中から、指定した条件にマッチする要素を取り出す関数です。splitは指定したパターンを区切りとして文字列を分割する関数です。grep、splitについては、以下のサイトにそれぞれ載っているので必要な方はご参照下さい。


まずgrepの条件である「/\d{3,4}/」は、3桁以上4桁以下の数字を意味します。
次に「split( /\D+/, $url)」は、パターンとして「\D+」、対象文字列として「$url」をそれぞれ指定しています。splitが処理する対象は「$url」であり、$urlには上記の場合だと各投稿記事のURLが格納されています。そしてパターンである「\D+」は、「数字以外の文字」を意味します。つまり、「split( /\D+/, $url)」により、$urlの中身である投稿記事のURLを数字以外の文字によって分割します。ここの例では、splitによって投稿記事のURLに含まれる数字がリストとして取り出されます。

以上から、29行目では、grepとsplitを使って、投稿記事のURLに含まれる3桁以上4桁以下の数字を取得しています。この数字は特に意味なくwordpressが付ける投稿記事の識別番号です。

実行結果

上記のコードをターミナルで実行すると、以下のような内容が出力されます。

上記のように、virtualimentのトップページにある新着記事の各情報がずらずらと表示されます。

ローカルのhtmlファイルではなく、直接Webからhtmlファイルを取得する場合

この場合は、以下の部分を


以下のように書き換えて使います。


#2014/1/24追記
2014/1/24にこのサイトのテーマを変更してトップページのhtmlファイルが変わりました。そのため、上記のようにこのサイトのhtmlファイルを直接取得しても、冒頭に記載した以下の情報が変わってしまっているので、実行しても何の情報も表示されません。

  • ① 投稿日 → <span class=”entry-day”>の中
  • ② URL → <div class=”entry-title”>の中
  • ③ 識別番号 → <div class=”entry-title”>のURLの中
  • ④ タイトル → <div class=”entry-title”>の中
  • ⑤ 説明 → <div class=”entry-content clearfix”>の<p>の中



したがって、Webからhtmlファイルを直接取得して試したい場合は、上記の5つの部分に対応するタグや値をこのサイトの新しいhtmlファイルの情報に置き換える必要があります。

#2014/1/25追記
詳しくはこちらperlでHTML5を解析して情報を抽出するコード(HTML::TagParser版)にメモしたので、見て頂ければと思います。

splitについてのメモ

上記では、splitを使って$urlの文字列に含まれる数字以外の文字によって分割しました。ここで分割とはどういうことかというと、例えば以下のコードによって文字列「$str」に対して「split(/\D+/,$str)」を実行すると、

以下のような実行結果になります。

上記を見ると、数字が取り出されて表示されているのが分かります。なお、「12」の上に空白があるのは、$strの先頭にある「This」が区切り文字であり、この「This」の前の要素が$strを分割した後に残る文字として出力されているからです。

参考サイト様

以下のサイトがとても参考になりました。ありがとうございました。

このエントリーをはてなブックマークに追加

SPONSORED LINK

この投稿へのコメント

コメントはありません。

コメントを残す

メールアドレスが公開されることはありません。

この投稿へのトラックバック

  1. […] この前、htmlファイルを解析して欲しい情報を抽出するためのperlコードをメモしました。(詳しくはこちら)ただ、この前のコードだとHTML5に対応できないことに後々気づいたので、今回はHTML5でも対応できるコードを改めてメモします。 […]

トラックバック URL