上文中我們已經大致明白了pydub庫的使用方法,今天的目標是寫個爬蟲爬取歌曲資訊。
關於網路爬蟲,Python的標準庫裡是有相應的包的,可以直接開啟:https://docs.python.org/zh-cn/ 去看Python相應版本的的官方中文文件(這個網站很有用,推薦學Python的小夥伴收藏),當然官方文件一般比較晦澀,可以再搜一些教程配合食用最佳。
通過學習瞭解到關於python網路爬蟲可以使用傳統的urllib庫或者更高階的 Requests庫,這裡暫時選用urllib。其中urllib.request模組用於開啟url,用法如下:
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
看起來很複雜,不過其他的預設可以不填,我們只需給出url引數就行了。開啟百度百科搜尋煙花易冷,發現網頁url是這樣的:https://baike.baidu.com/item/煙花易冷/211 ,嘗試更改url,輸入:https://baike.baidu.com/item/七里香 ,轉到,成功進入七里香的百度詞條介面,不過url自動更新為了:https://baike.baidu.com/item/七里香/2181450 (可以用,nice)。
觀察網頁,又出現了一個新問題,那就是七里香存在多義,而預設轉到的是周杰倫專輯《七里香》,而不是周杰倫歌曲,七里香。分別開啟煙花易冷和七里香搜尋結果的原始碼,觀察:
<li class="item">▪<span class="selected">周杰倫演唱歌曲</span></li>
<li class="item">▪<span class="selected">2004年周杰倫發行的音樂專輯</span></li>
可以發現他們這一行程式碼是不同的,另外在後一行程式碼附近,有如下程式碼:
<li class="item">▪<span class="selected">2004年周杰倫發行的音樂專輯</span></li>
<li class="item">▪<a title="席慕容詩集" href='/item/%E4%B8%83%E9%87%8C%E9%A6%99/2181435#viewPageContent'>席慕容詩集</a></li>
<li class="item">▪<a title="2007年泰國電視劇" href='/item/%E4%B8%83%E9%87%8C%E9%A6%99/2181466#viewPageContent'>2007年泰國電視劇</a></li>
<li class="item">▪<a title="陳淑樺演唱歌曲" href='/item/%E4%B8%83%E9%87%8C%E9%A6%99/2172939#viewPageContent'>陳淑樺演唱歌曲</a></li>
<li class="item">▪<a title="中藥" href='/item/%E4%B8%83%E9%87%8C%E9%A6%99/4494994#viewPageContent'>中藥</a></li>
<li class="item">▪<a title="旅遊景點" href='/item/%E4%B8%83%E9%87%8C%E9%A6%99/3518031#viewPageContent'>旅遊景點</a></li>
<li class="item">▪<a title="2005年中央編譯出版社出版的圖書" href='/item/%E4%B8%83%E9%87%8C%E9%A6%99/20490760#viewPageContent'>2005年中央編譯出版社出版的圖書</a></li>
<li class="item">▪<a title="小說《七里香》" href='/item/%E4%B8%83%E9%87%8C%E9%A6%99/3922533#viewPageContent'>小說《七里香》</a></li>
<li class="item">▪<a title="芸香科九里香屬植物" href='/item/%E4%B8%83%E9%87%8C%E9%A6%99/4499679#viewPageContent'>芸香科九里香屬植物</a></li>
<li class="item">▪<a title="臺灣2004年周杰倫演唱歌曲" href='/item/%E4%B8%83%E9%87%8C%E9%A6%99/12009481#viewPageContent'>臺灣2004年周杰倫演唱歌曲</a></li>
<li class="item">▪<a title="台灣地區小吃" href='/item/%E4%B8%83%E9%87%8C%E9%A6%99/2181417#viewPageContent'>台灣地區小吃</a></li>
<li class="item">▪<a title="席慕容創作新詩" href='/item/%E4%B8%83%E9%87%8C%E9%A6%99/22593324#viewPageContent'>席慕容創作新詩</a></li>
<li class="item">▪<a title="暗夜文學網小說" href='/item/%E4%B8%83%E9%87%8C%E9%A6%99/22781892#viewPageContent'>暗夜文學網小說</a></li>
<a href="javascript:;" class="fold-on">全部展開<em class="cmn-icon cmn-icons cmn-icons_arrow-b"></em></a>
<a href="javascript:;" class="fold-off">收起<em class="cmn-icon cmn-icons cmn-icons_arrow-t"></em></a>
發現這裡有個”臺灣2004年周杰倫演唱歌曲“選項,與前者相通的地方是有共同關鍵字”周杰倫演唱歌曲“。接下來繼續尋找,我們需要的資訊在這樣一段文字中:
<meta name="description" content="《煙花易冷》是方文山作詞,黃雨勳編曲,周杰倫作曲並演唱的一首歌曲,收錄在周杰倫2010年5月18日發行的專輯《跨時代》中。2011年,該曲獲得2010年度北京流行音樂典禮“年度金曲獎”。">
<meta name="description" content="《七里香》是周杰倫演唱的一首歌曲,由方文山作詞,周杰倫譜曲,鍾興民編曲,收錄在周杰倫2004年8月3日發行的同名專輯《七里香》中。2004年,該曲獲得香港TVB8十大金曲最佳作曲、監製、編曲3項大獎。2005年,該曲獲得第27屆十大中文金曲十大金曲獎、優秀流行華語歌曲獎以及第11屆全球華語音樂榜中榜年度最佳歌曲等多個獎項。">
所以,譜曲、編曲和作曲有什麼區別嗎?百度一下:
1、概念區別:作曲一般是指給歌詞譜寫旋律;編曲一般是指給歌曲作伴奏;譜曲是把已經有的曲子記下來,寫成簡譜,五線譜等。
2、順序區別:先有作曲,再有編曲和譜曲。
好吧,長見識了。到這裡,準備工作大致就差不多了。
這是歌曲標籤資訊在不同平臺與ffmpeg庫對照的的一個統計表:
Windows | iTunes(Info tab) | id3v2.3 | ffmpeg key | ffmpeg 示例 |
---|---|---|---|---|
Title | Title | TIT2 | title | -metadata title=”海闊天空” |
Subtitle | Description(Video tab) | TIT3 | TIT3 | -metadata TIT3=”beyond 20週年紀念版” |
Rating | n/a | n/a | n/a | n/a |
Comments | Comments | COMM | n/a | n/a |
Contributing artists | Artist | TPE1 | artist | -metadata artist=”黃家駒” |
Album artist | Album artist | TPE2 | album_artist | -metadata album_artist=”Josh Groban” |
Album | Album | TALB | album | -metadata album=”Closer” |
Year | Year | TYER | date | -metadata date=”2009” |
# | Track Number | TRCK | track | -metadata track=”3/12”(12首歌中的第3個) |
Genre | Genre | TCON | genre | -metadata genre=”Vocal” |
Publisher | n/a | TPUB | publisher | -metadata publisher=”Heaven Church” |
Encoded by | n/a | TENC | encoded_by | -metadata encoded_by=”Joshua” |
Aythor URL | n/a | WOAR | n/a | n/a |
CopyRight(不可編輯) | n/a | TCOP | copyright | -metadata copyright=”℗ lqsoft” |
Composers | n/a | TCOM | composer | -metadata composer=”Joshua” |
Conductors | n/a | TPE3 | performer | -metadata performer=”Joshua” |
Group description | Grouping | TIT1 | TIT1 | -metadata TIT1=”The Classics” |
Mood | n/a | n/a | n/a | n/a |
Part of set | Disc Number | TPOS | disc | -metadata disc=”1/2” |
Initial key | n/a | TKEY | TKEY | -metadata TKEY=”G” |
Beats-per-minute | BOM | TBPM | TBPM | -metadata TBPM=”120” |
Part of a compilation | Part of a compilation | TCMP | n/a | n/a |
n/a | n/a | TLAN | language | -metadata language=”eng” |
n/a | n/a | TSSE | encoder | -metadata encoder=”iTunes v10” |
由於店家的資原始檔名中帶有數字編號:
01.牛仔很忙.wav
01.說了再見.wav
所以先寫個指令碼重新命名一下,順帶匯出歌曲名單:
import os
import re
pattern=[r"^[0-9]+\.",r"\.wav"]
dir='E:\\BaiduNetdiskDownload\\周杰倫'
os.chdir(dir)
raw_dir_list=os.listdir(dir)
dir_list=list()
for file in raw_dir_list:
tmp=re.sub(pattern[0],"",file)
str=re.sub(pattern[1],"",tmp)
dir_list.append(str)
os.rename(file,tmp)
with open("song_list.txt","w") as p:
for file in dir_list:
p.write(file+"\n")
名單效果如下(檔名則是帶有“.wav”字尾):
七里香
世界末日
東風破
喬克叔叔
接下來是爬蟲指令碼:
from urllib import request
from urllib import parse
import re
import os
def getlist(file):
with open(file,"r") as p:
list=p.read().split("\n")
while '' in list:
list.remove('')
return list
def crawtext(url):
res=request.urlopen(url)
text=res.read().decode(encoding='utf-8', errors='strict')
return text
def isurl(patternlist,text):
if re.search(patternlist[0],text):
a=re.search(patternlist[1],text)
if a:
flag=0
else :
flag=2
else :
flag=1
return flag
def gettext(pattern,raw_text):
a=re.search(pattern,raw_text)
if a:
text=raw_text[a.span()[0]:a.span()[1]]
else :
text=False
return text
def geturl(pattern,patternlist,raw_text):
a=re.search(pattern,raw_text)
if a:
text=raw_text[a.span()[0]:a.span()[1]]
tmp=re.sub(patternlist[0],"",text)
url=re.sub(patternlist[1],"",tmp)
else :
url=False
return url
baseurl=r"https://baike.baidu.com/item/"
pattern1=['<li class="item">▪<span class="selected">','<li class="item">▪<span class="selected">.*周杰倫.*歌曲.*</span></li>']
pattern2='<meta name="description" content=".*">'
pattern3='<li class="item">▪<a title=".*周杰倫.*歌曲.*>'
pattern4=[".*href='/item/","'>.*"]
dir="E:\\BaiduNetdiskDownload\\周杰倫"
os.chdir(dir)
song_list=getlist("song_list.txt")
text_list=list()
for file in song_list:
name=re.sub(".wav","",file)
url=baseurl+parse.quote(name)
text=crawtext(url)
flag=isurl(pattern1,text)
if flag==0:
text_list.append(gettext(pattern2,text))
elif flag==1:
text=gettext(pattern2,text)
if text:
text_list.append(text)
else:
text_list.append(name+" error 1 ")
else :
key=geturl(pattern3,pattern4,text)
if key:
url=baseurl+key
text=crawtext(url)
text_list.append(gettext(pattern2,text))
else :
text_list.append(name+" error 2 ")
with open("text.txt","w") as p:
for str in text_list:
p.write(str+"\n")
還是出了一些問題,比如3個“error:2”:
菊花臺 error 2
說好的幸福 error 2
軌跡 error 2
開啟瀏覽器搜尋,發現周杰倫的歌曲叫“說好的幸福呢”,而不是“說好的幸福”,而對於“菊花臺”和“軌跡”:
周杰倫演唱電影《滿城盡帶黃金甲》片尾曲
周杰倫演唱電影《尋找周杰倫》主題曲
無語,副標題裡面沒有“歌曲“關鍵字。除此之外, 還有幾個資料錯誤是因為詞條沒有自動跳轉、演唱者不是周杰倫(獻世是周杰倫給陳小春寫的歌)。
看起來指令碼還可以優化下,好麻煩,反正就幾個,手動新增吧,順帶修改一下錯誤的歌曲名。原始資料下載成功,效果如下:
<meta name="description" content="《七里香》是周杰倫演唱的一首歌曲,由方文山作詞,周杰倫譜曲,鍾興民編曲,收錄在周杰倫2004年8月3日發行的同名專輯《七里香》中。2004年,該曲獲得香港TVB8十大金曲最佳作曲、監製、編曲3項大獎。2005年,該曲獲得第27屆十大中文金曲十大金曲獎、優秀流行華語歌曲獎以及第11屆全球華語音樂榜中榜年度最佳歌曲等多個獎項。">
接下來進行資料清理:
import os
import re
def getlist(file):
with open(file,"r") as p:
list=p.read().split("\n")
while '' in list:
list.remove('')
return list
class SONG:
title=""
artist=""
album=""
date=""
composer=""
def __init__(self,title) :
self.title=title
def cuthead(pattern,text):
a=re.search(pattern,text)
if a:
tmp=text[a.span()[1]:-1]+text[-1]
str=cuthead(pattern,tmp)
else :
str=text
return str
def search1(pattern,text):
a=re.search(pattern[0]+".*?"+pattern[1],text)
if a:
tmp1=text[a.span()[0]:a.span()[1]]
tmp2=re.sub(pattern[1],"",tmp1)
str=cuthead(pattern[0],tmp2)
else:
str=False
return str
def search2(pattern,text):
a=re.search(pattern,text)
if a:
str=text[a.span()[0]:a.span()[1]]
else :
str=False
return str
def search3(pattern,text):
pass
dir="E:\\BaiduNetdiskDownload\\周杰倫"
os.chdir(dir)
pattern1=["《","》"]
pattern2=["是","演唱"]
pattern3=["歌曲,.",",收錄"]
pattern4=["收錄.*?[0-9]+年[0-9]+月[0-9]+日","[0-9]+年[0-9]+月[0-9]+日"]
pattern5=["專輯《","》"]
textlist=getlist("text.txt")
li=[]
for text in textlist:
title=search1(pattern1,text)
song=SONG(title)
song.artist=search1(pattern2,text)
song.album=search1(pattern5,text)
song.date=search2(pattern4[1],str(search2(pattern4[0],text)))
song.composer=search1(pattern3,text)
li.append(song)
with open("list.txt","w") as p:
for song in li:
p.write(str(song.title)+"\t")
p.write(str(song.artist)+"\t")
p.write(str(song.album)+"\t")
p.write(str(song.date)+"\t")
p.write(str(song.composer)+"\n")
資料不規範,清理兩行淚。程式執行完還是手動檢查修改了幾個不規範資料。清理效果如下:
七里香 周杰倫 七里香 2004年8月3日 方文山作詞,周杰倫譜曲,鍾興民編曲
世界末日 周杰倫 范特西PLUS 2001年12月28日 周杰倫作詞、作曲
東風破 周杰倫 葉惠美 2003年7月31日 周杰倫譜曲,方文山填詞,林邁可編曲
接下來最後一步,格式轉化,標籤新增:
import os
import pydub
def getlist(file):
with open(file,"r") as p:
list=p.read().split("\n")
while '' in list:
list.remove('')
return list
class SONG:
title=""
artist=""
album=""
date=""
composer=""
def __init__(self,title) :
self.title=title
dir="E:\\BaiduNetdiskDownload\\周杰倫"
os.chdir(dir)
os.mkdir("test")
lines=getlist("list.txt")
list=[]
for line in lines:
tmp=line.split("\t")
song=pydub.AudioSegment.from_wav(tmp[0]+".wav")
dic={"title":tmp[0],"artist":tmp[1],"album":tmp[2],"date":tmp[3],"composer":tmp[4]}
song.export("test\\"+tmp[0]+".flac",format="flac",tags=dic)
song.export()
通篇下來,發現格式轉化反倒是最簡單的了。