初めてのWeb Scraping

| コメント(0) | トラックバック(0)

バイト先でスクレイピングをすることになりそうだ。

Javaでwebページの解析をしたら日が何回も沈みそうだし(というか、解析元のhtmlが汚くて読めねぇ( つД`))、言語は何でもいいらしいので、最近やたら見かけるperlのWeb::Scraper(ドキュメント)を使ってみることにした。

今日はそれのメモ。

まず、Web::Scraperに慣れるために題材はオレのソーシャルブックマーク一覧のページに右あるtagの名前と数を抜き出すことにする。

とりあえず、htmlの該当箇所の

<div id="sidebar" class="list"><div class="sidebar-inner">
<ul class="bundles">

	<li class="bundle fold"><h3 class="label"><span>tags</span></h3>
		<ul>
			<li><span>3</span> <a href="/Lyo/.htaccess">.htaccess</a></li>
			<li><span>6</span> <a href="/Lyo/.NET">.NET</a></li>
			<li><span>4</span> <a href="/Lyo/2006">2006</a></li>

(略)

class名がbundle foldのliに注目した。liからul, liと辿れば取得したいデータにたどり着ける。
Web::Scraperを使ってコレを表現すると以下のようになる。

use URI;
use Web::Scraper;
use YAML::Syck;

my $delicious_tag = scraper {
    process 'a',
            tag => 'TEXT';
    process 'span',
            bookmark_count => 'TEXT';
    result qw(tag bookmark_count);
};

my $delicious = scraper {
        process 'li.bundle > ul > li',
            'tags[]' => $delicious_tag;
        result "tags";
};

my $res = $delicious->scrape( URI->new(shift) );
print Dump($res);

process に渡す引数がミソかねぇ。li.bundle > ul > liと対象をCSSセレクタで絞って複数取得する。(tags[]の部分。[]で複数指定。コレがないと一個しか取ってきてくれない。)
ソースで言うと

			<li><span>3</span> <a href="/Lyo/.htaccess">.htaccess</a></li>
			<li><span>6</span> <a href="/Lyo/.NET">.NET</a></li>
			<li><span>4</span> <a href="/Lyo/2006">2006</a></li>

の部分。あとは複数個のliの中身の部分を$delicious の上($delicious_tag)で定義した内容で処理する。そこでaタグとspanタグに分解して、タグに囲まれてる部分を取得するような感じ。ちなみに当初はli.bundleやtags[]といった記法の意味が全然分からなかったのだが、元々このモジュールはrubyのscrAPIにインスパイアされて作られたそうなので、記法はscrAPIのドキュメントを見ろと言うことらしい。ドキュメントのsee alsoからscrAPI Cheat Sheetに飛べる。後はコレを見てがんがります。

実行
perl perl my_del.icio.us_tag.pl http://del.icio.us/Lyo

---
-
bookmark_count: 3
tag: .htaccess
-
bookmark_count: 6
tag: .NET
-
bookmark_count: 4
tag: 2006
(中略)
-
bookmark_count: "? "
tag: cloud
-
bookmark_count: "? "
tag: freq
-
bookmark_count: "? "
tag: 2
-
bookmark_count: "? "
tag: hide

おっと、一番下のtag optionsまで拾ってしまった。htmlは一体どうなっているのだろうか?
<li class="bundle fold options"><h3 class="label"><span>tag options</span></h3>
<ul>
<li><span>» </span>view as <a href="?settagview=cloud">cloud</a> | list</li>
<li><span>» </span>sort by alpha | <a href="?settagsort=freq">freq</a></li>

li.bundleと表現すると、bundleから始まるクラス名全てを拾ってしまうらしい。optionのところもtagsと同じ構造なのでクラス名をbundle foldで完全一致させなければならない。ソースを修正する。

use URI;
use Web::Scraper;
use YAML::Syck;

my $delicious_tag = scraper {
    process 'a',
            tag => 'TEXT';
    process 'span',
            bookmark_count => 'TEXT';
    result qw(tag bookmark_count);
};

my $delicious = scraper {
        process 'li[class="bundle fold"] > ul > li',
            'tags[]' => $delicious_tag;
        result "tags";
};

my $res = $delicious->scrape( URI->new(shift) );
print Dump($res);

先程のソースで実行した結果をdump_listに、修正したソースで実行した結果をdump_list2に流した後、diff -u dump_list dump_list2 | lv -c

+++ dump_list3  Fri Oct 19 18:16:22 2007
@@ -3338,15 +3338,3 @@
 -
   bookmark_count: 1
   tag: "ネタ"
--
-  bookmark_count: "? "
-  tag: cloud
--
-  bookmark_count: "? "
-  tag: freq
--
-  bookmark_count: "? "
-  tag: 2
--
-  bookmark_count: "? "
-  tag: hide

素晴らしい。余計な情報が全て消えた。

今回はソースを直に追ったが、正直コレはツライ。ブラウザがFirefoxなら、いちいち目で追わなくてもCSSセレクタを一発で表示してくれる「Firebug」か「Web Developer」を入れるべきだろう。

それにしても約20行のソースでココまで出来てしまうのがスゴイ。正に巨人の肩に乗ってるような感じ。

トラックバック(0)

トラックバックURL: https://hoge.sub.jp/blog-cgi/mt/mt-tb.cgi/1354

このブログ記事について

このページは、Lyoが2007年10月19日 22:04に書いたブログ記事です。

ひとつ前のブログ記事は「PC作りたいと言っておきながら、未だに作っていない件。」です。

次のブログ記事は「これは素晴らしいhello! mr.monkey magic orchestra」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

月別 アーカイブ

OpenID対応しています OpenIDについて
Powered by Movable Type 7.9.3