ガルパのスクレイピングをはじめよう～『Python編』

# ガルパの画像をなるべく集めていきたい...
ソーシャルゲームとかで画像を集めていく場合、インターネット上でPCのブラウザで右クリックで保存したり、ゲームの画像をスクショで保存したり、SNSで公開されている画像を保存したりと、自分で探して画像を保存する必要があります。しかし、それだと自分が見逃した場合、新しいキャラクターの画像や新衣装の画像を取り逃してしまったり、取り逃してしまった画像も集めようとした場合、時間がかかってしまうこともあります...    
そのため、自動化していきたいです...('ω')

# そうだ、スクレイピングをしよう(´・ω・)
せっかくプログラミングに触れているので活用するしかないということで、Pythonで 『バンドリ！ ガールズバンドパーティ！』のキャラクターの画像を自動で保存するプログラムを作成していこうと思います。ガルパの画像をスクレイピングしていく上で、対象のサイトして以下のサイトでまとめられているので利用させていただきます(/・ω・)/

- [バンドリ！ ガールズバンドパーティ！DB【ガルパDB】](http://bangdream.gamedbs.jp/)

# 動作環境
- Windows10 Pro
- Docker on Ubuntu1604 LTS on VirtualBox(Vagrant)
- Python 3
- Jupyter Notebook

# URLの情報を取得する
まず、URLの情報を取得します。今回、BeautifulSoupというライブラリを使って必要なURLの文字列を選択して取得していくようにしています。何も考えずに適当に要素を選択すると以下のように書けます。

```Python
import os
import requests
from bs4 import BeautifulSoup
from urllib.request import urlopen

url = 'http://bangdream.gamedbs.jp/'
pre_r = requests.get(url)

pre_soup = BeautifulSoup(pre_r.text,'lxml')
urls = pre_soup.find_all('a')

print(urls)
```
## 出力結果
![127.0.0.1_8888_notebooks_test.ipynb.png](https://qiita-image-store.s3.amazonaws.com/0/331462/b0be0ce2-3abd-36d7-ea29-6dcf4fd8f48d.png)

# 取得した情報から欲しい情報を抽出していく
次に取得した情報から必要な部分を抽出します。今回取得したいのは画像ファイルのリンクの文字列ですが、例としてキャラクターの名前の要素を取得してみました。

```Python
import os
import time
import requests
import re
import uuid
from bs4 import BeautifulSoup
from urllib.request import urlopen

url = 'http://bangdream.gamedbs.jp/'
pre_r = requests.get(url)

pre_soup = BeautifulSoup(pre_r.text,'lxml')
urls = pre_soup.find_all('a', href=re.compile('^http://bangdream.gamedbs.jp/chara/show'))

for url in urls:
    print(url['title'])
```
## 出力結果
![127.0.0.1_8888_notebooks_test.ipynb (1).png](https://qiita-image-store.s3.amazonaws.com/0/331462/765edd81-7509-8141-d14a-e1a41a0b10f9.png)

# キャラクターごとにURLを管理する
今回の対象となるサイトはキャラクターごとにリンクで画像がまとめられていたので、名前とURLを対応するように辞書でURLを管理しました(*‘ω‘ *) いつかはデータベースで管理するように改良していきたいですね～(>_<)

```Python

characters = {
    "kasumi_toyama":     "http://bangdream.gamedbs.jp/chara/show/11/",
    "tae_hanazono":      "http://bangdream.gamedbs.jp/chara/show/10/",
    "rimi_ushigome":     "http://bangdream.gamedbs.jp/chara/show/25/",
    "saaya_yamabuki":    "http://bangdream.gamedbs.jp/chara/show/24/",
    "arisa_ichigaya":    "http://bangdream.gamedbs.jp/chara/show/23/",
    "ran_mitake":        "http://bangdream.gamedbs.jp/chara/show/22/",
    "moka_aoba":         "http://bangdream.gamedbs.jp/chara/show/9/",
    "himari_uehara":     "http://bangdream.gamedbs.jp/chara/show/21/",
    "tomoe_udagawa":     "http://bangdream.gamedbs.jp/chara/show/8/",
    "tsugumi_hazawa":    "http://bangdream.gamedbs.jp/chara/show/20/",
    "kokoro_tsurumaki":  "http://bangdream.gamedbs.jp/chara/show/7/",
    "seta_kaoru":        "http://bangdream.gamedbs.jp/chara/show/19/",
    "hagumi_kitazawa":   "http://bangdream.gamedbs.jp/chara/show/6/",
    "kanon_matsubara":   "http://bangdream.gamedbs.jp/chara/show/18/",
    "misaki_okuzawa":    "http://bangdream.gamedbs.jp/chara/show/12/",
    "aya_maruyama":      "http://bangdream.gamedbs.jp/chara/show/5/",
    "hina_hikawa":       "http://bangdream.gamedbs.jp/chara/show/17/",
    "chisato_shirasagi": "http://bangdream.gamedbs.jp/chara/show/4/",
    "maya_yamato":       "http://bangdream.gamedbs.jp/chara/show/16/",
    "eve_wakamiya":      "http://bangdream.gamedbs.jp/chara/show/3/",
    "yukina_minato":     "http://bangdream.gamedbs.jp/chara/show/15/",
    "sayo_hikawa":       "http://bangdream.gamedbs.jp/chara/show/2/",
    "risa_imai":         "http://bangdream.gamedbs.jp/chara/show/14/",
    "ako_udagawa":       "http://bangdream.gamedbs.jp/chara/show/1/",
    "rinko_shirogane":   "http://bangdream.gamedbs.jp/chara/show/13/"
}
```
# 最終版
自分がやりたいように記述したら以下のようになりました...サイトや取得したい対象によって指定の仕方が変わっていくので、まずはライブラリを実際に使ってみるのがいいかもしれません(/・ω・)/    

```Python
import os
import time
import requests
import re
import uuid
from bs4 import BeautifulSoup
from urllib.request import urlopen

characters = {
    "kasumi_toyama":     "http://bangdream.gamedbs.jp/chara/show/11/",
    "tae_hanazono":      "http://bangdream.gamedbs.jp/chara/show/10/",
    "rimi_ushigome":     "http://bangdream.gamedbs.jp/chara/show/25/",
    "saaya_yamabuki":    "http://bangdream.gamedbs.jp/chara/show/24/",
    "arisa_ichigaya":    "http://bangdream.gamedbs.jp/chara/show/23/",
    "ran_mitake":        "http://bangdream.gamedbs.jp/chara/show/22/",
    "moka_aoba":         "http://bangdream.gamedbs.jp/chara/show/9/",
    "himari_uehara":     "http://bangdream.gamedbs.jp/chara/show/21/",
    "tomoe_udagawa":     "http://bangdream.gamedbs.jp/chara/show/8/",
    "tsugumi_hazawa":    "http://bangdream.gamedbs.jp/chara/show/20/",
    "kokoro_tsurumaki":  "http://bangdream.gamedbs.jp/chara/show/7/",
    "seta_kaoru":        "http://bangdream.gamedbs.jp/chara/show/19/",
    "hagumi_kitazawa":   "http://bangdream.gamedbs.jp/chara/show/6/",
    "kanon_matsubara":   "http://bangdream.gamedbs.jp/chara/show/18/",
    "misaki_okuzawa":    "http://bangdream.gamedbs.jp/chara/show/12/",
    "aya_maruyama":      "http://bangdream.gamedbs.jp/chara/show/5/",
    "hina_hikawa":       "http://bangdream.gamedbs.jp/chara/show/17/",
    "chisato_shirasagi": "http://bangdream.gamedbs.jp/chara/show/4/",
    "maya_yamato":       "http://bangdream.gamedbs.jp/chara/show/16/",
    "eve_wakamiya":      "http://bangdream.gamedbs.jp/chara/show/3/",
    "yukina_minato":     "http://bangdream.gamedbs.jp/chara/show/15/",
    "sayo_hikawa":       "http://bangdream.gamedbs.jp/chara/show/2/",
    "risa_imai":         "http://bangdream.gamedbs.jp/chara/show/14/",
    "ako_udagawa":       "http://bangdream.gamedbs.jp/chara/show/1/",
    "rinko_shirogane":   "http://bangdream.gamedbs.jp/chara/show/13/"
}

def my_makedirs(path):
    if not os.path.isdir(path):
        os.makedirs(path)

def main():
    for k, v in characters.items():
        
        url = str(v)

        dirs_card = './workspace/bangdream/' + str(k) + '/card'
        my_makedirs(str(dirs_card))
        dirs_sd = './workspace/bangdream/' + str(k) + '/sd'
        my_makedirs(str(dirs_sd))
        dirs_live2d = './workspace/bangdream/' + str(k) + '/live2d'
        my_makedirs(str(dirs_live2d))
        
        pre_r = requests.get(url)
        if pre_r.status_code == 404:
            continue
        else:
            pre_soup = BeautifulSoup(pre_r.text,'lxml')
            urls = pre_soup.find_all('a', href=re.compile('^http://bangdream.gamedbs.jp/chara/show/'))
        
        for url in urls:
            r = requests.get(url['href'])
            if r.status_code == 404:
                continue
            else:
                soup = BeautifulSoup(r.text,'lxml')
                imgs1 = soup.find_all('a', href=re.compile('^http://bangdream.gamedbs.jp/images/chara/card'))
                imgs2 = soup.find_all('a', href=re.compile('^http://bangdream.gamedbs.jp/images/chara/livesd'))
                imgs3 = soup.find_all('span', class_ ='swimg sbtn radius animated')
              
                for img in imgs1:
                    print(img['href'])
                    r = requests.get(img['href'])
                    tmp = img['href'].split('/')
                    with open(dirs_card + '/' + tmp[-1],'wb') as file:
                        file.write(r.content)

                for img in imgs2:
                    r = requests.get(img['href'])
                    tmp = img['href'].split('/')
                    with open(dirs_sd + '/' + tmp[-1],'wb') as file:
                        file.write(r.content)

                for img in imgs3:
                    r = requests.get(img['data-img-url'])
                    tmp = img['data-img-url'].split('/')
                    with open(dirs_live2d + '/' + tmp[-1],'wb') as file:
                        file.write(r.content)
                
if __name__ == '__main__':
	main()
```
# 実行結果
Jupyter  Notebookで実行しているので、以下のように実行結果が表示されていきます...やったね！(*'ω'*)！

![111111.JPG](https://qiita-image-store.s3.amazonaws.com/0/331462/49e82a6c-2f26-0702-ea9b-486349451b1e.jpeg)
![11111111.JPG](https://qiita-image-store.s3.amazonaws.com/0/331462/46ac1eae-396c-d1b6-f9eb-69cf0447a83a.jpeg)

以上となります。スクレイピングについて禁止されているサイトなどもあります。そのあたりは自己責任となりますので、ご注意ください('ω') 
また、取得した情報（画像や数値など色々）について私用の範囲で利用してください(/・ω・)/