長富蓮実ちゃん元ネタ調査ツールを作りました

はじめに

蓮実ちゃんお誕生日&SSRおめでとう。

 

蓮実ちゃんといえば昭和アイドルの歌詞などを元にした発言が多いことで有名ですが、残念なことに平成生まれの自分は昭和アイドルの知識が足りず元ネタが分からないことが多いです。

 


 

有志による素敵なDBやTwitterで元ネタを知ることが多いのですが、せっかくなら自分で見つけたいですよね。

 

元ネタ調査ツール

というわけでITの力で蓮実ちゃんのセリフから元ネタを見つけるツールを作成しました。

 

ツール:PythonGoogle Colaboratory

 

仕組みはシンプルで

  1. 歌詞スクレイピングを行って元ネタになりそうな歌詞のデータを集める
  2. データを元に文ベクトルを作成し、蓮実ちゃんのセリフとの距離が近いものを表示する

という仕組みです。

すべてGoogle Colaboratory上でやりました。

 

1.のスクレイピングこちらの記事、2.の文ベクトル作成・距離計算にはこちらの記事を参考にさせてもらいました。
 

コード

スクレイピング

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.find("div",id="kashi_area")
    kashi_row=str(kashi_row).replace("<br/>","\n").replace("<br>","\n").replace("</br>","\n").replace('<div id="kashi_area" itemprop="text">',"")
    kashi_row=kashi_row.replace("\n\n","\n")
    # カンマを大文字に
    kashi_row=kashi_row.replace(",","、")
    # 記号の排除
    kashi_row = re.sub(r'[ <>♪`‘’“”・…_!?!-/:-@[-`{-~]', '', kashi_row)
    # 注意書きの排除
    kashi = re.sub(r'注意:.+', '', kashi_row)
    return kashi.split("\n")

def search(id,pagen): 
  kashis = ''
  for i in range(1,pagen+1):
      # アーティストページのアドレス
      url = 'https://www.uta-net.com/artist/'+id+'/0/'+str(i)+"/"

      # 曲ページの先頭アドレス
      base_url = 'https://www.uta-net.com'

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

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

      """ 曲の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'),a.string])


      """ 歌詞の取得 """
      for i, page in enumerate(musics_url):
          print('{}曲目:{}'.format(i + 1, page[0]))
          html = load(page[0])
          for div in pickup_tag(html, 'div'):
              # id検索がうまく行えなかった為、一度strにキャスト
              div = str(div)
              # 歌詞が格納されているdiv要素か
              if r'itemprop="text"' in div:
                  # 不要なデータを取り除く
                  kashi = parse(div)
                  for line in kashi:
                    # 歌詞,曲名という形で保存
                    kashis=kashis+line.replace("div","")+","+page[1]+"\n"
                  # 1秒待機
                  time.sleep(0.1)
                  break
  return kashis

ドライブのマウント

from google.colab import drive
drive.mount('/content/drive')

歌詞をテキストファイルで出力

kashi=search("2747",3)
with open("/content/drive/My Drive/seiko.txt",mode="w",encoding="utf-8") as f:
    f.write(kashi)
kashi=search("2662",2)
with open("/content/drive/My Drive/kyonkyon.txt",mode="w",encoding="utf-8") as f:
    f.write(kashi)
kashi=search("2497",1)
with open("/content/drive/My Drive/momoe.txt",mode="w",encoding="utf-8") as f:
    f.write(kashi)
kashi=search("3292",2)
with open("/content/drive/My Drive/akina.txt",mode="w",encoding="utf-8") as f:
    f.write(kashi)
kashi=search("2350",1)
with open("/content/drive/My Drive/sayuri.txt",mode="w",encoding="utf-8") as f:
    f.write(kashi)
kashi=search("1287",1)
with open("/content/drive/My Drive/candys.txt",mode="w",encoding="utf-8") as f:
    f.write(kashi)
kashi=search("3865",1)
with open("/content/drive/My Drive/hiroko.txt",mode="w",encoding="utf-8") as f:
    f.write(kashi)

セットアップと日本語モデル読み込み

!git clone https://github.com/sonoisa/sentence-transformers
!cd sentence-transformers; pip install -r requirements.txt
!wget -O sonobe-datasets-sentence-transformers-model.tar "https://www.floydhub.com/api/v1/resources/JLTtbaaK5dprnxoJtUbBbi?content=true&download=true&rename=sonobe-datasets-sentence-transformers-model-2"
!tar -xvf sonobe-datasets-sentence-transformers-model.tar
%cd sentence-transformers
%tensorflow_version 2.x
from sentence_transformers import SentenceTransformer
import numpy as np
model_path = "/content/training_bert_japanese"
model = SentenceTransformer(model_path, show_progress_bar=False)

文ベクトルの計算

sentences=[]
songdic={}
sentence_d={}
with open("/content/drive/My Drive/seiko.txt",mode="r",encoding="utf-8") as f:
    lines=f.readlines()
    last=""
    for line in lines:
      data=line.split(",")
      sentence_d[data[0]]=data[1]
      sentence_d[last+" "+data[0]]=data[1]
      songdic[data[1]]=nam[1]
      last=data[0]
keys=set(sentence_d.keys())
items=set(sentence_d.values())
sentences.extend(list(keys))
sentences.extend(list(items))
sentence_vectors = model.encode(sentences)

検索

import scipy.spatial

queries = ["〇〇さん、あなたから誘って素知らぬ顔はないですよ♪",
           "南国のバカンスで、私の心もフレッシュ、フレッシュ、フレッシュです♪",
           "私の心もフレッシュ、フレッシュ、フレッシュです♪",
           "ああ…青空がエメラルド…!大好きなアイドルソングの世界の、まるでヒロインになった気分♪",
           "ああ…青空がエメラルド…!",
           "素敵なジャスミンの花、ありがとうございます。こうして髪に…ふふっ、似合いますか?",
           "ステージでは、私、笑っています。それが君との約束だから"]
query_embeddings = model.encode(queries)


closest_n = 5
for query, query_embedding in zip(queries, query_embeddings):
    distances = scipy.spatial.distance.cdist([query_embedding], sentence_vectors, metric="cosine")[0]

    results = zip(range(len(distances)), distances)
    results = sorted(results, key=lambda x: x[1])

    print("\n\n======================\n")
    print("セリフ「"+query+"」に似ている歌詞/曲名はこちら\n")

    for idx, distance in results[0:closest_n]:
        lyric=sentences[idx].strip()
        title=""
        artist=""
        if lyric in sentence_d:
          title="/曲名:"+sentence_d[lyric][:-1]
          artist=songdic[sentence_d[lyric]]
          lyric="歌詞:"+lyric
        elif lyric+"\n" in songdic:
          artist=songdic[lyric+"\n"]
          lyric="曲名:"+lyric

        print(lyric,title,"(歌:"+artist+")","(Score: %.4f)" % (distance / 2))

結果

出力結果は以下のようになります。

======================

セリフ「〇〇さん、あなたから誘って素知らぬ顔はないですよ♪」に似ている歌詞/曲名はこちら

歌詞:あなたから誘って 素知らぬ顔はないわ /曲名:白いパラソル (歌:松田聖子) (Score: 0.0633)
歌詞:誘ってみようよ OneTwoThree気取っていないで OneTwoThree /曲名:ラッキーチャンスを逃がさないで (歌:キャンディーズ) (Score: 0.1196)
歌詞:恥ずかしがりやの あいつにあいつ 誘ってみようよ OneTwoThree気取っていないで OneTwoThree /曲名:ラッキーチャンスを逃がさないで (歌:キャンディーズ) (Score: 0.1237)
歌詞:誘ってみようよ OneTwoThree気取っていないで OneTwoThree いつもは言えない ひとことだけど /曲名:ラッキーチャンスを逃がさないで (歌:キャンディーズ) (Score: 0.1338)
歌詞:うわついてない あなたが好きよ /曲名:恋路 (歌:中森明菜) (Score: 0.1419)


======================

セリフ「南国のバカンスで、私の心もフレッシュ、フレッシュ、フレッシュです♪」に似ている歌詞/曲名はこちら

歌詞:恋なら今はまどろんで 真昼の海もおだやかで /曲名:ストライプ (歌:中森明菜) (Score: 0.1604)
歌詞:水平線のむこう 幸せの島あるよ /曲名:東の島にブタがいたVol.2 (歌:小泉今日子) (Score: 0.1659)
歌詞:心がひとつに とけてゆく 浜辺のくちづけ 風の中 /曲名:乾いた唇 (歌:山口百恵) (Score: 0.1704)
歌詞:優しい気持ちなのアイランド 自然の中愛を誓うの素敵ね /曲名:Love Island (歌:松田聖子) (Score: 0.1708)
歌詞:心が癒やされるアイランド 永遠さえ感じられるわ素敵ね /曲名:Love Island (歌:松田聖子) (Score: 0.1718)


======================

セリフ「私の心もフレッシュ、フレッシュ、フレッシュです♪」に似ている歌詞/曲名はこちら

歌詞:そしてあなたの心をつかんでみたいの /曲名:I can't stop falling in love (歌:松田聖子) (Score: 0.1102)
歌詞:心では嬉しくても /曲名:今も、Playboy (歌:松田聖子) (Score: 0.1160)
歌詞:OhYes微笑かけるわ そしてあなたの心をつかんでみたいの /曲名:I can't stop falling in love (歌:松田聖子) (Score: 0.1194)
歌詞:フレッシュで かわいくて /曲名:レモンのキッス (歌:山口百恵) (Score: 0.1203)
歌詞:おいでね、急ぎ足で あなたの心にあるもの /曲名:ひみつ (歌:松田聖子) (Score: 0.1305)


======================

セリフ「ああ…青空がエメラルド…!大好きなアイドルソングの世界の、まるでヒロインになった気分♪」に似ている歌詞/曲名はこちら

歌詞:きれいなこの花 きっと見えるでしょう あなたへのそれは 愛の想いなのよ /曲名:なみだ草 (歌:キャンディーズ) (Score: 0.1056)
歌詞:一番好きな季節の中で 素敵なmusic愛を奏でる /曲名:Our love last forever (歌:松田聖子) (Score: 0.1090)
歌詞:それだけでいいの 可愛い人ね すてきな恋が /曲名:不死鳥伝説 (歌:山口百恵) (Score: 0.1162)
歌詞:笑顔があふれだす魔法なの 私から始めよう素敵な愛のMelody /曲名:Melody♪ (歌:松田聖子) (Score: 0.1190)
歌詞:愛を待てない愛を待てない まっ青な空の下元気な恋をしたいだけ /曲名:夏を待てない (歌:国生さゆり) (Score: 0.1199)


======================

セリフ「ああ…青空がエメラルド…!」に似ている歌詞/曲名はこちら

歌詞:青空はエメラルド /曲名:白いパラソル (歌:松田聖子) (Score: 0.0611)
歌詞:青空はエメラルド あなたから誘って /曲名:白いパラソル (歌:松田聖子) (Score: 0.0971)
曲名:エメラルド海岸  (歌:松田聖子) (Score: 0.1314)
歌詞:入江はエメラルド /曲名:ひまわりの丘 (歌:松田聖子) (Score: 0.1339)
歌詞:夏のシャワー浴びて 青空はエメラルド /曲名:白いパラソル (歌:松田聖子) (Score: 0.1341)


======================

セリフ「素敵なジャスミンの花、ありがとうございます。こうして髪に…ふふっ、似合いますか?」に似ている歌詞/曲名はこちら

歌詞:恋する気持ち通じた気がしたの 白い羽根がフワリと落ちたら /曲名:クリスマスの夜 (歌:松田聖子) (Score: 0.1658)
歌詞:小麦色に焼けたマーメイドが誘う パラソルを差しかけ微笑んで迎えているわ /曲名:30th Party (歌:松田聖子) (Score: 0.1751)
歌詞:ジャスミンの放つ 香りlostintimeandspace /曲名:Carnaval (歌:中森明菜) (Score: 0.1779)
歌詞:気持ちだけ聞かせて 髪にジャスミンの花 /曲名:白いパラソル (歌:松田聖子) (Score: 0.1790)
歌詞:髪にジャスミンの花 /曲名:白いパラソル (歌:松田聖子) (Score: 0.1810)


======================

セリフ「ステージでは、私、笑っています。それが君との約束だから」に似ている歌詞/曲名はこちら

歌詞:笑ってごらん それが君との約束だから /曲名:天使のウィンク (歌:松田聖子) (Score: 0.0813)
歌詞:笑ってごらん それが僕との約束だから /曲名:天使のウィンク (歌:松田聖子) (Score: 0.1187)
歌詞:笑顔見てるだけで 幸せになれるから 今の気持ち /曲名:祝福 (歌:中森明菜) (Score: 0.1356)
歌詞:君の事だけは 心残るけど 行こう 希望に光る笑顔を置いてゆくから /曲名:走る卒業 (歌:小泉今日子) (Score: 0.1390)
歌詞:あなたのその愛で包まれているからだね 「僕がそばにいるから 君はもっと輝いて /曲名:僕がそばにいるから (歌:松田聖子) (Score: 0.1393)


結構うまく元ネタを見つけられているのではないでしょうか?
ただし、青空とエメラルドのようにセリフを分割しないと見つからないものや

======================

セリフ「ああ…青空がエメラルド…!大好きなアイドルソングの世界の、まるでヒロインになった気分♪」に似ている歌詞/曲名はこちら

歌詞:きれいなこの花 きっと見えるでしょう あなたへのそれは 愛の想いなのよ /曲名:なみだ草 (歌:キャンディーズ) (Score: 0.1056)
歌詞:一番好きな季節の中で 素敵なmusic愛を奏でる /曲名:Our love last forever (歌:松田聖子) (Score: 0.1090)
歌詞:それだけでいいの 可愛い人ね すてきな恋が /曲名:不死鳥伝説 (歌:山口百恵) (Score: 0.1162)
歌詞:笑顔があふれだす魔法なの 私から始めよう素敵な愛のMelody /曲名:Melody♪ (歌:松田聖子) (Score: 0.1190)
歌詞:愛を待てない愛を待てない まっ青な空の下元気な恋をしたいだけ /曲名:夏を待てない (歌:国生さゆり) (Score: 0.1199)


======================

セリフ「ああ…青空がエメラルド…!」に似ている歌詞/曲名はこちら

歌詞:青空はエメラルド /曲名:白いパラソル (歌:松田聖子) (Score: 0.0611)
歌詞:青空はエメラルド あなたから誘って /曲名:白いパラソル (歌:松田聖子) (Score: 0.0971)
曲名:エメラルド海岸  (歌:松田聖子) (Score: 0.1314)
歌詞:入江はエメラルド /曲名:ひまわりの丘 (歌:松田聖子) (Score: 0.1339)
歌詞:夏のシャワー浴びて 青空はエメラルド /曲名:白いパラソル (歌:松田聖子) (Score: 0.1341)


======================


夏の扉の「フレッシュ!フレッシュ!フレッシュ!」のようにセリフを分割しても見つけられないものもありました。

======================

セリフ「南国のバカンスで、私の心もフレッシュ、フレッシュ、フレッシュです♪」に似ている歌詞/曲名はこちら

歌詞:恋なら今はまどろんで 真昼の海もおだやかで /曲名:ストライプ (歌:中森明菜) (Score: 0.1604)
歌詞:水平線のむこう 幸せの島あるよ /曲名:東の島にブタがいたVol.2 (歌:小泉今日子) (Score: 0.1659)
歌詞:心がひとつに とけてゆく 浜辺のくちづけ 風の中 /曲名:乾いた唇 (歌:山口百恵) (Score: 0.1704)
歌詞:優しい気持ちなのアイランド 自然の中愛を誓うの素敵ね /曲名:Love Island (歌:松田聖子) (Score: 0.1708)
歌詞:心が癒やされるアイランド 永遠さえ感じられるわ素敵ね /曲名:Love Island (歌:松田聖子) (Score: 0.1718)


======================

セリフ「私の心もフレッシュ、フレッシュ、フレッシュです♪」に似ている歌詞/曲名はこちら

歌詞:そしてあなたの心をつかんでみたいの /曲名:I can't stop falling in love (歌:松田聖子) (Score: 0.1102)
歌詞:心では嬉しくても /曲名:今も、Playboy (歌:松田聖子) (Score: 0.1160)
歌詞:OhYes微笑かけるわ そしてあなたの心をつかんでみたいの /曲名:I can't stop falling in love (歌:松田聖子) (Score: 0.1194)
歌詞:フレッシュで かわいくて /曲名:レモンのキッス (歌:山口百恵) (Score: 0.1203)
歌詞:おいでね、急ぎ足で あなたの心にあるもの /曲名:ひみつ (歌:松田聖子) (Score: 0.1305)


======================


「フレッシュ!フレッシュ!フレッシュ!」とかは人間的には固有の歌詞としてすぐ認識できるのですが、
今回のコードだと見つけられていないのは面白いですね。

文章ベクトルだから逆に見つけられていない気もするので、シンプルにTF-IDFとか使えば見つけられるんですかね。
ちゃんとコード書いて自然言語処理するのはまだまだ勉強が足りないので色々やっていってみたいです。
最近はずっと経済学よりこっちの方をやっている気もするもするので経済学的な研究も色々やりたいですね。

あとがき

f:id:viola_voila:20200321213131j:plain
永遠にMV見てるんですけれどマジで可愛くて「えっ…かわいい…」みたいな独り言が止まりません。

今回はColaboratory上でやりましたけど上手くやったらWebアプリとかにして皆が使えるようにもできるんだろうな。
総選挙のときに合わせてできたら面白そうだな。
とかは想うのですがいかんせん新人インフラエンジニアのため、WEB系の技術が全然分からず誰か教えてくれる人がいたら教えてほしいです。

遅くなりましたが蓮実ちゃんお誕生日おめでとうございました!!