0.為什么要玩這個
聽戳爺歌的時候網易云評論下面很多人說“我發現他歌詞都是pool,summer之類的詞語”
對于這個結果我是懷疑的……然而如果一篇一篇copy到excel里統計就很不酷炫了,那么我們就來現場學習一下用python怎么抓取網頁以及用正則表達式篩選好了。
(也是為了隨時好奇其他歌手高頻詞是什么)
一開始用了urllib抓一個很簡陋的網站:
https://www.azlyrics.com/
然后研究到一半它突然無法訪問了(隨后得知是因為ip被封)。
尸體的代碼如下
import requests
import re
import time
from bs4 import BeautifulSoup
time.sleep(4)
#防止被當作機器人
proxies={'http':'http://93.167.224.213:80'}
headers={'User-Agent':'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25'}
ty_url="https://www.azlyrics.com/t/troyesivan.html"
先做一些準備工作,設置好要爬的網站和代理ip,偽裝成瀏覽器的UA
#在歌手主頁獲取歌詞子界面的鏈接
ty_response=requests.get(ty_url,headers=headers,proxies=proxies)
ty_soup=BeautifulSoup(ty_response.content,'lxml')
使用requests.get(url,headers,proxies)得到一個response對象。
接下來使用BeautifulSoup函數方便解析html
link=[]
for links in ty_soup.find_all(target="_blank"):
link.append(links.get("href"))
tylist=[]
for x in link:
new=re.sub("../lyrics","https://www.azlyrics.com/lyrics",x)
tylist.append(new)
雖然不知道是怎么回事,但是所有定向到歌詞子界面的tag都有target="_blank"
這個特征,所以就姑且拿來用吧。
(本來是想用正則的)
既然知道了這么一個非常便利的特征,就很適合通過find_all()
來提取一整個標簽。接下來用.get()
來獲取href的值,添加到list中方便之后再用。
#去除歌詞相同的remix版本
for song in tylist:
if (re.search(".*remix.*",song))!=None:
tylist.remove(song)
#獲取歌詞存入一個list
all_lyric=[]
for tyhref in tylist:
tylyrichtml=requests.get(tyhref,headers=headers,proxies=proxies)
tylyric_soup=BeautifulSoup(tylyrichtml.content,'lxml')
final_tylyric=tylyric_soup.get_text()
all_lyric.append(final_tylyric)
print(all_lyric)
以上是一開始的思路。然而這網站我似乎永遠也進不去了也只能算了。
所以只好臨時換了一個網站(https://www.musixmatch.com/artist/),這個精致的網站果然是動態的,也就意味著本人的垃圾技術還沒學會怎么抓靜態網站就要學動態的了。行吧先搞起再說?。?/p>
1.思路
訪問歌手的主頁
找到每首歌對應的href
打開這些鏈接用beautifulsoup提取一個叫mxm-lyrics__content
的標簽
整理后(去掉<br>之類的無關字符)把歌詞分割成一大堆單詞
統計次數
2.正片
2.1 使用requests獲取網頁內容
我們可以發現這個網站是動態的,非常麻煩,只有點擊“load more”才能看到所有歌曲的列表。
不過其實本質還是可以看作一個靜態網站,因為如果f12查看源代碼就會發現,其實https://www.musixmatch.com/artist/歌手名字/從1開始的數字指向了不同的鏈接,每個鏈接里都有15首為上限的歌曲。
用BeautifulSoup
提取所有歌曲的子界面
2.2代碼部分
import re
from bs4 import BeautifulSoup
import requests
import time
from collections import Counter
time.sleep(5)
proxies={'http':'http://203.146.82.253:3128','http':'http://145.239.93.189:80','http':'http://203.74.4.7:80','http':'http://36.83.69.97:80'}
headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.149 Safari/537.36' }
#home page of the artist
url="https://www.musixmatch.com/artist/Troye-Sivan"
#get the complete song list
urlset=[url+"/{}".format(i) for i in range(1, 10)] #唱了150首以上歌的人還挺少的
lyric_dict={}
for url_forload in urlset:
ty=requests.get(url_forload,headers=headers,proxies=proxies)
time.sleep(3)
tysoup=BeautifulSoup(ty.content,"lxml")
finalsoup=tysoup.find_all("a",class_="title")
#find tags contain links of songs
for tag in finalsoup:
links=tag.get("href")
if (re.search(".*remix.*",links))==None:
#requests only understands links start with "http"
lyric_dict[re.sub("/lyrics","https://www.musixmatch.com/lyrics",links)]=_
if tysoup.find(class_='empty')!=None:
#stop reading when there's no more song
break
#get a list of lyrics to process later
def get_lyric_musix(url):
music_soup=BeautifulSoup(url,'lxml')
music_content=music_soup.find_all(class_='mxm-lyrics__content ')
return ([content.get_text() for content in music_content])
for url in list(lyric_dict.keys()):
tycontent=requests.get(url,proxies=proxies,headers=headers).content
time.sleep(3)
finalsoup=get_lyric_musix(tycontent)
lyric_dict[url]=re.sub("\s+"," ",re.sub(r"[!?,.\"']","",re.sub(r"\n"," ","".join(finalsoup)))).lower()
#remove useless parts
#get every single word to count frequency
lyricswords=[]
for lyric in lyric_dict.values():
lyricswords=lyricswords + lyric.split(' ')
#the 300 most frequent words
ly_frenquency=Counter(lyricswords).most_common(300)
for item in ly_frenquency:
print(re.sub(r"[()']",'',str(item)))
2.3稍微改進一下
其實隨便改一下就能變成輸入歌手名字批量下載:
(后來發現其實大小寫不分也毫無關系)
name=re.sub(r' ','-',str(input("Singer's name").title()))
url="https://www.musixmatch.com/artist/"+name
3.結果
事實上就是,戳爺的歌詞里也沒有那么多游泳池
篩選了前300個頻率最高的單詞中甚至沒有網易云評論中經常被吐槽的summer
比如說:(去掉了一些你我他之類的常用詞)
love, 144
youth, 106
wild, 96 ←總覺得只是因為you got me wild wild wild
running, 60
blue, 42 ←blue竟然這么多我都驚了
driving, 35
fools, 33
lost, 30
boy, 28
heart, 25
eyes, 24
kiss, 21
truth, 20
stars, 19
lights, 17
crawling, 16
fire, 16
twelve, 16
twenty, 16
colour, 12
pools, 12
swimming, 12 ←大家最愛的游泳池 其實也沒有特別多
boys, 12
moon, 12
shooting, 12
wave, 11
tear, 11
sun, 11
dreams, 11
sleepin, 10
waterfalls, 10
rifles, 8
june, 8
clean, 8
gasoline, 8
seat, 8
pillow, 7
pill, 7
bathe, 7
總而言之精選的這些還是挺夏天挺青春的,不過出現了一個問題就是boys不知道為什么出現了兩次。
看完戳爺的反正寫了也是放著浪費就拿來爬了一下霉霉的:
霉霉相比之下歌詞不是很有套路 ,第三百名直接頻率就兩次了(戳爺的話是7次)
shake, 70
trouble, 32
baby, 29
blood, 16
play, 16
ill, 15
break, 15
fake, 15
gorgeous, 13
mad, 8
ex-lovers, 6
players, 6
insane, 6
shame, 6
high, 6
romeo, 6
young, 5
下面開始幾乎就都是2次了在此略過。第一名shake差點噴了好吧,查了一下真的70個都是shake it off里的。
本來還想繼續看看黃老板啥的,發現可能是被發現我是機器人了就……等下次去學校了再研究吧。
這些流行歌手可能還是沒多大意思,說唱歌詞的內容或許會更豐富。不過總覺得這樣一來就很復雜(引號不能瞎刪除了),也許就需要研究一下代碼之外的東西了。