用python爬取qq音樂中五月天的歌曲歌詞

1、任務(wù)目標(biāo)
① 爬五月天正規(guī)專輯的所有歌曲的歌詞
② 按照年份進(jìn)行情感分析,并制作詞云
2、方法
在qq音樂上用Python進(jìn)行爬蟲,總共499首歌曲,其中包括演唱會和電影原聲帶等,需要進(jìn)行數(shù)據(jù)清洗。
3、情感語義分析

彎路部分:
原本是想用Beautiful Soup 來抓歌詞,Beautiful Soup是python的一個庫,最主要的功能是從網(wǎng)頁抓取數(shù)據(jù),但是后來發(fā)現(xiàn)此路不通。

其一,因為qq音樂里的url是固定不變的,并不是每一頁是一個單獨(dú)的url。點(diǎn)擊下一頁,這個url永遠(yuǎn)在那里不變,摔!!


image.png

打開之后跳轉(zhuǎn)到的是歌手的首頁,并不是我們要的單曲頁。


2.png

因為我是完全沒有學(xué)過php,后來搜索了一圈才知道,好像這個翻頁是用js寫的(還是什么ajax?),就是實(shí)際上看不到的……反正我是找了好久也沒找到那個對應(yīng)499首歌曲的對應(yīng)頁面的url。

其二,因為Beautiful Soup要依賴標(biāo)簽定位,而可以看到有的歌曲有mv注釋,有的歌曲有熱門注釋,所以源碼里標(biāo)簽并不是非常一致。

因為是小白,這個地方也摸索了半天,后來才發(fā)現(xiàn)怎么也提取不到《我不愿 讓你一個人》的歌名,才知道是標(biāo)簽xx.[1]這種寫法有問題,其他歌曲都是通過xx.[1]就可以定位,而這首歌由于沒有mv,所以要提取歌名的話,對應(yīng)標(biāo)簽是xx.[0],寫半天卻發(fā)現(xiàn)此路不通。

綜上,后來分析了一下,就是由于自己對php太小白,啥也不懂,所以才浪費(fèi)了這么久。還有就是,其實(shí)剛開始上手某種語言時,都會經(jīng)歷這種比較爬坡繞路的時期,不要怕,堅持一下,多搜索下前人經(jīng)驗,總會有辦法的。還好我沒放棄~~~

好吧,那我們開始尋找另一條路。

然后我不甘心,把所有能打開的url都打開了一遍,看看都是些什么鬼。

最后讓我找到了這個網(wǎng)址:

https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg?g_tk=5381&jsonpCallback=MusicJsonCallbacksinger_track&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8?ice=0&platform=yqq&needNewCode=0&singermid=000Sp0Bz4JXH0o&order=listen&begin=0&num=30&songstatus=1

3.png

打開是醬紫的:
image.png

小小興奮一下,仔細(xì)看里面有專輯名、歌名、歌手名,甚至還有歌詞的id。
image.png

到這里就有思路了,可以用正則表達(dá)式把歌名、專輯名、歌詞鏈接等關(guān)鍵字都篩選出來就好了呀~
突然有種柳暗花明的感覺呢!

但是這僅僅是499首單曲里第一頁的內(nèi)容,其他頁呢?
通過觀察發(fā)現(xiàn),在url里這里很不一樣!
https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg?g_tk=5381&jsonpCallback=MusicJsonCallbacksinger_track&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq&needNewCode=0&singermid=000Sp0Bz4JXH0o&order=listen&begin=0&num=30&songstatus=1

begin=0&num=30決定了每頁第一首歌曲的序號及歌曲數(shù)目。
只要做個循環(huán)就可以翻頁了都爬下來了嘛~

代碼走起,先來看看最基本的,爬了第一頁的歌曲:
import re
import pandas as pd
import requests
response = requests.get("https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg?g_tk=5381&jsonpCallback=MusicJsonCallbacksinger_track&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq&needNewCode=0&singermid=000Sp0Bz4JXH0o&order=listen&begin=0&num=30&songstatus=1")
response = response.text
print(response)

image.png

songname = '"songname":"(.?)","songorig"'
res1 = re.findall(songname,response)
for i in res1:
print(i)
image.png

同理,爬了專輯名、歌詞還有一個musicid后面會用到。
然后只要將每一頁的歌曲都抓出來就好了,用一個循環(huán)增加頁碼即可。
import re
import requests
for i in range(0,481,30):
response = requests.get("https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg?g_tk=5381&jsonpCallback=MusicJsonCallbacksinger_track&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq&needNewCode=0&singermid=000Sp0Bz4JXH0o&order=listen&begin="+str(i)+"&num=30&songstatus=1")
response = response.text
#print(response)
songname = '"songname":"(.
?)","songorig"'
album = '"albumname":"(.?)","alertid"'
strMedia = '"strMediaMid":"(.
?)","stream"'
musicid = '"songid":(.*?),"songmid"'
res1 = re.findall(songname,response)
res2 = re.findall(album,response)
res3 = re.findall(strMedia,response)
res4 = re.findall(musicid,response)
for i in range(0,len(res1)):
if res2 == '' or res3 == '' or res4 == '' :
continue
print (str(i),'\t',res1[i],'\t',res2[i],'\t',"http://y.qq.com/n/yqq/song/"+res3[i]+".html",'\t',res4[i])

image.png

這里最開始print的for循環(huán)寫的是:
for i in range(0,30)
拉到最后報錯說list index out of range
但代碼改成for i in range(0,len(res1))之后還是有問題,實(shí)際抓取出來只有409首歌,剩下的3頁90首歌因為有的專輯名為空,會同樣出現(xiàn)list index out of range的問題,只是不報錯,而是直接跳過去繼續(xù)打印下一頁的內(nèi)容了。
后來加上if語句,將為空的元素跳過繼續(xù)執(zhí)行循環(huán)就好了。

關(guān)于數(shù)組有時候很容易懵b。但還是那句話,剛開始學(xué),在還沒有那么扎實(shí)的理論功底時,這樣邊試錯、邊實(shí)戰(zhàn)是對代碼理解最深刻、學(xué)得最快的方式。然后在實(shí)操之后,可以再反過來,重新看一下基礎(chǔ)的理論知識,鞏固一下基本功,此時自己的理解力肯定跟兩眼一抹黑,從頭學(xué)的時候不一樣了,理解會更深刻的。
接下來是導(dǎo)出到excel中,然后根據(jù)歌詞的鏈接,再去抓取歌詞。最后就可以對歌詞進(jìn)行分析了~

我是直接把print出來的內(nèi)容copy到txt文檔中,再copy到excel即可,怎么快怎么來。
按照專輯分類,將演唱會、日語專輯等刪除,按照年份對原始先做一次清理。
最后整理完一共是124首歌。

image.png

然后找到歌詞頁,繼續(xù)解析網(wǎng)頁源碼,結(jié)果發(fā)現(xiàn)源碼里并沒有直接給出歌詞,shit!
image.png

完全陷入困境,不知從何下手。
然后搜了好多大神的方法,讓我找到了一位大神的github:
(https://github.com/lhtlht/qqmusic)
潛心研究了快一天啊!
最后稍微看明白一些,原來能夠有效區(qū)分不同歌曲的key有兩個,一個是在url中的歌曲號musicid(之前沒注意,沒有爬下來,后來加上的),一個是在referer里用到的歌詞號songmid(也就是我們之前抓到的strMedia)
image.png

image.png

然后對大神的代碼做了調(diào)整,改了好久啊,才跑成功,更改如下:
(簡書的編輯器會吞空格……看我公眾號的原版吧,無奈)
#抓取歌詞函數(shù)
import requests
import json
import pandas as pd
import re
def getLyric(musicid,songmid):
url = 'https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric.fcg?nobase64=1&musicid='+musicid+'&callback=jsonp1&g_tk=5381&jsonpCallback=jsonp1&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq&needNewCode=0'
header = {
'user-agent':'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36',
'referer':'https://y.qq.com/n/yqq/song/{}.html'.format(songmid)
}
paramters = {
'nobase64':'1',
'callback':'jsonp1',
'g_tk':'5381',
'jsonpCallback':'jsonp1',
'loginUin':'0',
'hostUin':'0',
'format':'jsonp',
'inCharset':'utf8',
'outCharset':'utf-8',
'notice':'0',
'platform':'yqq',
'needNewCode':'0'
}
html = requests.get(url=url,params=paramters,headers=header)
res = json.loads(html.text.lstrip('jsonp1(').rstrip(')'))
#由于一部分歌曲是沒有上傳歌詞,因此沒有默認(rèn)為空
lyric = json.loads(html.text.lstrip('jsonp1(').rstrip(')'))['lyric']
#對歌詞內(nèi)容做稍微清洗
dr1 = re.compile(r'&#\d.;',re.S)
dr2 = re.compile(r'[\d+]',re.S)
dd = dr1.sub(r'',lyric)
dd = dr2.sub(r'\n',dd).replace('\n\n','\n')
return dd

帶入一首《志明與春嬌》的musicid和 songmid試試看:
lyric = getLyric('4830147','001Sh6UI3dh9mE')
print (lyric)


image.png

寫到這里,快哭了好嗎!!!

然后把大神對于歌詞格式的更改稍微改了一下,便于導(dǎo)出。
從excel中導(dǎo)入musicid 和 songmid。

#抓取歌詞函數(shù) getLyric 及從excel傳參
import requests
import json
import pandas as pd
import re
import openpyxl
wb = openpyxl.load_workbook(r'D:\lyric.xlsx') #打開excel文件
#print(wb.get_sheet_names()) #獲取工作簿所有工作表名
sheet = wb.get_sheet_by_name('清洗') #獲取工作表
#print(sheet.title) #獲取sheet頁的名稱
def getLyric(musicid,songmid):
url = 'https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric.fcg?nobase64=1&musicid='+musicid+'&callback=jsonp1&g_tk=5381&jsonpCallback=jsonp1&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq&needNewCode=0'
header = {
'user-agent':'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36',
'referer':'https://y.qq.com/n/yqq/song/{}.html'.format(songmid)
}
paramters = {
'nobase64':'1',
'callback':'jsonp1',
'g_tk':'5381',
'jsonpCallback':'jsonp1',
'loginUin':'0',
'hostUin':'0',
'format':'jsonp',
'inCharset':'utf8',
'outCharset':'utf-8',
'notice':'0',
'platform':'yqq',
'needNewCode':'0'
}
html = requests.get(url=url,params=paramters,headers=header)
res = json.loads(html.text.lstrip('jsonp1(').rstrip(')'))
#由于一部分歌曲是沒有上傳歌詞,因此沒有默認(rèn)為空
lyric = json.loads(html.text.lstrip('jsonp1(').rstrip(')'))['lyric']
#對歌詞內(nèi)容做稍微清洗
dr1 = re.compile(r'&#\d.;',re.S)
dr2 = re.compile(r'[\d+]',re.S)
dd = dr1.sub(r'',lyric)
dd = dr2.sub(r'\n',dd).replace('\n',',')
return dd

lyric_list = []
for i in range(2,126,1):
lyric_list = getLyric(str(sheet.cell(row=i,column=5).value),str(sheet.cell(row=i,column=4).value))
print (lyric_list,'\n')


image.png

同上,copy到txt再直接粘貼到excel就好了,至此,歌詞爬蟲總算搞定了~
撒花~~~


image.png

這篇是比較理論的部分,下一篇會進(jìn)行歌詞的分析,結(jié)合年份看看我們主唱大人這幾年的心-路-歷-程,畢竟小伙子也變成發(fā)福中年大叔了嘛~哈哈

謝謝大家!
然后本人再次強(qiáng)調(diào),小白Python選手,記性不好,單純?yōu)閭€人記錄之用。
本文可分享,未經(jīng)允許請勿轉(zhuǎn)載!
整理后的excel文檔如果有人想用來分析,請在公眾號(fancyfanyc)后臺回復(fù)mayday即可獲得下載鏈接。
請大神們多多指教,輕拍,喵~
江湖之大,后會有期,咱們下篇見~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 序:python強(qiáng)大的功能,可以爬取網(wǎng)上的某些信息,本次主要是通過爬歌單信息熟悉下python基礎(chǔ)。 用到知識點(diǎn):...
    我大聲_你溫柔閱讀 9,413評論 0 5
  • 腦海一直有個想法,想做一個音樂播放的小程序。奈何還只停留在腦海之中。音樂的數(shù)據(jù)的來源是個需要考慮的問題。之前用No...
    Evtion閱讀 6,102評論 2 6
  • 利用perl語言抓取腳本的時候,我是拒絕的。因為用perl語言太繁瑣。空閑時間在聽音樂,突然發(fā)現(xiàn)有些歌沒辦法聽,就...
    自閉癥小孩閱讀 558評論 0 1
  • 教育孩子的第一步就是愿意聆聽孩子的心聲,在跟孩子的交流過程中我們可以更好的明白孩子的的所思所想,然后有針對性給予關(guān)...
    王盼盼啊閱讀 353評論 0 0
  • 消費(fèi)者心里真正以為的剛需,能夠滿足多少是多少
    Kevin007閱讀 139評論 0 0