perlの勉強として以前作ったJSPORTSのプレミアリーグ放送予定をスクレイピングするスクリプトを修正して、検索キーワードと放送形態(生放送、初回放送、同日録画)を指定できるようにした。
今回修正する上で一つだけつまづいたのがURLエンコードのための文字コード変換。スクリプトの入力はUTF8で、JSPORTSのURLエンコードはShift-JISなので、スクリプト内で文字コードをShift-JISに変換してやる必要があった。そこでEncodeのfrom_toを使って、
my $uri = URI->new('http://www.jsports.co.jp/search/sys/kensaku.cgi?kwd=' . uri_escape(from_to($kwd, 'utf8', 'shiftjis') . '&type=' . $type);
としていたんですけどうまくいかなかった。いろいろ調べてみると、こちらのページに
また、色々試したところ、UTF-8からShift_JISへの変換で、
Encode::from_to($str, 'utf8', 'shiftjis', Encode::FB_HTMLCREF);
では変換に失敗するけれど、
$str = encode('shiftjis', decode('utf8', $str), Encode::FB_HTMLCREF);
であれば、正しく変換(かつ、Shift_JISに無い文字はHTMLの数値文字参照に変換)されるようでした。なのでfrom_toの代わりにdecodeとencodeを使ったほうがよいのかも。
という情報が。そこで、次のように
my $uri = URI->new('http://www.jsports.co.jp/search/sys/kensaku.cgi?kwd=' . uri_escape(encode('shiftjis', decode('utf8', $kwd))) . '&type=' . $type);
とすると上手くいきました。お〜。ということで、from_toが上手くいかないときは、明示的にencodeとdecodeを使うといいみたいです。
ご参考までにできたスクリプトは以下。
#! /usr/bin/perl use strict; use warnings; use Web::Scraper; use URI; use URI::Escape qw(uri_escape); use YAML; use Encode qw(from_to encode decode); my $kwd = shift || 'アーセナル'; my $type = shift || '1'; my $uri = URI->new('http://www.jsports.co.jp/search/sys/kensaku.cgi?kwd=' . uri_escape(encode('shiftjis', decode('utf8', $kwd))) . '&type=' . $type); my $program_info = scraper { process '//td[@class="bSchedule"]', 'date' => 'TEXT'; process '//dd[@class="DETAIL"]', 'match' => 'TEXT'; process '//td[@class="bChannel"]/img', 'ch' => '@alt'; }; my $jsports = scraper { process '//div[@id="resultArea"]//tr[position()>1]', 'programs[]' => $program_info; }; my $result = $jsports->scrape($uri); binmode STDOUT, ":utf8"; print YAML::Dump $result;