目标:爬取网易云音乐热歌榜中全部歌曲(共200首)的热门评论(每首歌有15个热门评论)
分析:
需要分两步走,第一步是定位到热歌榜单所在的资源,从而得到这热歌榜中到底有哪些歌并获得每首歌的id;第二步是根据上一步得到的每首歌的id,定位到单独每首歌所在的资源,从而得到每首歌下的评论信息。具体讲:
1)首先我们需要得到热歌榜数据所在的url,经浏览器开发者工具查看网页代码,得知热歌榜的数据所在的请求url是:
http://music.163.com/discover/toplist?id=3778678
这个url的请求方式是get方式,返回的是html的doc文档,这个文档中的第610行就包含了每首歌的歌名,id,以及对应的播放资源链接。
所以我们的第一个任务就是把该html文档爬取下来,提取出所有歌曲的名称及id。有了歌曲id之后,我们可以进一步通过这个id访问到每一首歌的具体信息。
2)在网页上点进某一首歌的链接,分析弹出的每首歌单独的新页面的Network情况,我们可以分析出包含该首歌歌评的请求url为:
http://music.163.com/weapi/v1/resource/comments/R_SO_4_489998494?csrf_token=,
请求方式是post(因为评论需要往服务端发送数据),返回的是json文件,在该json文件中就包含了我们需要的热门评论。在这里唯一有点棘手的地方是发送post请求时需要两个参数,而不同的歌这两个参数是不同的(然而程序中用的参数是相同的),关于这两个参数如何定,具体介绍在下面的链接中。
所以下一步任务就是通过post请求把该json文件爬取下来,并提取出其中的热门评论信息。
下面代码的详细介绍请参见:https://blog.csdn.net/fengxinlinux/article/details/77950209法
#获取网易云热歌榜所有歌曲的名称和id
def get_all_hotSong():
url = "http://music.163.com/discover/toplist?id=3778678" #网易云音乐热歌榜url
ua_headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) \
AppleWebKit/537.36 (KHTML, like Gecko) \
Chrome/60.0.3112.101 \
Safari/537.36'} #请求头部
request = urllib.request.Request(url=url, headers=ua_headers) #构造请求对象
html = urllib.request.urlopen(request).read().decode('utf8') #打开url
html = str(html) #转换为str
#我们要筛选的html字段例如:
part1 = r''#进行第一次筛选的正则表达式,注意在这里有问号(本身是正则表达式的元字符)前要使用转义符\
result = re.compile(part1).findall(html) #用正则表达式进行筛选,返回的结果存在列表中
result = result[0] #获取list的第一个元素
part2 = r'(.*?) ' #进行歌名筛选的正则表达式
part3 = r'.*? ' #进行歌id筛选的正则表达式
hot_song_name = re.compile(part2).findall(result) #获取所有热门歌曲名称
hot_song_id = re.compile(part3).findall(result) #获取所有热门歌曲id
return hot_song_name, hot_song_id #返回的是两个list
#参数是歌曲名和id(由上一个函数返回),返回的是每首歌下的15条热评
def get_hotComments(hot_song_name, hot_song_id):
#每首歌使用单独的url请求
url = 'https://music.163.com/weapi/v1/resource/comments/R_SO_4_' + hot_song_id + '?csrf_token='
ua_headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) \
AppleWebKit/537.36 (KHTML, like Gecko) \
Chrome/60.0.3112.101 \
Safari/537.36'} #请求头部
#post请求表单数据,以字典形式组织参数
data = {'params':'Ms46IEnUeE4P/yfU6xsyEtEcjeRfhckhg/sBdqIG2tLBXGPoZ7MGVOZsu2AdyLQ+ZTPDvjf1OjalqcSSJLfBmf1vvbVx8cvv8MVoHYOQ6wCRnd2/6+GMfu1M13fbNXVb9aKiduqxPZjZrMsTgX5jecxsXs/rzP9KLRWDDMkvxusGini/WGaWDKGrBQj4cm4k', \
'encSecKey':'b049e6104264186dfaceba5f9a60dc39e8cf6900dac42a58223074346b758a4ca0fc66006a39a8d54e43cc95c271b415b69efa8a81742f06230a105e32a6f11128e8d526450a81f3245ce0fb5f5974de18207e6e3cdaf87b63572fcb7ad720124b19049457fe19c8f7f3424c3eae45d530b743ee7dec5ef78d15c2dbbc258975'}
postdata = urllib.parse.urlencode(data).encode('utf8') #将参数进行编码
request = urllib.request.Request(url, headers=ua_headers, data=postdata) #构造请求对象
response = urllib.request.urlopen(request).read().decode('utf8') #打开url,返回类文件对象并读其内容
json_dict = json.loads(response) #获取json
hot_comments = json_dict['hotComments'] #获取json中的热门评论
num = 0
fhandle = open('./song_comments.txt','a', encoding='utf-8') #按appendix的方式打开文件
fhandle.write(hot_song_name+':'+'\n')
for item in hot_comments: #按循环依次写入歌的每条评论
num += 1
fhandle.write(str(num)+'.'+item['content']+'\n')
fhandle.write('\n==============================\n\n')
fhandle.close()
#==============================主程序入口=======================================
#返回网易云热歌榜所有歌曲的名称和id
hot_song_name, hot_song_id = get_all_hotSong()
num = 0
while num < len(hot_song_name):
print('正在抓取第%d首歌曲热评...'%(num+1))
get_hotComments(hot_song_name[num], hot_song_id[num])
print('第%d首歌曲热评抓取成功'%(num+1))
num += 1