Pythonを用いたWebScrapingとWordCloudを用いた可視化〜星野源さんを添えて〜

####星野源さんの歌詞はどういった単語が多く使われているのかを調べるために、Webスクレイピングを行った。<br>

Webスクレイピングは、Webサイトから情報を抽出する技術のこと。
<font color="red">＊ウェブサイトによってスクレイピングを拒否している場合があり、そういったサイトにスクレイピングを行うと処罰の対象となるため注意！アクセスしすぎも迷惑をかけるのでダメ！</font>

##今回の目標
Webスクレイピングで、星野源さん全曲の歌詞を取得し、シルエットに使用頻度の高い単語を当てはめる。
![hosino.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1470630/8ac24c75-803d-9bf9-3676-c28b921ba1f6.png)
####顔の輪郭では分からないかもしれないが、星野源さん

##参考サイト
<a href="https://qiita.com/Senple/items/1ad08b1a7ac9560bef62">米津玄師の歌詞をWordCloudで可視化してみた。(Qiita)
####かなり参考にさせてもらいました。

##ソースコードと雑談
昨年春に大学の先輩から作ってみればと言われた。
当時はPythonに初めて触れたので、見よう見まねで作成した。
１年経ってから備忘録を書くというなんともマヌケなものだが、折角の成果だから載せておく。

###1.サイトから星野源作詞・作曲の曲を全て抜き出す

```py 
import os
import re
import bs4
import time
import requests
import pprint

def load(url):
    res = requests.get(url)
    res.raise_for_status()

    return res.text

def pickup_tag(html, find_tag):
    soup = bs4.BeautifulSoup(str(html), 'html.parser')
    paragraphs = soup.find_all(find_tag)

    return paragraphs

def parse(html):
    soup = bs4.BeautifulSoup(str(html), 'html.parser')
    # htmlタグの排除
    kashi_row = soup.getText()
    kashi_row = kashi_row.replace('\n', '')
    kashi_row = kashi_row.replace('　', '')

    # 英数字の排除
    kashi_row = re.sub(r'[a-zA-Z0-9]', '', kashi_row)
    # 記号の排除
    kashi_row = re.sub(r'[ ＜＞♪`‘’“”・…_！？!-/:-@[-`{-~]', '', kashi_row)
    # 注意書きの排除
    kashi = re.sub(r'注意：.+', '', kashi_row)

    return kashi

def main():
    with open('hosino_kashi.txt', 'a') as f:
        # アーティストページのアドレス
        url = f'https://www.uta-net.com/artist/9867/'
        
        # 曲ページの先頭アドレス
        base_url = f'https://www.uta-net.com'

        # ページの取得
        html = load(url)

        # 曲ごとのurlを格納
        musics_url = []
        # 歌詞を格納
        kashis = ''

        """ 曲のurlを取得 """
        # td要素の取り出し
        for td in pickup_tag(html, 'td'):
            # a要素の取り出し
            for a in pickup_tag(td, 'a'):
                # href属性にsongを含むか
                if 'song' in a.get('href'):
                    # urlを配列に追加
                    musics_url.append(base_url + a.get('href')) 

        """ 歌詞の取得 """
        for i, page in enumerate(musics_url):
            print('{}曲目:{}'.format(i + 1, page))
            html = load(page)
            for div in pickup_tag(html, 'div'):
                # id検索がうまく行えなかった為、一度strにキャスト
                div = str(div)
                # 歌詞が格納されているdiv要素か
                if r'itemprop="text"' in div:
                    # 不要なデータを取り除く
                    kashi = parse(div)

                    print(kashi, end = '\n\n') 
                    # 歌詞を１つにまとめる
                    kashis += kashi + '\n'

                    # １秒待機
                    time.sleep(1)
                    break
        # 歌詞の書き込み
        f.write(kashis)

if __name__ == '__main__':
    main()
```
<li>1では、<a href="https://www.uta-net.com">歌ネット</li>からデータを取得し、歌詞データをテキストファイルに保存する。

###2. WordCloudを使用して、出てくる回数の多い単語を大きくして表示

```py
import MeCab
from matplotlib import pyplot as plt
from wordcloud import WordCloud

 # テキストファイル読み込み
with open('hoshino_kashi.txt', mode='rt', encoding='utf-8') as fi:
    source_text = fi.read()

 # MeCabの準備
tagger = MeCab.Tagger()
tagger.parse('')
node = tagger.parseToNode(source_text)

 # 名詞を取り出す
word_list = []
while node:
    word_type = node.feature.split(',')[0]
    if word_type == '名詞':
        word_list.append(node.surface)
    node = node.next

 # リストを文字列に変換
word_chain = ' '.join(word_list)

 #無意味そうな単語除去
stop_words = ['そう', 'よう', 'もの', 'こと', 'まま']
 # ワードクラウド作成
W = WordCloud(font_path='/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',
              width=640, height=480,
              background_color='white',
              colormap='bone',
              stopwords=set(stop_words)).generate(word_chain)

plt.imshow(W)
plt.axis('off')
plt.show()
```

![hoshino_rank.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1470630/85f51886-c5c6-480e-ed3c-babb94071d31.png)
ここまできたら、四角よりもシルエットに単語を並べた方が良いかなと思い・・・。
###~~写真からシルエットを出す方法を忘れた~~
###3.写真から顔面が青白い星野源さんを作成<br>
####OpenCVを用いた画像処理を施し、写真を青白くさせる。ここの調整が難しかった。<br>青白くならないと、綺麗なシルエットが出ない。<br>写真は肖像権に引っかかるかもしれないので、一応載せない。<br>（すみません・・・）<br>上半身がしっかり写っているものが良いと思われる。

```python
import cv2
import numpy as np
import matplotlib.pyplot as plt

BLUR = 21
CANNY_THRESH_1 = 10
CANNY_THRESH_2 = 100
MASK_DILATE_ITER = 10
MASK_ERODE_ITER = 10
MASK_COLOR = (1.0,0.0,0.0) 

img = cv2.imread('hoshino2.jpg') #青白くしたい画像
img1 = img[0 : 2100, 0: 2650]
gray = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)

edges = cv2.Canny(gray, CANNY_THRESH_1, CANNY_THRESH_2)
edges = cv2.dilate(edges, None)
edges = cv2.erode(edges, None)
contour_info = []
contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)

for c in contours:
        contour_info.append((
        c,
        cv2.isContourConvex(c),
        cv2.contourArea(c),
    ))
contour_info = sorted(contour_info, key=lambda c: c[2], reverse=True)
max_contour = contour_info[0]

mask = np.zeros(edges.shape)
cv2.fillConvexPoly(mask, max_contour[0], (255))

mask = cv2.dilate(mask, None, iterations=MASK_DILATE_ITER)
mask = cv2.erode(mask, None, iterations=MASK_ERODE_ITER)
mask = cv2.GaussianBlur(mask, (BLUR, BLUR), 0)
mask_stack = np.dstack([mask]*3) 
mask_stack = mask_stack.astype('float32') / 255.0    
img1 = img1.astype('float32') / 255.0   

masked = (mask_stack * img1) + ((1-mask_stack) * MASK_COLOR) 
masked = (masked*255).astype('uint8')  
plt.imshow(img_a)
plt.axis("off")
plt.show()
```
####<font color="red">スクリプトにコメントが無くてごめんなさい
####そのうち書きます。
 
###4.顔面が青白い星野源さんにWordCloudを適用
```py
from PIL import Image
import numpy as np
import MeCab
from matplotlib import pyplot as plt
from wordcloud import WordCloud
# テキストファイル読み込み
with open('hoshino_kashi.txt', mode='rt', encoding='utf-8') as fi:
    source_text = fi.read()
# MeCabの準備
tagger = MeCab.Tagger()
tagger.parse('')
node = tagger.parseToNode(source_text)
# 名詞を取り出す
word_list = []
while node:
    word_type = node.feature.split(',')[0]
    if word_type == '名詞':
        word_list.append(node.surface)
    node = node.next
 # リストを文字列に変換
 word_chain = ' '.join(word_list)
 #無意味そうな単語除去
 stop_words = ['そう', 'よう', 'もの', 'こと', 'まま', 'これ', 'それ']
 def get_wordcrowd_mask( word_chain, imgpath ):
    img_color = np.array(Image.open( imgpath ))
    wc = WordCloud(font_path='/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',
                   mask=img_color,
                   collocations=False, # 単語の重複しないように
                   stopwords=set(stop_words),
                   background_color='white',
                   contour_width=3,
                   contour_color='black'
                  ).generate( word_chain )
  # show
    plt.figure(figsize=(6,6), dpi=200, facecolor='white')
    plt.imshow(wc)
    plt.axis("off")
    plt.show()
```
####顔面が青白いとWordCloudを適用した際に、顔の輪郭がしっかり出る
![hosino.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1470630/c9afedcc-55e1-b723-eee1-ba5ad8f3cf6a.png)
####星野源さんの曲は、日常や身近な人を歌っていることが多いのかなと思う。