初音ミク解析

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)