久留米市人口データのスクレイピング
Webページから情報収集をしてくる処理をスクレイピングって言うらしい。シェル芸勉強会でもスクレイピングみたいなことをやった。
福岡県久留米市では、オープンデータカタログとして人口情報をCSVにて公開している。
ただ、過去の情報はExcel形式での公開。xlsx形式ならばエクシェル芸で捌けそうであるが、残念ながら旧形式のようだ。
平成25年より新しいデータについては、HTMLでWebページとして公開されている。ならばスクレイピングでCSVにした方が扱いやすいのでは?
ということで、人口情報が記載されたWebページからCSV作成して保存するスクレイピングなシェルスクリプトを作ってみた。パソコンはMac、OSはOSX Yosemiteだが、Linux、FreeBSDなどでも動くはず。
必要なコマンド
GNU系のツールについては、OSXやFreeBSDの場合は追加インストールしよう。Linuxの場合はgsed
をsed
と読み替えること。
- curl
- nkf
- GNU coreutils
- GNU sed
- GNU awk
では作成したスクリプトを順次紹介。実行するときは適当な一時ディレクトリを作成し、その中にスクリプトをコピペして保存して利用のこと。カレントディレクトリにCSVファイルがたくさん出来るので要注意。
WebページをCSVへ保存
久留米市の人口情報は下記のようなURLで、HTMLのTableを使って表現されている。
まずは中核となる、上記のようなWebページからCSVに保存するスクリプトを作成。スクリプトのファイル名はcsv_save.sh
。
#!/bin/sh curl $1 | nkf -wLux | sed -n '/<div id="content-otherpage">/,/<\/div>/p' | sed -n '/<table/,/<\/table>/p' | tr -d '\n' | gsed 's;</table>;&\n;' | head -n 1 | gsed 's;<caption>;\n&;' | gsed 's;<tr>;\n&;g' | tail -n +2 | sed 's/<[^<>]*>/ /g' | tr -d ',' | sed 's/^ *//' | sed 's/ *$//' | tr -s ' ' | sed '1s/ /_/' | sed '1s/ /_/' | awk 'NR==1{filename=$0}NR!=1{gsub(/ /,",",$0);print > filename".csv"}'
使い方はこちら。人口情報WebページのURLを指定して実行すると、TableのCaptionをファイル名としたCSVファイルに保存する。
$ ./csv_save.sh http://www.city.kurume.fukuoka.jp/1080shisei/2010shoukai/3040toukei/4030nenreijinkou/2015-0703-1719-442.html $ ls *.csv 年齢別人口_平成27年7月1日現在.csv $ head -n 5 年齢別人口_平成27年7月1日現在.csv 年齢,男,女,計 0,1512,1382,2894 1,1451,1486,2937 2,1516,1414,2930 3,1552,1409,2961 4,1592,1410,3002 5,1469,1437,2906 6,1446,1387,2833 7,1514,1397,2911 8,1460,1384,2844
WebページのURLリスト作成
人口情報へのURLリストは、下記のようなWebページになっている。
ここからリンクURLを抽出して一覧にするスクリプトを作成。スクリプトのファイル名はlist_url.sh
。
#!/bin/sh curl $1 | nkf -wLux | sed -n '/<div id="content-otherpage">/,/<\/div>/p' | sed -n '/<ul>/,/<\/ul>/p' | grep '^<li>' | grep -v '過去データ' | sed 's/<li><a href="\([^"]*\)".*$/\1/' | sed "s;^;$1;"
使い方はこちら。下記のWebページへのURLを指定して実行すると、人口情報WebページへのリンクURLを抽出する。一番下の「過去データ」はxls形式のデータだけなので外す。
$ ./list_url.sh http://www.city.kurume.fukuoka.jp/1080shisei/2010shoukai/3040toukei/4030nenreijinkou/ http://www.city.kurume.fukuoka.jp/1080shisei/2010shoukai/3040toukei/4030nenreijinkou/2015-0703-1719-442.html http://www.city.kurume.fukuoka.jp/1080shisei/2010shoukai/3040toukei/4030nenreijinkou/2015-0603-1706-442.html http://www.city.kurume.fukuoka.jp/1080shisei/2010shoukai/3040toukei/4030nenreijinkou/2015-0508-1537-442.html http://www.city.kurume.fukuoka.jp/1080shisei/2010shoukai/3040toukei/4030nenreijinkou/2015-0406-1701-442.html http://www.city.kurume.fukuoka.jp/1080shisei/2010shoukai/3040toukei/4030nenreijinkou/2015-0305-0957-442.html ....
これと先ほどのcsv_save.sh
を組み合わせることでCSVファイルを一括作成する。
実際に使うときは、連続でたくさんのURLにアクセスするとよくない気がするので、1秒毎に休みながら連続実行。
$ ./list_url.sh http://www.city.kurume.fukuoka.jp/1080shisei/2010shoukai/3040toukei/4030nenreijinkou/ | xargs -I {} sh -c './csv_save.sh {}; sleep 1' $ ls *.csv 年齢別人口_平成26年10月1日現在.csv 年齢別人口_平成26年8月1日現在.csv 年齢別人口_平成26年11月1日現在.csv 年齢別人口_平成26年9月1日現在.csv 年齢別人口_平成26年12月1日現在.csv 年齢別人口_平成27年1月1日現在.csv 年齢別人口_平成26年1月1日現在.csv 年齢別人口_平成27年2月1日現在.csv 年齢別人口_平成26年2月1日現在.csv 年齢別人口_平成27年3月1日現在.csv 年齢別人口_平成26年3月1日現在.csv 年齢別人口_平成27年4月1日現在.csv 年齢別人口_平成26年4月1日現在.csv 年齢別人口_平成27年5月1日現在.csv 年齢別人口_平成26年5月1日現在.csv 年齢別人口_平成27年6月1日現在.csv 年齢別人口_平成26年6月1日現在.csv 年齢別人口_平成27年7月1日現在.csv 年齢別人口_平成26年7月1日現在.csv
3種類の人口情報をまとめてCSV保存
久留米市の人口情報は、上記の年齢別だけでなく、校区別、町別でも公開されている。
上記3種類の人口情報を一括でCSV保存するスクリプトを作成。スクリプトのファイル名はkurume_getopendata_tocsv.sh
。
#!/bin/sh # 住民基本台帳 年齢別人口 # http://www.city.kurume.fukuoka.jp/1080shisei/2010shoukai/3040toukei/4030nenreijinkou/index.html # 住民基本台帳 校区別人口及び世帯数 # http://www.city.kurume.fukuoka.jp/1080shisei/2010shoukai/3040toukei/4010koukujinkou/index.html # 住民基本台帳 町別人口及び世帯数 # http://www.city.kurume.fukuoka.jp/1080shisei/2010shoukai/3040toukei/4020machijinkou/index.html cat <<EOF | http://www.city.kurume.fukuoka.jp/1080shisei/2010shoukai/3040toukei/4030nenreijinkou/index.html http://www.city.kurume.fukuoka.jp/1080shisei/2010shoukai/3040toukei/4010koukujinkou/index.html http://www.city.kurume.fukuoka.jp/1080shisei/2010shoukai/3040toukei/4020machijinkou/index.html EOF sed 's/index.html$//' | xargs -n 1 ./list_url.sh | xargs -I {} sh -c './csv_save.sh {}; sleep 1'
このスクリプトを実行すると、下記のようにたくさんのCSVファイルが出来る。
$ ./kurume_getopendata_tocsv.sh $ ls *.csv 年齢別人口_平成26年10月1日現在.csv 年齢別人口_平成26年11月1日現在.csv 年齢別人口_平成26年12月1日現在.csv .... 町別人口及び世帯数 平成26年10月1日現在.csv 町別人口及び世帯数 平成26年11月1日現在.csv 町別人口及び世帯数 平成26年12月1日現在.csv .... 校区別人口及び世帯数_平成26年10月1日現在.csv 校区別人口及び世帯数_平成26年11月1日現在.csv 校区別人口及び世帯数_平成26年12月1日現在.csv
作成してみて感想
最初のスクレイピング本体スクリプトcsv_save.sh
よりも、一覧作成してどうやって連続実行させるか?の方が意外と悩んでしまった。
上記のように、スクレイピングをする処理、URL一覧を作る処理をそれぞれコマンドにしてしまい、xargsで連続実行するというのがスッキリしていいのではないかと思う。
単機能なフィルタコマンドを作る。結局UNIX哲学に則るのが一番シンプルになるというのと実感したのであった。