読者です 読者をやめる 読者になる 読者になる

うめすこんぶ

日々のプログラミングで残しておきたいメモ.何かの役に立てれば幸いです.

Wikipediaのデータをダンプしてスクレイピングする方法(スクレイピング編)

ruby スクレイピング

スポンサーリンク

前回、Wikipediaの全ページをダンプする手順を書きました。今回は、調べたいページ本文をだして、実際にスクレイピングしてみる。とりあえず、「静岡県出身の有名人一覧」から有名人の名前だけ取り出してみる。これを応用すれば、何かの一覧ページだったら同じ方法で抽出可能。

流れ

  1. mysqlからページ本文を抽出
  2. mediawiki記法のページ本文をhtml形式に変換
  3. ogaを使用して本文を解析

mysqlからページ本文を抽出

前回で3つのテーブルを作成した。 1. page… ページのタイトルが入っているテーブル。 1. text ページの本文が入っている。 1. revision ページのid(page_id)と、ページ本文のid(old_id)の対応が入っている。

今回はすべて使って、textテーブルの本文を出してみる。

とりあえず、自分の見たいページのタイトルで検索して、ページの本文を手に入れる。 今回は、「静岡県出身の人物一覧」というページを検索する。

select page_id, page_title from page where page_title like "%静岡県出身の人物一覧%" limit 1;

以下の結果が出てくる。

+---------+--------------------------------+
| page_id | page_title                     |
+---------+--------------------------------+
|  125985 | 静岡県出身の人物一覧           |
+---------+--------------------------------+
1 row in set (3.08 sec)

今度は、page_idを元に、以下のコマンドで、ページ(静岡県出身の有名人一覧)の本文を手に入れる。 ${page_id}にはさっき見つけた125985を入れる。 ${page_title}は「静岡県出身の有名人一覧」。 今回は、"/tmp/${page_title}.wiki"というファイルに保存しているけど、拡張子とかは適当なので注意。

また、mysqlでファイルの保存をすると、どうゆうわけか、カレントディレクトリなどに保存してくれない。

select old_text from revision, text where rev_page = ${page_id} and rev_text_id = old_id INTO OUTFILE "/tmp/${page_title}.wiki" FIELDS TERMINATED BY ',';

mysqlでoutfileするときは、なぜか/tmpのディレクトリ以下にアウトプットするようにしないとうまくいかない。あまり、こうゆうので困ったと言う話を見ないのはなぜだろう。

参考: MySQLで、テーブルを丸ごとCSVで入出力する - INOHILOG

mediawiki記法のページ本文をhtml形式に変換

抽出した本文は、なんとmediawiki記法で書かれている!このままだと必要部分を取り出すのが少し手間。でも、ご安心を。pandocを使えば一発でhtmlに変換できる。

pandoc 静岡県出身の人物一覧.wiki -f mediawiki -t html -s -o 静岡県出身の人物一覧.wiki.html

pandocの使い方については、以下のページを参照のこと。此れ以外にも、markdownやemacsのorgファイルをhtmlやword、pdfに変換でき、非常に有用。ぜひいれることをおすすめする。 + Markdown - Pandocの比較的簡単なインストール方法 - Qiita

pandocのエラーになる場合があるが、エラー分にかかれたエラー行周辺を見て、適宜 {|などの囲いを消してやれば行ける。

自分は、以下のスクリプトをつかって、sedで不要な文字を消しつつhtml変換するようにした。 以下で、カレントディレクトリ内の.wiki拡張子のファイルすべてをhtmlに変換する。

sed -i "s/\\\\//g" *.wiki

for f in `ls *.wiki`; do
  echo $f
  pandoc $f  -f mediawiki -t html -s -o ${f}.html
done

sed -i "s/<p.*<\/p>//g" *.wiki.html
sed -i "s/<div.*/g" *.wiki.html
sed -i "s/.*<\/div>.*//g" *.wiki.html

綺麗でないのは勘弁!

ogaを使用して本文を解析

長かったけど、いよいよ解析!

rubyにて、ogaというスーパーライブラリを利用してスクレイピングする。今回はWikipediaのページの人物名だけを取り出してみる。人物名は、すべてリンクになっているので、htmlからa要素だけ取り出してやればいい。

ogaのインストールは以下。 以前、スクレイピングの記事でnokogiriを利用する方法を書いたけど、インストールで数時間悩んだ。それと比べると、ogaはすごく簡単!nokogiriの苦労はなんだったんだろうか。

gem install oga

ogaを使ってスクレイピングしてみる。

require 'oga'

src_path = "./静岡県出身の人物一覧.wiki.html" # 入力ファイル(html)のパス
dst_path = "./静岡県出身の人物一覧.csv" # 出力ファイルのパス

html = File.read(src_path)
oga = Oga.parse_html(html)

a_nodes = oga.css('body > ul a').map do |a|
  a.text # 人物名はリンク。リンクに該当するテキストのみ抽出
end

csv = a_nodes.join("\n") + "\n"
File.write(dst_path, csv)

結果は以下になる。

斎藤寿夫
静岡県知事
富士市
竹山祐太郎
建設大臣
磐田市
磐田郡
見付町
...

今回は簡易なrubyスクリプトで抽出したので、人物名以外の要素も入っている。ちゃんとスクレイピングしようと思うと、いろいろと工夫が必要になる。例えば、今回人物名とその人物のカテゴリ(政治家とか歌手)も対応付けようとしたが、結構苦労した。

これで、ひとまずWikipediaのスクレイピングについては以上。

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例