13 June 2011

(Perl) HTML::Parserを使ってWebページのタイトルを取得する

任意のWebページから、HTML::Parserを使ってWebページのタイトルを取得(抽出)する方法

緑色 : HTML::Parser で HTMLを解析する処理
青色 : LWP::UserAgent と HTTP::Request でWebページをダウンロードする処理


#!/usr/bin/perl

use warnings;
use strict;
use utf8;
use HTML::Parser;
use LWP::UserAgent;
use HTTP::Request;
use Encode;

binmode(STDIN, ":utf8");
binmode(STDOUT, ":utf8");

my $flag_in_title = 0; # <title>タグと</title>タグの間にあるとき 1 をセット
my $str_title; # 抽出された title 文字列
my $enc; # meta http-equiv タグで指定されたエンコード形式


print "title属性を抜き出します\n";
main();
exit;

sub main{

# 指定されたURLよりHTMLファイルをダウンロードし $html 変数に格納する
print("解析するURLを入力 : "); # 例:http://www.google.com
my $url = <>;
chomp($url);
if($url eq '' or $url !~ /^http:\/\//){
print("Error : 入力が無かった、又はurlが「http://」で始まっていない\n");
exit;
}
my $req = HTTP::Request->new(GET => "$url");
my $ua = LWP::UserAgent->new;
# $ua->proxy('http', 'http://proxy:8080');
my $res = $ua->request($req);
if (!$res->is_success){
print("Error : 指定したURLからファイルをダウンロードできない\n");
exit;
}
my $html = $res->content;


# HTML形式の文字列を解析して、title属性を抜き出す
my $parser = HTML::Parser->new(
api_version => 3,
start_h => [\&sub_start_callback, "self, tagname, attr"], # 開始タグ
end_h => [\&sub_end_callback, "self, tagname"], # 終了タグ
text_h => [\&sub_text_callback, "dtext"], # タグ間の文字列
marked_sections => 1);

$parser->parse($html);


# 画面表示
if(defined($enc)){
print("encode detected : ".$enc."\n");
if(defined($str_title)){ $str_title = Encode::decode($enc, $str_title); }
}
if(defined($str_title)){
print("title : ".$str_title."\n");
}

}

# 開始タグ検出時(HTML::Parserコールバック サブルーチン)
sub sub_start_callback{
my ($self, $tagname, $attr) = @_; ## コンストラクタで指定した変数が渡される
if($tagname eq 'title'){
$flag_in_title = 1;
}
if($tagname eq 'meta' and defined($attr->{'http-equiv'}) and
lc($attr->{'http-equiv'}) eq 'content-type' and defined($attr->{'content'})){
if(lc($attr->{'content'}) =~ m/utf-8/){ $enc = 'utf8'; }
if(lc($attr->{'content'}) =~ m/shift_jis/){ $enc = 'shiftjis'; }
if(lc($attr->{'content'}) =~ m/euc-jp/){ $enc = 'euc-jp'; }
if(lc($attr->{'content'}) =~ m/iso-2022-jp/){ $enc = 'iso-2022-jp'; }
}
}


# 終了タグ検出時(HTML::Parserコールバック サブルーチン)
sub sub_end_callback{
my ($self, $tagname) = @_; ## コンストラクタで指定した変数が渡される
if($tagname eq 'title'){
$flag_in_title = 0;
}
}


# タグ間文字列検出時(HTML::Parserコールバック サブルーチン)
sub sub_text_callback{
my @dtext = @_; ## コンストラクタで指定した変数が渡される
if($flag_in_title == 1 and $dtext[0] ne ''){
$str_title = $dtext[0];
}
}


■ その他の方法

URI::Title を用いてもWebページのタイトルを取得できる


#!/usr/bin/perl

use warnings;
use strict;
use utf8;
use LWP::UserAgent;
use HTTP::Request;
use Encode;
use Encode::Guess qw/shiftjis euc-jp iso-2022-jp/;
use URI::Title;

binmode(STDIN, ":utf8");
binmode(STDOUT, ":utf8");

my $str_title; # 抽出された title 文字列
my $enc; # 自動判定されるエンコード形式


print "title属性を抜き出します\n";
main();
exit;

sub main{

# 指定されたURLよりHTMLファイルをダウンロードし $html 変数に格納する
print("解析するURLを入力 : ");
my $url = <>;
chomp($url);
if($url eq '' or $url !~ /^http:\/\//){
print("Error : 入力が無かった、又はurlが「http://」で始まっていない\n");
exit;
}
my $req = HTTP::Request->new(GET => "$url");
my $ua = LWP::UserAgent->new;
# $ua->proxy('http', 'http://proxy:8080');
my $res = $ua->request($req);
if (!$res->is_success){
print("Error : 指定したURLからファイルをダウンロードできない\n");
exit;
}
my $html = $res->content;

$str_title = URI::Title::title($url);
$enc = find_encoding($str_title);
if(ref($enc)){ $str_title = $enc->decode($str_title); }
print("title=".$str_title."\n");
}