見出し画像

ヨルシカの歌詞でWordCloudやってみた

タイトルの通りヨルシカの歌詞を使ってWordCloudを利用し単語の頻出具合を可視化してみました。

今回の成果物

以下画像はWordCloudで作成される単語頻出具合を可視化したものです。

ヨルシカ歌詞の取得

今回ヨルシカの歌詞をWebスクレイピングにて取得しました。
歌詞データに関しては以下サイトを利用しました。

参考サイト:Uta-Net
https://www.uta-net.com/artist/22653/

コードとしてはまず初めに必要なモジュールのインポートから始めます。
今回は以下モジュールを利用しました。
(コードの変数名等至らない点あるかと思いますが、ご了承ください…)

import requests
from bs4 import BeautifulSoup
import time

こちらでURLを利用するときは以下URLを基準に操作します。
URL:https://www.uta-net.com/song/

それぞれの歌詞に関してのURLは以下のような法則が存在しています。
https://www.uta-net.com/song/歌詞番号

そこでそれぞれの歌詞番号をリストに格納しfor文を回して処理をしていけば良さそうです。
※Webスクレイピングをする際はサーバーへの負荷を軽減させるためにfor文等を回すときはtimeモジュールを利用し処理が終わるごとに1秒程度処理を止める必要があります。

sites = ['348205','343679','337012','335430','335429','335428','335427','335426','335425','335424','333757','331316','330679','323380','321620','319680','308234','306198','302605',
         '296971','296970','296138','291826','288473','288472','288471','288470','288012','286906','286044','284491','282379','272763','272762','272761','272760','272759','272758',
         '272757','272756','271759','269616','265902','265901','265900','265899','265898','265897','265896','265895','264894','261309','248499','248498','248496','248495','247424',
         '247423','232390','232389','232388','232387','232386']
URL = 'https://www.uta-net.com/song/'
file_number = 0

for elem in sites:
    print(elem+"の処理開始")
    URLs = URL + elem
    response = requests.get(URLs)
    html = response.text

    soup = BeautifulSoup(html, "html.parser")
    texts = soup.select('#kashi_area')

    #テキストファイルに出力 
    for text in texts:
        f = open(f'./texts/{file_number}.txt','w',encoding='UTF-8')
        f.write(str(text))
        f.close()
    file_number += 1
    URLs=''
    print(elem+"の処理完了")
    time.sleep(1)

print("処理完了")

初めに歌詞番号をリストに格納しています。
for文では、検証(F12)にて確認できるhtmlの中のid=kashi_areaの要素を抽出しています。このidが所謂歌詞データです。
その後取得した歌詞データを任意のフォルダにテキストファイルとして出力しています。

これで歌詞データは取得できたのですが、この状態では<div>タグ等歌詞としては不要なものが存在しています。そこで出力したテキストデータを修正します。

for i in range(0,63):
    print(str(i)+"番目処理開始")
    
    with open(f'./texts/{i}.txt',encoding='UTF-8') as f:
        read_file = f.read()
        print(read_file)
    change_text = read_file.replace(' ','')
    change_text=change_text.replace('</div>','')
    print(change_text)
    with open(f'./texts/{i}.txt',mode="w",encoding='UTF-8') as f:
        f.write(change_text)
    print(str(i)+"番目処理完了")
print('処理完了')

こちらでは「数値.txt」で作成したテキストファイルを1つずつ開き不要なものを順に削除しています。

私は歌詞データをDBから取得したいと考えたのでこのテキストデータをSQLServerに保存して使うようにしました。

必要なモジュールのインポート

from wordcloud import WordCloud
from janome.tokenizer import Tokenizer
import pyodbc
import datetime

pythonとSQLServerを接続

pythonとSQLServerを接続する際はpyodbcモジュールを利用し接続しました。接続の設定などは以下Qitaの記事を参考にしました。
【参考】https://qiita.com/wiskerpaddy/items/4268dfab09a6c53a64d1

def lyrics(songs):
    texts = []
    driver = '{SQL Serverh'
    server = 'ホスト名'
    database = 'データベース名'
    trusted_connection = 'yes'
    connect = pyodbc.connect('DRIVER='+driver+';SERVER='+server+';DATABASE='+database+';PORT=1433;Trusted_Connection='+trusted_connection+';')
    for i in songs:
        cursor = connect.cursor()
        #print (i)
        cursor.execute(f"SELECT 歌詞1,歌詞2 FROM [KARAOKE_DB].[dbo].[TB_yorushika] WHERE [曲名(漢字)] = '{i}'")
        rows = cursor.fetchall()
        texts.append(rows)
        cursor.close()
    connect.close()
    lyrics_texts = []
    for i in texts:
        for j in i:
            T = str(j)
            lyrics_texts.append(T)
    return lyrics_texts

こちらでPythonとSQLServerを接続し歌詞をSELECTしています。そして歌詞データをリストに格納しリストデータを返しています。

janomeを利用し品詞ごとに分解

def before_change(text):
    words_list = []
    tk = Tokenizer()
    hinshi = ['名詞','形容詞','動詞','副詞','感動詞','形容動詞','感動詞']
    for i in text:
        for j in hinshi:
            for token in tk.tokenize(i):
                if token.part_of_speech.split(",")[0] == j:
                    words_list.append(token.surface)
    return words_list

こちらではjanomeを利用して品詞分解を行っています。そして品詞ごとに得られた単語をwords_listリストに格納しこちらを返しています。

def after_token(token_list):
    delet_words = ["('","',","'","')"]
    for token in token_list:
        for del_word in delet_words:
            if token == del_word:
                token_list.remove(del_word)
    return token_list

先ほど作成したwords_listでは不要な文字として「(」や「'」などが存在しているのでそういった文字列を削除し純粋な単語のみのリストを作成し返しています。

WordCloud

def wordcloud_maker(wordlist):
    font = 'フォントパス'
    colormap="Paired"
    texts = ''
    texts = ' '.join(wordlist)
    wc = WordCloud(background_color="white",
                   width=900,
                   height=500,
                   font_path=font).generate(texts)
    return wc

こちらにてWordCloudを実施しています。初めに出した画像のようなフォントを利用したい場合は「春夏秋冬Ⅱ」フォントを利用してください。
現状単語はリストに格納しているのでリストから文字列にします。

WordCloudの実行

i = int(input('曲数を入力してください'))
songs = []
for j in range(i):
    print(j+1,"曲目")
    song = input('曲名を入力してください。')
    songs.append(song)

text = lyrics(songs)
token = before_change(text)
aft_token = after_token(token)
wc_png = wordcloud_maker(aft_token)
dt_now = datetime.datetime.now()

wc_png.to_file("./png/"+ str(dt_now.year) + '-' + str(dt_now.month) + '-' + str(dt_now.day) + '-' + str(dt_now.hour) + '-' + str(dt_now.minute) + '-' + str(dt_now.second) +"_Word_Cloud.png")

こちらでは曲数を指定し任意の曲をWordCloudにて利用し頻出具合の可視化をしています。画像を出力する際はpngフォルダに「今日の日付、時間_Word_Cloud.png」というファイル名で作成されます。

今後の展望

現状、コマンドプロンプト上で実行するような状況なのでTkinter等利用しGUIアプリ化していきたいと思います。

初投稿でつたない文章でしたが記事をご覧いただきありがとうございました。

この記事が気に入ったらサポートをしてみませんか?