Python爬虫进阶实战一——网易云音乐歌曲和评论的爬取

Python kingmo888 1088℃ 0评论

目标设定

1、本次爬虫的目标内容:N多个歌曲的歌名、演唱者、评论数量、评论内容评论的点赞数量。

2、对爬虫抓取下来的数据进行数据清洗。

3、对清洗后的数据进行分析,比如以评论数判断最受欢迎的歌曲top10;所有歌曲评论按照演唱者累加判定最受欢迎的歌手;分析点赞超过1000的评论的字数,用以判断是一句话戳中,还是感情牌戳中点赞人的认同点,等等。

项目分析

对网易云音乐进行分析,经过分析其排行榜等推荐里面只有前一二百的歌曲,存在大量音乐列表的地方在歌单里面,热门歌单有将近40页,每页35个歌单,每个歌单列表中都存在几十上百首歌,40*35*50估算下大约7万首歌,基本满足我们的需求。

如此,可以初步构思整个爬虫的执行流程:

1、获得所有歌单id

  • 找到歌单列表页面的首页
  • 分析歌单列表一共多少个页面
  • 分析歌单列表页面的元素,提取每一页中的歌单id。

2、获取所有歌曲的基本信息

  • 在歌单页面信息中可以提取【歌曲标题】、【歌手】、【所属专辑】。(如下图)

3、获取网易云音乐中每首歌的评论。

爬虫开发

1、获取歌单列表页总页码。

我们通过源文件看到页码信息是静态数据,而不是js动态生成的,可以直接抓取源码来获得。一共38页。

实际上,如果是一次性爬虫,我们可以直接通过指定最大页码数量,然后循环构建歌单列表url集就可以了,在这里呢为了实现一键启动直接可用,我们把所有环节都以自动化为目的。下面开始爬虫的开发流程,

第一步,引入相关库,并构造一个request header

import requests, os
from pyquery import PyQuery as pq
headers_play = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
 'Accept-Encoding': 'gzip, deflate, br',
 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
 'Cache-Control': 'no-cache',
 'Connection': 'keep-alive',
 'DNT': '1',
 'Host': 'music.163.com',
 'Pragma': 'no-cache',
 'Upgrade-Insecure-Requests': '1',
 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'}

然后,我们获取歌单首页的源码并提取出页码总数。

baseurl = 'http://music.163.com/discover/playlist/'
response = requests.get(baseurl, headers=headers_play)
content = response.content.decode()

执行后通过查看状态码来判断是否访问成功,可以看到访问成功了:

response.status_code

Out[3]: 200

而源码内容与网页一致:

其链接页码的链接格式为:<a href="/discover/playlist/?order=hot&cat=%E5%85%A8%E9%83%A8&limit=35&offset=1295" class="zpgi">38</a>,也就是a标签,class为zpgi,一共有9个,只要解析出了这9个,最后一个值就是总页码了。我们尝试并打印出来看一下:

doc = pq(content)
page_area = doc('a.zpgi')
total_page_num = int(page_area.eq(-1).text())
print('总页码:',total_page_num)

总页码: 38

说明完全没有问题了。

2、解析歌单ID

解析规则同理,查看歌单链接主要区域的css规则:

<a title="你曾经有多认真的喜欢一个人" href="/playlist?id=2610231104" class="tit f-thide s-fc0">你曾经有多认真的喜欢一个人</a>

也是a标签,class为tit f-thide s-fc0,这里需要注意,如果class的标签中含有空格,直接以'.'来代替。原因同CSS的设计规则。提取一下试试,总数量应该有35个:

#%% 获取歌单列表页歌单id

playlist_area = doc('a.tit.f-thide.s-fc0')
print(len(playlist_area))
playlist_ids = [x.attr('href').split('?id=')[-1] for x in playlist_area.items()]
print(playlist_ids)

3、解析歌单中歌曲ID

这里剧透一下,通过查看网页源码可以看出,源码地址与源地址显示是有一些差别的,我们需要以源文件的地址来获取内容。

在歌单列表中的源码中,我们通过几个层次关系就能快速准确的定位到歌曲链接,如图:

分别是div->song-list-pre-cache, ul->f-hide,在ul内就是纯净的歌曲链接a标签。我们可以直接在pyquery中使用连续定位,只要在不同的标签之间空格即可。同时对于标签为id的,以#间隔,class的以.间隔。

ne_playlist_url = 'https://music.163.com/playlist?id=2610231104'
response = requests.get(one_playlist_url, headers=headers_play)
content = response.content.decode()
doc = pq(content)
songid_area = doc('div#song-list-pre-cache ul.f-hide a')
print(len(songid_area))
all_song_ids = [x.attr('href').split('?id=')[-1] for x in songid_area.items()]

歌曲id搞定!

4、重磅部分:获取歌曲具体信息、评论信息

这里我们简化教程内容,通过分析源文件可以知道在title标签和meta描述标签中就包含了歌名、演唱者、所属专辑的信息,实现方法如下:

song_info = {}
meta = doc('meta')
for x in meta.items():
    if x.attr.name == 'description':
        description = x.attr.content
        #print(description)
        song_info['description'] = description.split('所属专辑:')[-1] if '所属专辑:' in description else ''
name, singer, *_ = doc('title').text().split(' - ')
song_info['singer'] = singer
song_info['song_name'] = name
print(song_info)  

注意,其中name, singer, *_ 种的*_是因为可能有不确定的返回值被忽略,不能用一个或者几个_占位符。

4.2、获取评论信息

对于网易云音乐歌曲的评论,真是一波三折,具体信息就不展开了,这里提供一下知乎@平胸小仙女的答案,其中提供了非常详细的解决思路,如果想要学习具体如何做到的,请查看问题:《如何爬网易云音乐的评论数?》下的该答案,可以说写的非常清晰了。答案中提供了源码,但由于源码是py2版本的不适用python3环境同时格式有些乱,因此,博主在源代码的基础上做了修改和升级,一方面将其修改升级为python3专用版本另一方面更加方便调用,只需要传入歌曲的id即可获取该歌曲下的所有评论。

5、爬虫的去重以及提高爬虫的可用性

整个爬虫的主要业务模块已经都走通了。此后,我们可以封装成函数来方便我们的后续操作。这里要着重说几个重要的地方:

业务量庞大的时候,一定要结合数据库。

一定要做好爬虫进度标记,爬虫去重。

初期已经测算过,云音乐的数据量不会特别大,因此简单使用文本存储就可以了,一个文本记录已经爬取到的歌单信息、一个记录歌曲id信息,一个文件夹保存记录一首歌的详细json信息(名称、演唱者、评论数、热门等等)。


欢迎关注公众号:python_trader,最新爬虫资源/教程、量化交易资源/教程都放在上面。

本系列爬虫教程源码,请在公众号回复爬虫即可获得。

转载请注明:Python量化投资 » Python爬虫进阶实战一——网易云音乐歌曲和评论的爬取

喜欢 (0)or分享 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址