PerlでHTMLを解析してデータ収集してみる? スクレイピングはLWP::UserAgentまたはMojo::UserAgentとMojo::DOMの組み合わせ

PerlでHTMLを解析してデータ収集してみる? スクレイピングはLWP::UserAgentまたはMojo::UserAgentとMojo::DOMの組み合わせ。

codezine.jp

Perlで行う方法を紹介します。

LWP::UserAgent

まずオーソドックスな方法は、LWP::UserAgentを使う方法です。LWP::UserAgentは、PerlのオーソドックスなHTTPクライアントで、Webスクレイピングに利用できます。

perldoc.jp

 require LWP::UserAgent;
 
 my $ua = LWP::UserAgent->new;
 $ua->timeout(10);
 $ua->env_proxy;
 
 my $response = $ua->get('http://search.cpan.org/');
 
 if ($response->is_success) {
     print $response->content;  # or whatever
 }
 else {
     die $response->status_line;
 }

Mojo::UserAgentとMojo::DOM

またWebフレームワークMojoliciousには、Mojo::UserAgentと呼ばれるノンブロッキングI/O対応のHTTPクライアントがあるので、複数サイトに並列アクセス(5くらいが良心的)して、HTMLをとってきて、Mojo::DOMを使ってDOMを解析するということもできます。これは、スクレイピングでHTML情報を解析するのに便利です。

mojodoc.perlzemi.com

use Mojo::UserAgent;

# 良い粒度のレスポンスの処理(接続エラーの場合は、例外を発生)
my $ua  = Mojo::UserAgent->new;
my $res = $ua->get('mojolicious.org/perldoc')->result;
if    ($res->is_success)  { say $res->body }
elsif ($res->is_error)    { say $res->message }
elsif ($res->code == 301) { say $res->headers->location }
else                      { say 'Whatever...' }

# Acceptヘッダをつけてユニコードのスノーマンにハローを言う
say $ua->get('www.☃.net?hello=there' => {Accept => '*/*'})->result->body;

# HTMLとXMLのリソースからCSSセレクタを使ってデータを抽出する
say $ua->get('www.perl.org')->result->dom->at('title')->text;

取ってきたHTMLは、Mojo::DOMで解析して自由に取り出せます。

mojodoc.perlzemi.com

use Mojo::DOM;

# 解析
my $dom = Mojo::DOM->new('<div><p id="a">Test</p><p id="b">123</p></div>');

# 見つける
say $dom->at('#b')->text;
say $dom->find('p')->map('text')->join("\n");
say $dom->find('[id]')->map(attr => 'id')->join("\n");

# イテレート
$dom->find('p[id]')->reverse->each(sub { say $_->{id} });

# ループ
for my $e ($dom->find('p[id]')->each) {
  say $e->{id}, ':', $e->text;
}

# 修正
$dom->find('div p')->last->append('<p id="c">456</p>');
$dom->at('#c')->prepend($dom->new_tag('p', id => 'd', '789'));
$dom->find(':not(p)')->map('strip');

# 描画
say "$dom";