⽹易云歌单信息爬取及数据分析(1)爬⾍部分
爬⾍思路:
⽹页分为两个部分,歌单⼴场和歌单详情页。总体思路是先从歌单⼴场获取所有的URL然后去详情页进⾏解析。
最后的数据⼤概这个样⼦:
歌单⼴场:
在⼴场中需要实现获取所有歌单详情页的URL链接。
研究URL不难发现这样的规律,改变cat可以换歌单的⼤分类(华语,流⾏,全部等),limit是每页显⽰35个歌单,这⾥是第⼆页所以offset是35*2=70。那么只需要采⽤for循环就可以。
右键打开检查我们可以发现关于歌单详情页URL就在a标签下⾯herf,之后beautifulsoup就可以获取,查看⼀下具体歌单详情页的URL确实是这样,只需要做⼀下字符串的拼接就可以了。
下⾯是代码:
import requests as rq
from bs4 import BeautifulSoup
import pandas as pd
import numpy as np
import time
import concurrent.futures
from multiprocessing.dummy import Pool as pool
##后⾯所有的代码都是调的这些个库,我习惯写pd np因为懒。。。
list1=[]
headers ={
'Referer':'music.163/',
'Host':'music.163',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36', 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'
}
163音乐网def getHTMLText(url,headers):#通⽤的获取⽹站内容的框架
try:
r = rq.get(url,headers=headers)
r.raise_for_status()
except:
return"⽹络解析错误"
def get_url(cat):#获取⾸页该分类下⾯的歌单url,形成url_list
depth=38
start_url='music.163/discover/playlist/?order=hot&cat='+cat
for i in range(depth):
try:
url=start_url+'&limit=35'+'&offset='+str(35*(i+1))
html=getHTMLText(url,headers)
parse_main(html)
except:
print('失败')
continue
def parse_main(html):#解析每个⼴场页,bs4弄出来歌单名,歌单URL
soup=BeautifulSoup(html,'html.parser')
c=soup.find_all('li')
for unit in c:
try:
name_url=unit.find('a',{'class':"tit f-thide s-fc0"})#m这⾥有URL,名字的信息
number=eval(unit.find('span',{'class':'nb'}).place('万','0000'))#这⾥获取的是播放量的信息,⽤于初步筛选
list1=[name_url['title'].replace(u'\xa0',u' '),number,name_url['href']]
url_list.append(list1)
except:
continue
弄出来list1⼤概这个样⼦:
[歌单名,播放次数,URL]
之后按照每个URL进⼊相应的详情页解析就可以了。
歌单详情页:
需要获取具体信息:
这⾥渴望拿到的是所属标签,播放次数,转发次数,收藏次数,评论量,歌单标题和歌单长度。他们的解析途径都差不多,都是beautifulsoup。我们可以看⼀个:
不难看到总共有两个属性,都在div标签下的a标签下的i,我们根据特征到左右class为u-tag的标签然后弄出来它的text就⾏了。
tags=soup.find_all('a',{'class':'u-tag'})
##中间有省略
tag1=tags[0].place(u'\xa0',u' ')
下⾯是具体代码:
finallist=[]
headers1={
'Referer':'music.163/',
'Host':'music.163',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36', 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' }
def parse_single(listid):#进⼊歌单内部解析,获取播放量,收藏量,标签等信息
global count
count+=1
singleurl='music.163'+listid
singletext=getHTMLText(singleurl,headers=headers1)
soup=BeautifulSoup(singletext,'html.parser')
play_count=eval(soup.find('strong',{'class':'s-fc6'}).text)
fav=eval(soup.find('a',{'class':'u-btni u-btni-fav'}).i.text.strip('(').strip(')'))
share=eval(soup.find('a',{'class':'u-btni u-btni-share'}).i.text.strip('(').strip(')'))
comment=eval(soup.find('a',{'data-res-action':'comment'}).)
length=eval(soup.find('span',{'id':'playlist-track-count'}).text)
date=soup.find('span',{'class':'time s-fc4'}).text[:10]
name=soup.find('h2',{"class":'f-ff2 f-brk'}).place(u'\xa0',u' ')
try:
tags=soup.find_all('a',{'class':'u-tag'})
p=len(tags)
if p==3:
tag1=tags[0].place(u'\xa0',u' ')
tag2=tags[1].place(u'\xa0',u' ')
tag3=tags[2].place(u'\xa0',u' ')
elif p==2:
tag1=tags[0].place(u'\xa0',u' ')
tag2=tags[1].place(u'\xa0',u' ')
tag3="nan"
else:
tag1=tags[0].place(u'\xa0',u' ')
tag2="nan"
tag3="nan"
list1=[name,date,play_count,fav,share,comment,length,tag1,tag2,tag3]
finallist.append(list1)
print('解析第{}个歌单成功'.format(count))
except:
tag1='nan'
tag2='nan'
tag3='nan'
list1=[name,date,play_count,fav,share,comment,length,tag1,tag2,tag3]
finallist.append(list1)
print('解析第{}个歌单成功'.format(count))
整合
最后是我的main函数和多线程的使⽤当然这⾥你弄个列表个main函数传参也可以。
def main(type):
get_url(type)
print("歌单列表获取完成")
print(url_list)
main('轻⾳乐')
#这⾥需要⾃⼰改动标签(⽐如改为流⾏,华语等,下⾯存储同样改变)
a=pd.DataFrame(url_list)
b=list(a[2])
with concurrent.futures.ThreadPoolExecutor()as executor:
executor.map(parse_single,b)
#多线程
print(finallist)
a=pd.DataFrame(finallist)
b=pd.DataFrame(url_list)
title_list=['名称','创建⽇期','播放次数','收藏量','转发量','评论数','歌单长度','tag1','tag2','tag3']
c=pd.Series(title_list)
<_excel(r'C:\Users\Leo\Desktop\轻⾳乐.xlsx')
#数据输出到Excel
特别注意和解释
(1)headers很重要,并且⼴场和详情页的headers还不太⼀样,这个我捣⿎了好长时间,尽量还是都加相应页的headers。
(2)听从⼤佬的建议采⽤了多线程,⽤之前三秒钟爬出来⼀个,⽤之后不到⼀秒⼀个,很舒适。感觉这个操作计算和io都很密集,但是我没想到怎么同时使⽤多线程和多进程。(不明⽩的⼩伙伴可以看我的另外⼀个多线程多进程的博客)
-----后续数据分析请见下⼀篇-----
–本⼈准⼤⼆⼩⽩,欢迎dalao指教–
那路径啥的,⾃⼰看着调调吧。
最后附上全部代码:
import requests as rq
from bs4 import BeautifulSoup
import pandas as pd
import numpy as np
import time
import concurrent.futures
from multiprocessing.dummy import Pool as pool
limit=10000#热门歌单播放量筛选下限
headers ={
'Referer':'music.163/',
'Host':'music.163',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'
}
headers1={
'Referer':'music.163/',
'Host':'music.163',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9'
}
finallist=[]
url_list=[]
count=0
LABEL='轻⾳乐'
def getHTMLText(url,headers):#通⽤的获取⽹站内容的框架
try:
r = rq.get(url,headers=headers)