HTML の表をスクレイピングするのは結構だるい作業です。
私は以前は、単純な HTML であれば、うまく特徴を見つけて awk や sed を作ったり、
Perl の正規表現で取り出したり、 Google Chrome のコンソールから XPath を使って取り出すような苦労をやっていました。
ところで pandas というとデータ解析用のツールとして主流ではあるのですが、
意外にも HTML からのデータ入力も可能になっていて、これが表のスクレイピングにはかなり楽だということがわかりました。
なので紹介してみます。
サンプルに使うページ
以下で示すサンプルに国税庁の所得税の税率のページを使うことにしました。
https://www.nta.go.jp/taxes/shiraberu/taxanswer/shotoku/2260.htm
(2019.9.28 移転したようなので、URLを修正しました)
こんな感じの表があります。
<table width="99%" border="1" cellpadding="5" cellspacing="0" class="datatable">
<caption>
所得税の速算表
</caption>
<tr>
<th width="62%" scope="col"> 課税される所得金額</th>
<th width="13%" scope="col"> 税率</th>
<th width="25%" scope="col"> 控除額</th>
</tr>
<tr>
<th align="left" scope="row"> 195万円以下</th>
<td align="center"> 5%</td>
<td align="right"> 0円</td>
</tr>
<tr>
<th align="left" scope="row"> 195万円を超え 330万円以下</th>
<td align="center"> 10%</td>
<td align="right"> 97,500円</td>
</tr>
<tr>
<th align="left" scope="row"> 330万円を超え 695万円以下</th>
<td align="center">20%</td>
<td align="right">427,500円</td>
</tr>
<tr>
<th align="left" scope="row"> 695万円を超え 900万円以下</th>
<td align="center">23%</td>
<td align="right">636,000円</td>
</tr>
<tr>
<th align="left" scope="row"> 900万円を超え 1,800万円以下</th>
<td align="center"> 33%</td>
<td align="right"> 1,536,000円</td>
</tr>
<tr>
<th align="left" scope="row"> 1,800万円を超え4,000万円以下</th>
<td align="center"> 40%</td>
<td align="right"> 2,796,000円</td>
</tr>
<tr>
<th align="left" scope="row"> 4,000万円超</th>
<td align="center"> 45%</td>
<td align="right"> 4,796,000円</td>
</tr>
</table>
また使用した Python のバージョンは 3.4.2 です。
インストール
$ pip install pandas lxml html5lib BeautifulSoup4
pip を使ってインストールします。
pandas だけでなく read_html が使うパッケージも lxml, html5lib, BeautifulSoup4 をインストールする必要があります。
実際に使用
以下ではインタラクティブシェル上での挙動を説明します。
インポート
$ python3
>>> import pandas
読み取り
>>> url = 'https://www.nta.go.jp/taxanswer/shotoku/2260.htm'
>>> fetched_dataframes = pandas.io.html.read_html(url)
たった 2 行でスクレイピングは終わりです。
- URL を指定
- pandas.io.html.read_html で URL を読み取る
これだけ。
それぞれの表にアクセス
取得した表はリストと同じようにインデクスでアクセスできます。
>>> fetched_dataframes[0]
0 1 2
0 課税される所得金額 税率 控除額
1 195万円以下 5% 0円
2 195万円を超え 330万円以下 10% 97,500円
3 330万円を超え 695万円以下 20% 427,500円
4 695万円を超え 900万円以下 23% 636,000円
5 900万円を超え 1,800万円以下 33% 1,536,000円
6 1,800万円超 40% 2,796,000円
>>> fetched_dataframes[1]
0 1 2
0 課税される所得金額 税率 控除額
1 195万円以下 5% 0円
2 195万円を超え 330万円以下 10% 97,500円
3 330万円を超え 695万円以下 20% 427,500円
4 695万円を超え 900万円以下 23% 636,000円
5 900万円を超え 1,800万円以下 33% 1,536,000円
6 1,800万円を超え 4,000万円以下 40% 2,796,000円
7 4,000万円超 45% 4,796,000円
>>> fetched_dataframes[2]
0 1 2
0 課税される所得金額 税率 控除額
1 330万円以下 10% 0円
2 330万円を超え 900万円以下 20% 330,000円
3 900万円を超え 1,800万円以下 30% 1,230,000円
4 1,800万円超 37% 2,490,000円
>>>
保存
もちろんこのままでも pandas のデータフレームとして [色々と便利なアクセスが可能] (http://pandas.pydata.org/pandas-docs/dev/comparison_with_sql.html) なのですが、他の言語やフレームワークとの連携も考え CSV ファイルでの保存も説明します。
pandas のデータフレームの保存方法が使えるので、 to_csv メソッドにファイル名を指定すれば保存できます。
>>> fetched_dataframes[0].to_csv('heisei19to26.csv')
>>> fetched_dataframes[1].to_csv('heisei27to.csv')
>>> fetched_dataframes[2].to_csv('heisei11to18.csv')
,0,1,2
0,課税される所得金額,税率,控除額
1,195万円以下,5%,0円
2,195万円を超え 330万円以下,10%,"97,500円"
3,330万円を超え 695万円以下,20%,"427,500円"
4,695万円を超え 900万円以下,23%,"636,000円"
5,"900万円を超え 1,800万円以下",33%,"1,536,000円"
6,"1,800万円を超え 4,000万円以下",40%,"2,796,000円"
7,"4,000万円超",45%,"4,796,000円”
超便利。
免責
引用したデータは国税庁が持つデータです。筆者は解説のために引用したのみで、
筆者は記載している税率についての正誤・法的な責任は負いません。