Organizationメンバーチームをスクレイピングしてランキングを作ってみた


SDTのQiita Organizationがますます熱くなってきました！
ということでなんとなくランキングを作ってみました〜(ということってどういうことだ!!)

## ソースコード

[nnsnodnb/sdt-qiita-ranking | GitHub](https://github.com/nnsnodnb/sdt-qiita-ranking)

## 公開ページサンプル

![スクリーンショット 2016-07-23 午前1.22.55.png](https://qiita-image-store.s3.amazonaws.com/0/97280/a4505cc6-e4d2-560a-d7bb-0e7168270abe.png "スクリーンショット 2016-07-23 午前1.22.55.png")

だいたいこんな感じ。大体...
まだはSDT内のものしか見れないですがこれから先、暇があるときにどのOrganizationでもランキングがとれるようにAPIを作ろうとか考えていたり考えていなかったり!!

## スクレイピング

### パッケージ

```requirements.txt
beautifulsoup4==4.5.0
bottle==0.12.9
Jinja2==2.8
MarkupSafe==0.23
```

Jinja2とかは使ったかどうか聞かないでください:;(∩´﹏`∩);:

### パッケージをインポートするお♪

```python
from urllib.request import urlopen
from bs4 import BeautifulSoup
```

### まとめる部分をまとめる

```python:get_soup()
url = 'http://qiita.com/organizations/smartdt/members'
html = urlopen(url)
return = BeautifulSoup(html, 'html.parser')
```

### メンバーリスト及びコントリビュート数

```python:get_contribution()
soup = get_soup()

contribution_array = {}
# organizationMemberList_itemクラスのliタグをすべて取得
members = soup.findAll('li', class_='organizationMemberList_item')

for member in members:
    # メンバーごとのaタグの1番目を取得
    a = member.find('a')
    # メンバーごとのorganizationMemberList_memberProfileクラスのdivタグの1番目を取得
    profiles = member.find('div', 'organizationMemberList_memberProfile')
    # 上で取得したdivタグの中からorganizationMemberList_memberStatsクラスのdivタグをすべて取得しその2番目を指定
    contribute = profiles.findAll('div', 'organizationMemberList_memberStats')[1]

    # a.attrs['href'] -> nnsnodnb
    name = a.attrs['href'].split('/')[1]
    # contribute.text -> 50 Contribution
    number = int(contribute.text.split(' Con')[0])
    
    contribution_array.update({name: number})
```

### メンバーアイコン

```python:get_membericon()
soup = get_soup()

icons = {}
# organizationMemberList_iconクラスのimgタグをすべて取得
member_icons = soup.findAll('img', 'organizationMemberList_icon')
# organizationMemberList_itemクラスのliタグをすべて取得
members = soup.findAll('li', class_='organizationMemberList_item')

for index in range(len(members)):
    a = members[index].find('a')
    name = a.attrs['href'].split('/')[1]
    # メンバーアイコンリストのそれぞれのメンバーごとからsrc属性を取り出す
    icon = member_icons[index].attrs['src']

    icons.update({name: icon})
```

**メンバーリスト及びコントリビュート数** と **メンバーアイコン**に関係を持たせるために今回は `name` をkeyにしました。

### ランキング順に並び替え

リストでは `key` と `value` の関係を持たせることができないので辞書を使っています。
しかし、辞書はあくまでも辞書なので順番バラバラで出力されます。泣きたい
ということで順番に取り出してリストに打ち込むという形を取ります。
また、ぶち込んだら昇順でデータが追加されているので `reverse()` を忘れずに

```python:ranking()
contribution = get_contribution()

names, numbers = [], []
for key, value in sorted(contribution.items(), key=lambda x:x[1]):
    names.append(key)
    numbers.append(value)
    
user_icons = get_membericon()

names.reverse()
numbers.reverse()
```

### templateに流し込む

今回はWebフレームワークに `Bottle` を使用しました。
使い方はググればたくさんでてくる！はず！

```python
from bottle import template, get, run
```

基本的にはこれでよいのじゃよ

```python:templateに流す
return template('hoge')
return template('foo', name = name)
```

だいたいこんな感じでやってればなんとかなる〜
`hoge` や `foo` のところはアプリケーションディレクトリに `views` フォルダを作って以下に `hoge.tpl` や `foo.tpl` などを作る！HTMLと同じです

`hoge.tpl` 内でPythonコードを実行する場合は `%` をつけて実行することが可能です。
また、 `template('foo', name = name)` のような場合は `hoge.tpl` 内に `{{ name }}` とすることで置き換えることができます。 ~~mustacheそのままですね。~~

また、 `for` や `if` を使ってループ等を終了させる場合は以下のようにするとできます

```tpl:forサンプル
% for i in range(10):
% # ターミナルに出力
% print(i)
% end
```

```tpl:ifサンプル
% if name == 'nnsnodnb':
% <p>やっほ〜！</p>
% else:
% <p>おめー誰だよｗｗｗｗｗ</p>
% end
```

やっぱりインデントないと気持ち悪いですね！！
もちろんインデントをつけて `hoge.tpl` を記述することも可能です

という感じでゆるふわコーディングすると公開ページサンプルのようなページができあがります。

### Bottle実行

```python:main()
run(host = '0.0.0.0')
```

```bash
$ python hoge.py
```

## まとめ

こんなものが存在してるだけでなんかみんなの戦闘力が可視化できて目標がゆるふわに可視化されてきました！

何かあればコメントや編集リクエスト等出していただければ幸いです！