stMind

about Arsenal, Arsene Wenger, Tech, Computer vision and Machine learning

from_toとencode, decode

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;