不知不觉中喜欢周杰伦已经那么多年了,刚好最近也在学习python爬虫的东西,顺便记录下爬取JAY的热门歌曲和热门评论的过程。
0_1. 首先是今天所用到的东西
py2.7.13(IDE使用的是Pycharm) + requests +urllib2 + re
0_2.确定我们的目标网页,我们从这个杰伦歌曲合集页面(http://music.163.com/#/artist?id=6452)开始。
OK,正式开始今天的工作
1.打开F12 开发者工具,Network确定为我们登陆这个网页是一个GET请求,目前状态码是200,证明登陆成功。
2. 获取 歌名 + 歌曲id
接下来,就需要我们利用程序来模拟这个登陆操作了。这里我用到的是一个经典操作
response = urllib2.urlopen(url)
html = response.read()
利用 urllib2.urlopen(url) 向指定URL发送一个请求,然后将得到的响应读取处理。print 一下结果,可以看到在<ul class="f-hide"> 后面有着我们需要的各种歌名。所以,我们现在的工作是从这个html中找到这个部分的内容,并取出来。
这里就要用到强大的 正则表达式 的内容了。当然,你也可以选择其他讨巧的方法。因为最开始接触的是正则(无良老师),所以这里用正则匹配来获取这部分内容。
所有的歌曲位于 <ul class="f-hide"> 后面,而每首歌位于 <a href="/song?id=531051217">等你下课 (with 杨瑞代)</a></li><li> 里面,包括 歌曲id(531051217)、歌曲名称(等你下课(with 杨瑞代)) 也就是说用正则匹配到这之间的内容即可。
reg_list = '<ul class="f-hide"><li>(.*?)</a></li></ul>'
reg_list = re.compile(reg_list, re.S)
content = re.findall(reg_list, html)
content里即包含了需要的 歌曲id 和 歌曲名称 内容,输出看一下。啊哈?怎么全都是奇奇怪怪的内容!!!(掀桌)
['<a href="/song?id=531051217">\xe7\xad\x89\xe4\xbd\xa0\xe4\xb8\x8b\xe8\xaf\xbe (with \xe6\x9d\xa8\xe7\x91\x9e\xe4\xbb\xa3)</a></li><li><a href="/song?id=418603077">\xe5\x91\x8a\xe7\x99\xbd\xe6\xb0\x94\xe7\x90\x83</a></li><li><a href="/song?id=186016">\xe6\x99\xb4\xe5\xa4\xa9</a></li><li><a href="/song?id=186001">\xe4\xb8\x83\xe9\x87\x8c\xe9\xa6\x99</a></li><li><a href="/song?id=185709">\xe7\xa8\xbb\xe9\xa6\x99</a></li><li><a href="/song?id=185820">\xe7\x94\x9c\xe7\x94\x9c\xe7\x9a\x84</a></li><li><a href="/song?id=185809">\xe5\xbd\xa9\xe8\x99\xb9</a></li><li><a href="/song?id=186119">\xe7\xae\x80\xe5\x8d\x95\xe7\x88\xb1</a></li><li><a href="/song?id=186125">\xe5\xbc\x80\xe4\xb8\x8d\xe4\xba\x86\xe5\x8f\xa3</a></li><li><a href="/song?id=29818120">\xe7\xae\x97\xe4\xbb\x80\xe4\xb9\x88\xe7\x94\xb7\xe4\xba\xba</a></li><li><a href="/song?id=186005">\xe6\x90\x81\xe6\xb5\x85</a></li><li><a href="/song?id=186139">\xe5\xae\x89\xe9\x9d\x99</a></li><li><a href="/song?id=185811">\xe9\x9d\x92\xe8\x8a\xb1\xe7\x93\xb7</a></li><li><a href="/song?id=185924">\xe4\xb8\x80\xe8\xb7\xaf\xe5\x90\x91\xe5\x8c\x97</a></li><li><a href="/song?id=185868">\xe4\xb8\x8d\xe8\x83\xbd\xe8\xaf\xb4\xe7\x9a\x84\xe7\xa7\x98\xe5\xaf\x86</a></li><li><a href="/song?id=185904">\xe5\xa4\x9c\xe6\x9b\xb2</a></li><li><a href="/song?id=185821">\xe6\x9c\x80\xe9\x95\xbf\xe7\x9a\x84\xe7\x94\xb5\xe5\xbd\xb1</a></li><li><a href="/song?id=185699">\xe8\xaf\xb4\xe5\xa5\xbd\xe7\x9a\x84\xe5\xb9\xb8\xe7\xa6\x8f\xe5\x91\xa2</a></li><li><a href="/song?id=185912">\xe6\x9e\xab</a></li><li><a href="/song?id=185668">\xe7\x83\x9f\xe8\x8a\xb1\xe6\x98\x93\xe5\x86\xb7</a></li><li><a href="/song?id=186014">\xe4\xbb\xa5\xe7\x88\xb6\xe4\xb9\x8b\xe5\x90\x8d</a></li><li><a href="/song?id=186055">\xe5\x9b\x9e\xe5\x88\xb0\xe8\xbf\x87\xe5\x8e\xbb</a></li><li><a href="/song?id=185884">\xe9\x80\x80\xe5\x90\x8e</a></li><li><a href="/song?id=185815">\xe8\x92\xb2\xe5\x85\xac\xe8\x8b\xb1\xe7\x9a\x84\xe7\xba\xa6\xe5\xae\x9a</a></li><li><a href="/song?id=185694">\xe7\xbb\x99\xe6\x88\x91\xe4\xb8\x80\xe9\xa6\x96\xe6\xad\x8c\xe7\x9a\x84\xe6\x97\xb6\xe9\x97\xb4</a></li><li><a href="/song?id=186046">\xe5\x8d\x8a\xe5\xb2\x9b\xe9\x93\x81\xe7\x9b\x92</a></li><li><a href="/song?id=25641369">\xe6\x98\x8e\xe6\x98\x8e\xe5\xb0\xb1</a></li><li><a href="/song?id=186160">\xe9\xbe\x99\xe5\x8d\xb7\xe9\xa3\x8e</a></li><li><a href="/song?id=186010">\xe8\xbd\xa8\xe8\xbf\xb9</a></li><li><a href="/song?id=185906">\xe5\x8f\x91\xe5\xa6\x82\xe9\x9b\xaa</a></li><li><a href="/song?id=185879">\xe5\x90\xac\xe5\xa6\x88\xe5\xa6\x88\xe7\x9a\x84\xe8\xaf\x9d</a></li><li><a href="/song?id=185920">\xe7\x8f\x8a\xe7\x91\x9a\xe6\xb5\xb7</a></li><li><a href="/song?id=186008">\xe5\x9b\xad\xe6\xb8\xb8\xe4\xbc\x9a</a></li><li><a href="/song?id=185667">\xe8\xaf\xb4\xe4\xba\x86\xe5\x86\x8d\xe8\xa7\x81</a></li><li><a href="/song?id=29822018">\xe6\x89\x8b\xe5\x86\x99\xe7\x9a\x84\xe4\xbb\x8e\xe5\x89\x8d</a></li><li><a href="/song?id=417250561">\xe4\xb8\x8d\xe8\xaf\xa5(with aMEI)</a></li><li><a href="/song?id=186018">\xe4\xb8\x9c\xe9\xa3\x8e\xe7\xa0\xb4</a></li><li><a href="/song?id=186145">\xe5\x8f\xaf\xe7\x88\xb1\xe5\xa5\xb3\xe4\xba\xba</a></li><li><a href="/song?id=186149">\xe6\x98\x9f\xe6\x99\xb4</a></li><li><a href="/song?id=418602087">\xe7\x88\xb1\xe6\x83\x85\xe5\xba\x9f\xe6\x9f\xb4</a></li><li><a href="/song?id=185878">\xe5\xa4\x9c\xe7\x9a\x84\xe7\xac\xac\xe4\xb8\x83\xe7\xab\xa0</a></li><li><a href="/song?id=185818">\xe6\x88\x91\xe4\xb8\x8d\xe9\x85\x8d</a></li><li><a href="/song?id=185908">\xe9\xbb\x91\xe8\x89\xb2\xe6\xaf\x9b\xe8\xa1\xa3</a></li><li><a href="/song?id=186002">\xe5\x80\x9f\xe5\x8f\xa3</a></li><li><a href="/song?id=186114">\xe7\x88\xb1\xe5\x9c\xa8\xe8\xa5\xbf\xe5\x85\x83\xe5\x89\x8d</a></li><li><a href="/song?id=186103">\xe8\x9c\x97\xe7\x89\x9b</a></li><li><a href="/song?id=25641368">\xe7\xba\xa2\xe5\xb0\x98\xe5\xae\xa2\xe6\xa0\x88</a></li><li><a href="/song?id=29822014">\xe5\x90\xac\xe8\xa7\x81\xe4\xb8\x8b\xe9\x9b\xa8\xe7\x9a\x84\xe5\xa3\xb0\xe9\x9f\xb3</a></li><li><a href="/song?id=186045">\xe5\x8d\x8a\xe5\x85\xbd\xe4\xba\xba</a></li><li><a href="/song?id=186109">\xe4\xb8\x96\xe7\x95\x8c\xe6\x9c\xab\xe6\x97\xa5']
不过好像这个 with 和上面 with 杨瑞代应该是匹配的,所以结果肯定没错。那只能是编码问题。那就不影响结果。继续从content里面匹配需要的 id 和 名字。
reg = u'<a href="(.*?)">(.*?)</a></li><li>'
reg = re.compile(reg, re.S)
song_list = re.findall(reg, content[0])
输出song_list的内容看看。哈哈哈哈哈哈,好像第一步很成功嘛。
3. 获取每首歌曲的热门评论和评论数等
随便点进去一首歌,会发现网页变成 http://music.163.com/#/song?id=531051217,和我们原始的网页相比,artist?id变成了song?id 这里就可以理解网易云音乐网页存储的格式了,song_id 代表每首歌的编号, artist?id代表每个歌手的编号,也就是随便更改编号,应该能进入对应的歌曲或歌手的的页面。哇, 我周杰伦才只能 6452, 我要看看1是谁。 呃......好吧,到处都是404。
回归正常操作。
根据前面对网页url的分析,可以知道前面已经获取了的歌曲id ,就是我们这里进入下一个页面的钥匙。哇, 芝麻开门~~~
继续利用开发者工具分析网页评论部分,可以看出我们需要的总评论数的位置,以及单条评论的位置。包括评论用户名称、内容、点赞数。所以现在我们需要get到这部分内容。
而这里,我们看到这个响应对应的消息头里,请求网址和方法,是一个post请求。(chrome突然崩溃了。很忧伤,只能用第二喜欢的 火狐 浏览器了)
对应的参数页参数,这明显应该是一个加密的参数。不知道复制可不可以有用。试试再说。2333333
设置好请求头和参数数据,利用post请求获取相应
header = {'User_Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0',
'Referer': 'http://music.163.com/song?id=531051217'}
data = {
"params": params,
"encSecKey": encSecKey
}
response = requests.post(song_url, data=data, headers=header)
虽然得到的response是一个200响应,代表我访问成功,但是输出response.text()却得到如下信息:
{"code":-460,"msg":"Cheating"}
呃....我觉得我被套路了,这应该就是传说中的反爬虫机制了吧。。可是我已经写过头了呀。
于是我干脆把请求头里面的所有东西全加进去
header = {
'Host': 'music.163.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36',
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.8'
}
呃。。。。这个反爬机制... 好吧。我们成功的获取了评论列表。由于这里是json编码的,我们也可以利用json库来解析。
然后我们就可以得到我们想要的一切了。。。。
hot_comments = json_dict['hotComments']
count_comments = json_dict['total'] # 总评论数
for item in hot_comments:
comment = item['content'] # 内容
likedCount = item['likedCount'] # 点赞总数
nickname = item['user']['nickname'] # 昵称
然后你就可以把这些存下来慢慢看咯。。当然,如果你能写入数据库的话也不错来着。
ok。打完手工~! 我要再去玩新的拉。