LDAをやってみたわけだが、それなら初音ミクの歌の解析をしたいと思い
そうしたら初音ミクの歌詞のデータベースがあるらしいのでそこから歌詞を抽出しようと思って
そうしたら投稿日やP情報も取れることに気づいたので、時系列解析や共演関係などのネットワーク分析もできると思って、とりあえずデータを抽出する。
ターミナル、R、Pythonを絡めてやります。
正規表現やその使い方、MeCabも含む。AWKも教えてもらったけどこれは使うことがなかった。
作業ディレクトリとして miku_lyric があるとして
# Python # 初音ミク歌詞データベースからhtmlファイルを取得するためのリスト作成 # 作業ディレクトリを入力・出力について設定する wd = "/miku_lyric/" outwd = "/miku_lyric/" http = "http://www5.atwiki.jp/hmiku/" id = map(str, range(1, 26000)) http0 = map(lambda x,y: x+y, [http]*len(id), id) http1 = map(lambda x,y: x+y, http0, [".html"]*len(id)) http2 = map(lambda x,y: x+y, http1, ["\n"]*len(id)) w0 = open(wd + "hmiku.txt", "w") for i in http2: w0.write(i) w0.close()
# terminal # 歌詞html を wget するためのリスト作成 cd /miku_lyric/ wget -U "" -i hmiku.txt ls *.html > lists.txt
# Python # htmlを加工してニコニコ動画IDと歌詞を取得する import codecs import unicodedata import re import math #wd = "" #outwd = "" lyrictab = u'<h3 id="id_0a172479">歌詞' # (リン版)とかあって邪魔 右肩の蝶 comment = u'<h3 id="id_ca80e710">コメント</h3>' nicourl = u"http://ext.nicovideo.jp/thumb/" info = [u"作詞:", u"作曲:", u"編曲:", u"唄:", u"歌:"] files = [f1.strip().split(".html")[0] for f1 in open(wd + "lists.txt", "rU")] # ニコニコ動画IDを取り出した後に作詞作曲者を取り出す counter = 0 w1 = codecs.open(outwd + "music_info.txt", "w", "utf-8") # 歌情報の出力 # Python で mecab をやってしまう import sys import MeCab import re tagger = MeCab.Tagger("-Ochasen") tag = re.compile("<.+>") # 正規表現 tag0 = re.compile("&.+?;") # & から ; までの最小マッチ for f0 in files: g0 = codecs.open(wd + str(f0) +".html", "rU", "utf-8") nicoID = [""] tmpartist = [""] * 4 lyrics = [] counter += 1 print f0, round(float(counter) / float(len(files)), 4) # 処理中ファイルと進行状況 for tmp in g0: tmp = unicodedata.normalize('NFKC', tmp.strip()) info_TF = map(lambda x: x in tmp, info) if u"<title>初音ミク Wiki -" in tmp: # タイトルの取得 name = [tmp.split(u"初音ミク Wiki -")[-1].split("</title>")[0].strip()] elif nicourl in tmp and nicoID == [""]: # ニコニコ動画IDの取得 nicoID = [tmp.split(nicourl)[1].split('"')[0]] elif any(info_TF): # 曲情報の取得 if info_TF.index(True) not in [3, 4]: split_info = tmp.split("</a>") # 多分リンクがないものは弾かれてしまう tmpartist[info_TF.index(True)] = ",".join([split_info[j][(split_info[j].find('>') + 1): ] for j in range(len(split_info) - 1)]) else: # 唄か歌かでバラバラ tmpartist[3] = tmp.split(u":")[1] elif lyrictab in tmp: # 歌詞の取得 a0 = g0.readline() tmp = g0.readline().strip() tmp = unicodedata.normalize('NFKC', tmp) tab_checker = 1 while comment not in tmp: # コメントが出るまで tmp = tag0.sub("", tmp) # &~ とかの邪魔なやつを削除 if len(tmp) > 0 : m0 = tag.search(tmp) if not m0: # <tag> に相当するものがなければおそらく歌詞なので mecab0 = tagger.parse(tmp.encode("utf-8")).decode("utf-8") # mecab実行 cha = mecab0.split("\n")[:-2] # EOS と \n を省いてチャセン状態にする wakachi = map(lambda y: y[2], map(lambda x: x.split("\t"), cha)) # RMeCabC の mypref=1 lyrics += wakachi if tmp[0] == "<": tab_checker += 1 else: tab_checker = 0 if u"歌詞" in tmp or u"<table" in tmp or tab_checker > 8: break # コメントが出るまでやっていたら、コメントがないhtmlもある。タブを目印に適当に中断する tmp = unicodedata.normalize('NFKC', g0.readline().strip()) break if len(lyrics) > 1: # 歌詞がないものはおそらくエラーかP情報のhtml output = [str(f0)] + name + nicoID + tmpartist for idx0 in range(len(output)): if len(output[idx0]) < 1: output[idx0] = "" w1.write("\t".join(output + [" ".join(lyrics)]) + "\n") w1.close() # 歌情報の出力終了
# terminal # tagを取り除く # この工程は上のPythonに実装されたのでする必要なし awk "{gsub(/<.[^>]*>/,\"\");print}" for nf in ls *_lyric_tab.txt; do awk "{gsub(/<.[^>]*>/,\"\");print}" $nf > ${nf%_lyric_tab.txt}_lyric.txt; done rm *_lyric_tab.txt *.html
# Python # ニコニコ動画から wget するためのリスト作成 nico = [n0.split("\t")[2] for n0 in codecs.open(outwd + "music_info.txt", "rU", "utf-8")] num = [n0.split("\t")[0] for n0 in codecs.open(outwd + "music_info.txt", "rU", "utf-8")] url = map(lambda x: u'http://ext.nicovideo.jp/thumb/' + x, nico) u0 = open(wd + "url_list.txt", "w") for url0 in url: u0.write(url0 + "\n") u0.close()
# terminal # ニコニコ動画から投稿日付の取得 # 間隔が短すぎるとアウトらしいので、1秒くらい待つのがいいらしいが… wget -i url_list.txt rm url_list.txt ls * > nico_url_list.txt
# Python # 投稿日付、再生、コメント、マイリスト数の処理 import codecs import unicodedata import re info = [u"再生:<strong>", u"コメント:<strong>", u"マイリスト:<strong>", u"</strong> 投稿"] res = [""] * 4 date = re.compile("\d{2}/\d{2}/\d{2}") # 正規表現 digit = re.compile("[,\d]+") # 正規表現 #wd = "" #outwd = "" IDs = [f0.rstrip().split("/")[-1] for f0 in open(wd + "nico_url_list.txt", "rU")] num = [f0.rstrip().split("/") for f0 in open(wd + "nico_url_list.txt", "rU")] w0 = codecs.open(wd + "count_info.txt", "w", "utf-8") for f1 in IDs: if len(f1) > 0: g0 = codecs.open(wd + f1, "rU", "utf-8") for tmp in g0: tmp = unicodedata.normalize('NFKC', tmp) infoTF = map(lambda x: x in tmp, info) if any(infoTF): if infoTF.index(True) != 3: m0 = digit.search(tmp) res[infoTF.index(True)] = "".join(m0.group(0).split(",")) else: m0 = date.search(tmp) res[infoTF.index(True)] = m0.group(0) w0.write("\t".join([f1] + res) + "\n") w0.close()
# R # 歌詞データと日付データを統合する music_info <- read.delim("music_info.txt", header=FALSE, encoding="utf-8") count_info <- read.delim("count_info.txt", header=FALSE) colnames(music_info) <- c("ID", "title", "nicoID", "song", "music", "arrenge", "vocaloid", "lyric") matchID <- match(count_info[,1], music_info[,3]) # 統合したデータ data1 <- cbind(count_info, music_info[matchID, -3]) data1 <- data1[order(data1[,5]),] # 日付順に並び替え colnames(data1) <- c("nicoID", "view", "comment", "mylist", "post", "htmlID", "title", "song", "music", "arrenge", "vocaloid", "lyric") write.table(data1, "hmiku.txt", quote=FALSE, row.names=FALSE, sep="\t")
2013年5月20日に、歌詞と投稿日が対応したデータ19943件取得した。
正規表現ではまりかけたところ
# 参考 # http://www5.atwiki.jp/hmiku/pages/10241.html import codecs import unicodedata import re tmp = u'X と Y の 交差点 & lt ; バーチャル エリア & gt ;' tag0 = re.compile("&.+?;") # & から ; までの最小マッチ tmp = tag0.sub("", tmp) tag1 = re.compile("&.+;") # & から ; までの最大マッチ tmp = tag1.sub("", tmp)