日本酒が美味しい県へ旅行に行くために~スクレイピングとD3.jsによる可視化(その1)~

#動機
1．日本酒が美味しい所に旅行行きたい！(できれば海の日3連休に)
2．スクレイピングの勉強会に参加して、わくわくしたのでやってみたい
3．D3.jsに以前から興味があった

#処理概要
1. スクレイピングでデータ取得
2. データ加工
3. D3.jsで日本地図描画　　　　　　　　　　　( ←今回ここまで )
4. 描画した日本地図にスクレイピングでとってきたデータを反映
5. 結果を見て目的地を決めて旅行に行って美味しい日本酒を飲んでくる

※可視化はすでにやっている方がいらっしゃいました。素晴らしい。。
http://gonomee.com/topics/alpha_ranking/


#スクレイピングとは
※混同されがちな言葉にクローリングがある

- クローリング・・・リンクを辿ってWebページを収集すること
- スクレイピング・・・収集したWebページから必要な情報を抜き出すことを指す（両者を区別せず使うことも多いらしい）

**スクレイピングを行う上での注意点**

- スクレイピングしたデータの使用目的や方法によっては、情報公開元に迷惑をかけたり、場合によっては法に触れることもある
- 以下のページを読み誰にも迷惑をかけないWebスクレイピングを心がけるべし
    - [Webスクレイピングの注意事項一覧](http://qiita.com/nezuq/items/c5e827e1827e7cb29011)

- APIが提供されている場合はそちらを利用する
- サイトの利用規約を確認する
- robots.txtを確認する
    - 大体のサイトに用意されているらしい。取得したいサイトのトップページのURLの末尾にrobots.txtをつけて確認
- Webサイトに負荷をかけないようにアクセスする
    - sleepを入れて行うらしい←未学習

**スクレイピングの大まかな手順**

1. スクレイピングを行いたいページを取得する
2. ページのDOMツリーを確認する
3. 欲しいデータを抽出する

今回は「日本酒　都道府県　ランキング」でぐぐってTOPに出てきた日本酒ランキングのページを取得してきたいと思います。
(http://www.sakeno.com/ranking/)

```scraping.py
# -*- coding:utf-8 -*-
import pandas as pd
import requests
from bs4 import BeautifulSoup
import re

#抽出してきたタグを含む文字列から必要な単語のみをとってくる関数
def str_select(tag_name):
    str_list = []
    for name in tag_name:
        str_list.append('{name}'.format(name=name.string))
    return str_list

#WEBページのHTMLをgetし、ファイルとして保存
res = requests.get('http://www.sakeno.com/ranking/') #Response オブジェクト
with open('nihonsyu_ranking.html', 'wb') as f:
    f.write(res.content)

#WEBページの文字コードを確認して、encoding指定してHTMLを読み込む
html = open('nihonsyu_ranking.html',encoding='EUC-JP').read()
soup = BeautifulSoup(html, 'html.parser')

#欲しい情報が構成されているHTMLタグを指定して、データをとってくる
#銘柄名
meigara = soup.find_all("strong", attrs={"class":"lrg"})
#都道府県名
tmp_pref = soup.find_all("td", attrs={"class":"smll"})
pref = []
for row in tmp_pref:
    pref += row.find_all("a", attrs={"href":re.compile("http://www.sakeno.com/ranking_todou/")})

#とってきたタグを含む文字列から欲しい単語のみを抽出
meigara_list = str_select(meigara)
pref_list = str_select(pref)
rank_list = []
for i in range(1,len(meigara_list)+1):
    rank_list.append(i)

#結果をデータフレーム化
output = pd.DataFrame()
output["meigara"] = meigara_list
output["pref"] = pref_list
output["rank"] = rank_list

#出力
output.to_csv('meigara_pref_rank.csv', index=False)
```

取得したデータ

|meigara|pref|rank|
|-------|----|----|
|獺祭    |山口県|1|
|十四代|山形県|2|
|醸し人九平次|愛知県|3|
|黒龍|福井県|4|
|田酒|青森県|5|
|久保田|新潟県|6|
|出羽桜|山形県|7|
|飛露喜|福島県|8|
|八海山|新潟県|9|
|鳳凰美田|栃木県|10|
|〆張鶴|新潟県|11|
|...|...|...|
|麒麟|新潟県|190|
|酒一筋|岡山県|191|
|不老泉|滋賀県|192|
|花泉|福島県|193|
|米鶴|山形県|194|
|吉乃川|新潟県|195|
|翠露|長野県|196|
|三井の寿|福岡県|197|
|おんな泣かせ|静岡県|198|
|五橋|山口県|199|
|越州|新潟県|200|

#データ加工
- 都道府県毎に銘柄数をカウント
※データ量が少ないのでExcelで加工

|state|value|
|---|---|
|新潟県|20|
|福島県|16|
|山形県|15|
|広島県|11|
|秋田県|10|
|宮城県|9|
|静岡県|9|
|長野県|9|
|兵庫県|7|
|岩手県|6|
|石川県|6|
|茨城県|5|
|...|...|
|香川県|1|
|山梨県|1|
|神奈川県|1|
|千葉県|1|
|徳島県|1|
|奈良県|1|

データの準備は整った。
次は可視化の準備に取り掛かります！

#[D3.js](http://ja.d3js.node.ws/)とは
- Data Driven Documentの略
- JavaScriptライブラリ
- HTMLや SVG,CSSを使ってデータに命を吹き込んでくれる
- ブラウザ上で動かせる
- とにかくおしゃれ

事例紹介

- [Songrium](http://yt.songrium.jp/map/)
- [各都道府県の有効求人倍率と充足度](http://shimz.me/example/d3js/geo_example/geo8/)
- [アメリカにおける死亡要因](http://www.bloomberg.com/graphics/dataview/how-americans-die/)
- [機械学習のフローを可視化](http://www.r2d3.us/visual-intro-to-machine-learning-part-1/)


#日本地図を描画する

``` japan_plot.html
<!DOCTYPE html>
	<html lang ="ja">
		<head>
		<meta charset="utf-8">
		<script type="text/javascript" src="d3.min.js"></script>
		<script type="text/javascript" src="topojson.min.js"></script>
	<style>![Invalid file type: text/html]()

		body { background-color:LightCyan;}
	</style>
	</head>
	<body>
	<div id='example'></div>
	<script src="japan_plot.js"></script>
</body>
</html>
```


``` japan_plot.js
    //svg要素の設定
    var width = 600,
    height = 500;

    //D3を使ってsvg要素を生成し、中身を追加していく
    var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);
     
    var color = d3.scale.category20();

    // 地図描画の準備 
    // 投影法(メルカトル法)の設定。
    var mercator = d3.geo.mercator()
        .center([136.0,35.6])
        .translate([width/2, height/2])
        .scale(800);
     
    // geojsonからpath要素を作るための設定
    var geopath = d3.geo.path()
    .projection(mercator);
     
    // topojsonファイルの読み込み
    d3.json("japan_topojson.json", function(error, jp) {
        console.log(jp);
         
        // topojsonからgeojsonへの変換。
        var geoJp = topojson.feature(jp, jp.objects.ne_10m_admin_1_states_provinces);
        console.log(geoJp);
         
        svg.selectAll("path")
            .data(geoJp.features) // geojsonのすべての県の座標データを読み込む。
          .enter().append("path")
            .attr("class", function(d) { return d.id; })
            .attr("d", geopath) // geojsonからpath要素に変換する。
            .attr("fill", function(d){ return color(d.geometry.coordinates); }); // idがないので、各県の座標リストに基づいて色を変える。
    });
```

日本地図描画できた。
<img width="500" alt="japan.png" src="https://qiita-image-store.s3.amazonaws.com/0/132984/8d2ace81-6969-f0fd-a0e1-36314cb20bb3.png">

#今後
- csvファイルを日本地図に反映する(そして旅行にいく)
- クローリングして取得するデータを増やしてみる
- 自分の好きな日本酒の味などをキーワードにして自分好みの日本酒MAPにする
- D3.js使っていろいろ可視化してみる
- amd more...


#D3.jsを使った地図可視化の他の方法のご紹介
- Python(もしくはR)でleaflet
    - JS書かなくていい
    - ナレッジ豊富
- ツールを使う
    - http://blockbuilder.org/
    - http://blockbuilder.org/n1n9-jp/e515f3df49957efc8693b746fdaf7bc8
    - てっとり早そう
    - ブラウザ上でコーディングできるツール



#参考にさせて頂いたサイト
- http://www.tam-tam.co.jp/tipsnote/javascript/post6174.html
- http://dataisfun.org/2014/06/02/?p=444

ありがとうございます。