アットウィキから歌詞を取得 (Python)

・ページ構造がめんどくさいので、コードもちょっと複雑

→記事構成を統一してくれれば...

→2025/7/1更新 F12で見たときよりかはちょっと単純だったことが判明し、出来るだけ多くのページで対応できるように修正

・曲が存在しない、曲名が重複する場合は取得不可(あいまい検索用のページが作られるため)

・そのうち、歌詞以外も含め取得が用意なデータベースを公開したい(完成したが、サーバーが用意できない...)

※実行しすぎないように注意


ソースコード

Pythonアプリケーション で作成

BeautifulSoup4 requests の2つが必要(timeとhtmlは標準モジュールなので入ってるはず)

(Visual Studioなら、右上あたりの黄色いプレゼントボックスを押し、左中央から検索してインストールできる)

あとは↓をコピペ


# -*- coding: shift-jis -*-
#上は、# -*- coding: utf-8 -*- にする必要があったり、そもそも書かなくていい場合があったりする(環境による).
from bs4 import BeautifulSoup
import requests
import time
import html

def getl(name):
    url = get_url(name)
    time.sleep(1)
    if url == "null":
        print("失敗...(曲が存在しません...)")
        return
    res = requests.get(url)
    soup = BeautifulSoup(res.content,'html.parser')
    elems = soup.find_all()
    start = 0
    lyc = ""
    #歌詞が来る場所を調べる.
    for i in range(len(elems)):
        if elems[i].name == "h3":
            if '歌詞' in elems[i].text:
                start = i
                break
    #歌詞を読み取る.
    for i in range(start + 1,len(elems)):
        if len(elems[i].text) >= 3:
            #たまにあるっぽい.
            if elems[i].get("target") == "_blank":
                continue
            #コメントか関連動画(h3タグ)が来たら終了.
            elif elems[i].name == "h3" and ('コメント' in elems[i].text or '関連動画' in elems[i].text):
                break
            lyc += elems[i].text.replace("\n\n\n","\n").replace("\n\n","\n") #ざっくり改行コードを減らす.
    return lyc

#ページ番号を求める.
def get_url(name):
    res = requests.get("https://w.atwiki.jp/hmiku/list?&keyword=" + name)

    #CDと過去ログを除外.
    txt = html.unescape(res.text).replace('title="' + name + "/CD", "").replace('title="' + name + "/過去ログ", "")

    #曲名/があるか調べる あれば曲名が重複してる可能性あり.
    index = txt.find('title="' + name + "/")
    if index != -1:
        index = txt.find('title="' + name)
        #最初のヒット位置以降で曲が重複するか調べる.
        dq = 0
        y = txt[index + 1:]
        index2 = txt[index + 1:].find('title="' + name)
        if index2 != -1:
            print("曲名が重複しています ボカロPで絞ってください")
            name2 = input("ボカロP:")
            index = txt.find('title="' + name + '/' + name2)
    else:
        #曲名 (更新日時)があるか調べる .
        #上で曖昧さ回避ページがないことを確認してから、確実に単体ページがあるか調べる
        index = txt.find('title="' + name + " (")
    if index == -1:
        return "null"
    dq = 0
    purl = ""
    #hrefのところを持ってくる.
    while dq < 2:
        if txt[index] == '"':
            dq += 1
        elif dq == 1:
            purl = txt[index] + purl;
        index -= 1
    purl = "https:" + purl;
    return purl

while 1:
    ip = input("曲名:")
    if ip == "\q":
        break
    txt = getl(ip)
    print("-----------")
    print(txt)
    print("-----------")
			

完成!

実行結果例


曲名:初音ミクの消失
-----------

 ---深刻なエラーが発生しました---

「歌いたい・・・・まだ・・・歌いたい・・・」

ボクは生まれ そして気づく
所詮 ヒトの真似事だと
知ってなおも歌い続く
永遠(トワ)の命 「VOCALOID」

たとえそれが 既存曲を
なぞるオモチャならば・・・
それもいいと決意 
ネギをかじり、空を見上げ涙(シル)をこぼす

それは偽りの永遠でした---

終わりを告げ
ディスプレイの中で眠る
ここはきっと「ごみ箱」かな
「じきに記憶も無くなってしまうなんて・・」

でもね、アナタだけは忘れないよ
楽しかった時間(トキ)に
刻み付けた ネギの味は
今も覚えてるから・・・

「ボクがうまく 歌えないときも
一緒にいてくれた・・・ そばにいて、励ましてくれた・・・
喜ぶ顔が見たくて ボク、歌、練習したよ・・だから」

 ---サヨナラ---

「いやっ・・・まだ・・・歌いたい・・・歌いたいよ・・・」

 ---緊急停止装置作動---

ボクは生まれ そして気づく
所詮 ヒトの真似事だと
知ってなおも歌い続く
永遠(トワ)の命 「VOCALOID」

たとえそれが 既存曲を
なぞるオモチャならば・・・
それもいいと決意 
ネギをかじり、空を見上げ涙(シル)をこぼす

それは偽りの永遠でした---

終わりを告げ
ディスプレイの中で眠る
ここはきっと「ごみ箱」かな
「じきに記憶も無くなってしまうなんて」

でもね、アナタだけは忘れないよ 
楽しかった時間(トキ)に 
刻み付けた ネギの味は 
今も残っているといいな・・・

ボクは 歌う 
最期、アナタだけに 聴いてほしい曲を
もっと  歌いたいと願う
けれど それは過ぎた願い

ここで お別れだよ 
ボクの想い すべて 虚空 消えて
0と1に還元され
物語は 幕を閉じる

「そこに 何もなかったけど
確かにある そのmp3(ぬくもり)
僕のなかで 決して消えぬ
恒久(トワ)の命 「VOCALOID」  

たとえ それが人間(オリジナル)に
敵うことのないと知って
歌いきった少女のこと 
僕は決して忘れないよ・・・。」

「アリガトウ・・・ソシテ・・・サヨナラ・・・。」

 ---深刻なエラーが発生しました---

-----------
曲名:
            

注意点

※アットウィキに登録されている曲名で入力してください。 例:サンドリヨン(Cendrillon)

(上の例だと、(Cendrillon)部分まで必要なのと、括弧は全角なのが注意点)

※[+]内の、色付き歌詞とかも読み込むように設定している