Perl楽しいから好き

Perlをはじめとしたプログラミング周りのあれこれについて。モダーンなPerlを楽しんでいます。

【Perl 文字化け解決】Wide character in print atといふエラーが原因だったー

こんばんは、Perl48です。


引き続き、

「アマゾンのゲーム売れ筋ランキングのゲームタイトルデータを引っこ抜きたーい」

の文字化け解消に取り組んでまいります。


まずは、前回までのソース


#!/usr/bin/perl -w

use lib 'C:/usr/cpan/build/Web-Scraper-0.32-VSDMOU/lib';

use Web::Scraper;
use URI;

# ゲームタイトル部分を gtitle という名前で取るスクレイパーを作成
my $scraper = scraper {
process 'table.zg .productTitle', 'gtitle' => 'TEXT';
};

# amazon.co.jpのTVゲームベストセラーページのURLオブジェクトを、
my $uri = new URI('http://www.amazon.co.jp/gp/bestsellers/videogames’);

# 先ほどのスクレイパーに渡す。(スクレイピングされる)
my $res = $scraper->scrape($uri);

print $res->{gtitle}; # 何が出るかな?

実行すると、こんな感じの文字化け↓


「ははーん、文字化けといえば、Jcode.pm だろ?」

という期待を裏切らない安易な発想で、


#!/usr/bin/perl -w

use lib 'C:/usr/cpan/build/Web-Scraper-0.32-VSDMOU/lib';

use Web::Scraper;
use URI;
use Jcode;

# ゲームタイトル部分を gtitle という名前で取るスクレイパーを作成
my $scraper = scraper {
process 'table.zg .productTitle', 'gtitle' => 'TEXT';
};

# amazon.co.jpのTVゲームベストセラーページのURLオブジェクトを、
my $uri = new URI('http://www.amazon.co.jp/gp/bestsellers/videogames');

# 先ほどのスクレイパーに渡す。(スクレイピングされる)
my $res = $scraper->scrape($uri);

print $res->{gtitle}; # 何が出るかな?

・・・残念ながら先ほどと結果は変わらず。

あきらめの境地でエラー画面を眺めていると、

「!!!」

『wide character in print at』の文字が目に飛び込んでくる!

「これだっー!」

早速ググル先生に質問しまくる。


ググル先生はエラーメッセージのコピペ検索に対しての
回答の精度がめちゃくちゃ高いから好きだ。


秀逸な記事はたくさんあったけど、
一番わかりやすかったのは、下記の記事
UTF8フラグとPerlIOレイヤ


どうやらutf-8 のテキストをprintしようとしてるから
エラーが出ちまうらしい。


まずは、utf-8のフラグが立ってるかどうかの確認をするため、
下記のソースを記述(もともとのprint文は一旦コメントアウト


#!/usr/bin/perl -w

use lib 'C:/usr/cpan/build/Web-Scraper-0.32-VSDMOU/lib';

use Web::Scraper;
use URI;

# ゲームタイトル部分を gtitle という名前で取るスクレイパーを作成
my $scraper = scraper {
process 'table.zg .productTitle', 'gtitle' => 'TEXT';
};

# amazon.co.jpのTVゲームベストセラーページのURLオブジェクトを、
my $uri = new URI('http://www.amazon.co.jp/gp/bestsellers/videogames');

# 先ほどのスクレイパーに渡す。(スクレイピングされる)
my $res = $scraper->scrape($uri);

#print $res->{gtitle}; # 何が出るかな?→一旦コメントアウト

print utf8::is_utf8($res->{gtitle}) ? 'flagged' : 'no flag';

すると、予想通りフラグが立った!!(flagged!)


Perl 5.8.x Unicode関連

の中の

Wide character な文字列はそのまま出力すると文句を言われるというわけです。
回避するには、PerlIOレイヤを使うか、UTF8フラグを落とします。

を参考に、ソースにPerlIOレイヤを追加


#!/usr/bin/perl -w

use lib 'C:/usr/cpan/build/Web-Scraper-0.32-VSDMOU/lib';

use Web::Scraper;
use URI;

# ゲームタイトル部分を gtitle という名前で取るスクレイパーを作成
my $scraper = scraper {
process 'table.zg .productTitle', 'gtitle' => 'TEXT';
};

# amazon.co.jpのTVゲームベストセラーページのURLオブジェクトを、
my $uri = new URI('http://www.amazon.co.jp/gp/bestsellers/videogames');

# 先ほどのスクレイパーに渡す。(スクレイピングされる)
my $res = $scraper->scrape($uri);

binmode(STDOUT, ":utf8");# PerlIOレイヤ

print $res->{gtitle}; # 何が出るかな?


すると、エラーは消えた!!

が、

文字化けはそのままー(爆)

またまたググル先生に相談。

ググル先生は、何時に相談しても答えてくれる素敵なヒトだ。


で、行き着いたのが
wakaponさんの超☆掃き溜め帳

どうすればいいかというと、またまたencodingを使う。encodingにソースコード文字コードを指定する。ソースコードがshiftjisであった場合、次のようにする。

で、ソースを以下のように


#!/usr/bin/perl -w

use lib 'C:/usr/cpan/build/Web-Scraper-0.32-VSDMOU/lib';

use Web::Scraper;
use URI;
use encoding qw(shiftjis);

# ゲームタイトル部分を gtitle という名前で取るスクレイパーを作成
my $scraper = scraper {
process 'table.zg .productTitle', 'gtitle' => 'TEXT';
};

# amazon.co.jpのTVゲームベストセラーページのURLオブジェクトを、
my $uri = new URI('http://www.amazon.co.jp/gp/bestsellers/videogames');

# 先ほどのスクレイパーに渡す。(スクレイピングされる)
my $res = $scraper->scrape($uri);

print $res->{gtitle}; # 何が出るかな?


そして、ついに・・・

キタ━━━━(゚∀゚)━━━━!!


wakaponさんの2006年の記事に助けられましたー。
ありがとうございます!


残すは、繰り返し処理の部分だぁぁぁ!!

今日はもう寝まーす。





富山市 賃貸