それでは毛玉諸君、これにて失敬

日々の精進を備忘録的に綴ります。

メタル楽曲の歌詞をワードクラウドで可視化

「凶星のデストラップ」にハマってるko_ya346です。

bodoge.hoobby.net

大体いつも最初にエイリアンに食べられる雑魚っぷりを発揮しています。

先日connpassのイベントのMusic×Analytics Meetup Vol.2に参加したのですが、

Bump Of Chickenの歌詞分析のLTがすごい面白かったので自分も真似してみました。何番煎じか分かりませんが…

手順は

1.スクレイピングで歌詞を集める

2.ワードクラウドのライブラリに突っ込む

です。

収集する歌詞

自分はヘヴィメタルが好きなのですが、メタルには非常に多くのジャンルが存在し(少なくとも60以上)、それぞれで思想が異なるようです。

ja.wikipedia.org

そこで今回は各ジャンルを代表するバンドを勝手に選び、ワードクラウドで歌詞の頻出単語を可視化してみました。

代表バンド

デスメタル代表

Cannibal Corpse(代表曲 Hammer Smashed Face

一言:ずっと人間食べてる。安心して聴ける高クオリティのデスメタルの重鎮。

ブラックメタル代表

Behemoth(代表曲 demigod

一言:教会燃やしがち。ボーカルは悪魔が憑りついてるみたいな怖い人だけど普段は優しい。ベースがゴツイ。

メロスピ代表

Darkmoor(代表曲 Quest for the Eternal Fame

一言:この人たちのせいでメタルにハマった。2ndと3rdは人類史上最も美しい名盤。ボーカルが変わって変な感じになった。

Rhapsody(代表曲 Emerald Sword

一言:剣と魔法とドラゴン。ルカ(ギター)のギターソロは天才。最近ボーカルと仲直りして嬉しい。

ブルデス代表

Dying Fetus(代表曲 Your Treachery Will Die With You

一言:攻撃力が高い。演奏技術がエグイ。ブルデスなのにメロディが特徴的で聴きやすいという矛盾したバンド。個性が強すぎて似ているバンドが思い当たらない。好き。

パワーメタル代表

Manowar(代表曲 Hail and Kill

一言:筋肉がすごい。ジャケットが少しダサい。

スラッシュメタル代表

Slayer(代表曲 Angel of Death

一言:メタラーが全員好きなバンド(ホントに)。初期のメロ重視の作風も好き。

スクレイピング

各バンドのイメージを何となく掴んで頂いたと思うので早速歌詞を収集しましょう。

こちらのサイトを使用させて頂きました。 www.darklyrics.com

コードはこちら(すごく…汚いです…)

import time
import os
import re
import requests
from bs4 import BeautifulSoup

#アーティスト
artist = "slayer"
input_dir = "./input/"
#ディレクトリが存在しなければ新規作成する
if not os.path.exists(input_dir+artist):
    os.mkdir(input_dir+artist)

url = "http://www.darklyrics.com/" + artist[0] + "/"+artist+".html"
#歌詞が掲載されているページ
base_url = "http://www.darklyrics.com/lyrics/"+artist+"/"

#httpライブラリでWebページを取得
res = requests.get(url)
#ステータスコードが200番台以外ならメッセージを吐いてスクリプト停止
res.raise_for_status

#取得したhtmlから情報を抽出
soup = BeautifulSoup(res.content, "html.parser")
#aタグを取得
sound_list = soup.find_all("strong")

#アルバム名を収集
album_title = []
for i in sound_list:
    #URLに入れれるように変換(改善の余地あり)
    album_title.append(i.get_text().lower().replace(" ", "").replace("...", "").replace("-", "").replace("'", "").replace(":", "").replace(")", "").replace(".", "")[1:-1])

#アルバム毎に歌詞をまとめる
for i in range(len(album_title)):
    print(f"{i+1} album_title {album_title[i]}")

    with open(f"{input_dir+artist}/{album_title[i]}.txt", "w") as f:
        #アルバムのページに移動
        base_url1 = base_url+album_title[i]+".html"
        res1 = requests.get(base_url1)
        res1.raise_for_status
        soup1 = BeautifulSoup(res1.content, "html.parser")

        #アルバム収録曲のリスト
        song_list = []
        for num in range(1, 31):
            song_title = soup1.find("a", {"href":f"#{num}"})
            if song_title:
                song_list.append(song_title.text)
            else:
                break

        #歌詞を抽出
        text = soup1.get_text()
        #歌詞リスト
        lines = [line.strip() for line in text.splitlines()]
        #このサイトでは歌詞の直後に下の文が来るので終点の目安にする
        end_word = "Submits, comments, corrections are welcomed at webmaster@darklyrics.com"

        end_point = lines.index(end_word)

        #歌詞
        lyrics = ""

        #曲の始まりと終わりのインデックスを取得
        index_list = [j for j, x in enumerate(lines) for sl in song_list if x == sl ][len(song_list):] + [end_point]

        for k in range(len(index_list)-1):
            #不要部を削除
            ly = " ".join(lines[index_list[k]+1:index_list[k+1]]).replace("  ", " ").replace("...", " ").lower()
            #記号を削除
            ly = re.sub(r'[<>♪`‘’“”・…_!?!-/:-@[-`{-~]', '', ly)
            lyrics += ly
        #unicodedecodeerror回避のためcp932に変換できない部分を無視する
        lyrics = lyrics.encode("cp932", "ignore").decode("cp932")
        f.write(lyrics)
        #スクレイピング時のマナー
        time.sleep(1)

こちらのサイトではアルバム毎に歌詞が管理されているので、一度全てテキストを取得し、曲名を頼りに歌詞部分を抽出しています(index_listが目安)。

正直歌詞の抽出はすごく手こずりました。もうちょいうまいやり方はないのか?

アルバムタイトルに記号が含まている場合は取り除く必要があります(アドレスに含まれないため)。

本当はフォーク、ペイガンのジャンルも試したかったのですが、大量のエラーが予想されるので怖くて諦めました(キリル文字が多用されてたりする)。

word_cloudを作る

qiita.com

こちらを参考にしました。

txtファイルを放り込むだけなので楽ちんです。

import matplotlib.pyplot as plt
from wordcloud import WordCloud

def create_wordcloud(text, ar, dir):
    #特徴的な単語を見るために、あえて汎用的な単語は省いています
    stop_words = [ u'am', u'is', u'of', u'and', u'the', u'to', u'it', u'for', u'in', u'as', u'or', u'are', u'be', u'this', u'that', u'will', u'there', u'was', u'by', u'from', u'with', u'on', u"an", u"into", u"their", u"you", u"your", u"my", u"his", u"me", u"we", u"im", u"our", u"so", u"they", u"he"]

    wordcloud = WordCloud(background_color="white", width=900, height=500, \
                          stopwords=set(stop_words)).generate(text)

    fig = plt.figure(figsize=(15,12))
    plt.imshow(wordcloud)
    plt.axis("off")
    plt.show()
    fig.savefig(dir + ar + ".png")

#スクレイピングしたアーティストのリスト
artist = ["behemoth", "darkmoor", "manowar", "dyingfetus", "rhapsody", "cannibalcorpse", "slayer"]

for ar in artist:
    print("now", ar)
    input_dir = f"./input/{ar}/"
    output_dir = "./word_cloud/"

    txt_list = [i for i in os.listdir(input_dir) if ".txt" in i ]
    lyrics = ""
    for i in txt_list:
        with open(input_dir + i) as f:
            tmp = f.read()
        lyrics += tmp
    create_wordcloud(lyrics, ar, output_dir)

結果

Cannibal Corpse

f:id:ko_ya346:20200628172019p:plain

blood、dead、killなどらしい単語が目立ちます。

flesh、bone、eye、body、など体に関する単語は他のバンドには見られませんでした。やっぱ人肉ばっかり食べてるからですかね?(バンド名を和訳すると「食人死体」)

Behemoth

f:id:ko_ya346:20200628172014p:plain

godが目立つところからも彼らの音楽性が伺えます。blood、fireなどは儀式で使用するのでしょうか?

DarkMoor

f:id:ko_ya346:20200628172035p:plain

chorusはおそらく歌詞ではなく曲中のコーラス部分を示す言葉のようです。やっつけ仕事なので仕方ないですね…

これまでのバンドと違いlove、dreamなど前向きな単語が多いかと思いきや右上にしっかりdeathの文字。

Rhapsody

f:id:ko_ya346:20200628172104p:plain

nowとallの二大巨頭。「皆の者、今こそ立ち上がるのだ!」的なことでしょうか?

holy、king、ancient、gloryなどは中世の聖騎士が連想されます。

Dying Fetus

f:id:ko_ya346:20200628172039p:plain

no、f〇cking、deadなど強い単語が目立ちます。

歌詞を読むと政治批判などが書かれているので、強烈な単語で否定し続けているのでしょうか。

Manowar

f:id:ko_ya346:20200628172044p:plain

Rhapsodyと同様にall、nowが目立ちます。

右下のheavy metalで彼らのメタル愛が感じられます。

Slayer

f:id:ko_ya346:20200628172106p:plain

god、death、blood、painと世間が抱くメタルのイメージが全部乗っかったような画像になりました。

感想

想像通りというか、全体的にdeathやkillなど死に関するワードが多めなのが面白かったです。曲自体が強烈なので歌詞も強い言葉を載せないと釣り合いが取れないのかな~と感じます。

また、正直これまでメタル楽曲の歌詞に注目したことはほとんどありませんでしたが、各ジャンルの特徴が垣間見えたのが良かったです。

今回は各アーティストの楽曲を全てひっくるめて集計しましたが、アルバム毎などにすると特色が見れてさらに面白いかもしれません。

感情分析を取り入れると歌詞から彼らの心情も得られて楽しいかもしれませんね。

また機会があれば挑戦したいと思います。