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/),这个精致的网站果然是动态的,也就意味着本人的垃圾技术还没学会怎么抓静态网站就要学动态的了。行吧先搞起再说啊!
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里的。
本来还想继续看看黄老板啥的,发现可能是被发现我是机器人了就……等下次去学校了再研究吧。
这些流行歌手可能还是没多大意思,说唱歌词的内容或许会更丰富。不过总觉得这样一来就很复杂(引号不能瞎删除了),也许就需要研究一下代码之外的东西了。
网友评论