Python爬取网易云音乐评论
兴趣点:
这个网易云音乐的评论我早就想爬了,可惜技术不行,研究了两天的时间我终于用最简单的方法实现了网易云音乐评论的爬取,我以毛不易的《像我这样的人》为例来介绍一下
爬取网站:
虚假的爬取网站:
https://music.163.com/#/song?id=569213220
这个是打开歌曲《像我这样的人》的页面,由于页面是动态加载的,评论信息都保存在json文件里,无法直接爬取,但我们可以想办法看一下:
(1)按F12进入开发者工具,刷新一下,点几下翻页,你会发现多了好多文件,如图:
(2)切换不同的文件看一下,发现只有两个参数是不同的,这很明显是js加密了的
林林子皱了皱眉,发现此事并不简单,网上也有很多的解密方法,但是我看不太懂,大神们太厉害了,于是在看知乎大神的方法的时候我就找到了下面的方法
真实的爬取网站:
http://music.163.com/api/v1/resource/comments/R_SO_4_569213220?
(1)这个网页是由前面的 http://music.163.com/api/v1/resource/comments/R_SO_4_ 和 歌曲ID 在加问号拼接而成的,这个页面介绍未加密的json,至于怎么找到这个链接,我也不知道,可以看看大神自己的说法:
(2)如何翻页?大佬也说了:
limit是一页的数量,offset是往后的偏移。比如limit是20,offset是40,就展示第三页评论,对于我们爬评论来讲limit肯定是越大越好,本人亲测limit最大值是100,链接样式如下:
http://music.163.com/api/v1/resource/comments/R_SO_4_569213220?limit=100&offset=0
爬虫大体思路与方法:
大体思路:
(1)找到评论页面的规律和翻页方法(如上所说)
(2)把json类型转成Python字典类型,提取想要的内容就行了
方法:
(1)getHTMLText(url):页面获取方法
(2)fillList(music_id,url,commentlist):把用户名及评论内容存入列表
(3)save(commentlist,path):读取列表内容存入本地txt文件
参数介绍:
(1)music_id:你要爬取评论的歌曲的id,也可以使用循环爬取多首歌的评论
(2)commentlist:存放用户名和评论内容的列表
(3)path:本地存储路径
部分细节讲解:
(1)json解读,这个相对容易,json也是键值对,只要屡清层次就非常简单,但在网页上不好屡,所以我粘了一部分到本地,整理如下:
这里我们要注意用户名和评论内容不是同一层次,我开始这里还看错了
(2)json解析案例,方便理解:
import json
jsonString = '{
"arrayOfNuns":[{"nunber":0},{"number":1},{"number":2}],
"arrayOfFruits":[{"fruit":"apple"},{"fruit":"banana"},{"fruit":"pear"}]
}'
json0bj=json.loads(jsonString) #转字典
print(type(json0bj)) #返回:<class 'dict'>
print(json0bj.get("arrayOfNuns")) #输出:[{'nunber': 0}, {'number': 1}, {'nunber': 2}]
print(json0bj["arrayOfNuns"]) #输出:[{'nunber': 0}, {'number': 1}, {'nunber': 2}]
print(json0bj.get('arrayOfNuns')[1]) #输出:{'number': 1}
print(json0bj["arrayOfNuns"][1]) #输出:{'number': 1}
print(json0bj.get('arrayOfNuns')[1].get('number') + json0bj.get('arrayOfNuns')[2].get('number')) #输出:3
print(json0bj['arrayOfNuns'][1]['number'] + json0bj['arrayOfNuns'][2]['number']) #输出:3
print(json0bj.get('arrayOfFruits')[2].get('fruit')) #输出:pear
print(json0bj['arrayOfFruits'][2]['fruit']) #输出:pear
(3)特殊字符编码失败:这个问题只出现在IDLE窗口打印中,如图所示:
这个我直接使用try——except抛出了:
for item in comments:
try:
commentlist.append([item['user']['nickname'],item['content']])
print(item['user']['nickname'] + "评论了:" + item['content'])
except:
print("特殊字符打印失败!!!")
完整代码:
import requests
import re
import os
from bs4 import BeautifulSoup
import json
def getHTMLText(url):
try:
kv = {"user-agent":"Mozilla/5.0"}
r = requests.get(url,headers = kv)
r.raise_for_status()
#r.encoding = r.apparent_encoding #这里自动识别编码方式会乱码,注释掉就行了
return r.text
except:
print("getHTMLText失败!")
return ""
def fillList(music_id,url,commentlist):
for i in range(4): #爬取前四页
new_url = url + "{0}?limit=100&offset={1}".format(music_id,100*i)
print(new_url)
html = getHTMLText(new_url)
json_dict = json.loads(html) #利用json方法把json类型转成dict
comments = json_dict['comments']
for item in comments:
try:
commentlist.append([item['user']['nickname'],item['content']])
print(item['user']['nickname'] + "评论了:" + item['content'])
except:
print("特殊字符打印失败!!!")
def save(commentlist,path):
with open (path,'a',encoding = 'utf-8') as f:
for comment in commentlist:
f.write(comment[0] + "评论了: " + comment[1] + "\n")
f.close()
def main():
music_id = "569213220"
url = "http://music.163.com/api/v1/resource/comments/R_SO_4_"
commentlist = []
path = "像我这样的人.txt"
fillList(music_id,url,commentlist)
save(commentlist,path)
main()