高效自动化网易云爬虫系统,自动寻找未爬取的歌曲、用户进行数据爬取并无限循环,理论上只要时间够就能爬取几乎所有网易云的歌曲和用户信息。笔者用大约24小时的时间就获取了如题的战果。
先展示一下成果:
music.csv存储每首歌的歌曲id、歌名、歌手、专辑、专辑图片url和评论数量信息,部分截图:
comment.csv存储每首歌的热评,包括评论所属歌曲id、评论用户id、评论获赞数、评论内容和评论时间信息。部分截图:
user.csv存储用户信息,包括用户id、昵称、等级、vip类型、生日、所在地区、粉丝数量、头像url等信息。部分截图:
程序设计思路
在开始之前,先隆重介绍一个python库:cloudmusic,这个库可以让网易云爬虫变得十分简单,非常适合大规模爬虫系统的设计,可以节省很多很多代码。官网:http://cloudmusic.cool/
github:https://github.com/p697/cloudmusic
我的思考流程大约是这样:
网易云的的每首歌都有自己独立的id,而只要获得了歌曲id就可以通过网易的各种api接口获取歌曲的相关数据。那么如何获取歌曲id就成为了关键。
假如我们只需要爬单个歌曲的信息,就用 Get Lucky 这首歌为例。首先我们去网易云官网找到Get Lucky这首歌的歌曲id,再借助python的cloudmusic库,只要这么写即可:
import cloudmusic
music = cloudmusic.getMusic(26349642)
# 不会从网易云官网获取某首歌的id,请自行百度
print("歌曲名称:{}".format(music.name))
print("歌手:{}".format(music.artist))
ccount = music.getCommentsCount()
print("评论数量:{}".format(ccount))
运行结果如下:
也可以通过关键字搜索来获取,代码示例:
music = cloudmusic.search("Get Lucky")[0]
print("歌曲名称:{}".format(music.name))
print("歌手:{}".format(music.artist))
ccount = music.getCommentsCount()
print("评论数量:{}".format(ccount))
运行结果和上面相同。
能获取这些数据,我们就能把数据保存在本地csv或数据库中。而如何批量的获取歌曲id就是关键。只要有个歌曲id,就可以轻松的获取这些歌曲信息。那么除了去官网查看之外,还有什么方法可以获取歌曲id呢?
获取歌曲id方法一:从歌单里获取
熟悉网易云爬虫或网易api的朋友肯定知道,歌单中的每首歌都是通过歌曲id来定位的。只要有了一个歌单,我们就可以获取这个歌单内所有的歌曲id。而cloudmusic库对这一特性进行了包装,可以直接生成一个歌单内所有歌曲的music对象,每个music对象都包含了这首歌的全部信息。而这里又涉及到网易云的歌单id。
代码示例:
musiclist = cloudmusic.getPlaylist(2850578667)
# 通过歌单id来定位歌单
for music in musiclist:
print("歌曲名称:{}".format(music.name))
结果就不展示了,musiclist是music对象组成的列表,循环这个列表就可以获取歌单内每首歌的各种信息。不会使用cloudmusic库的话可以去看看官网或者github看看示例和文档,链接在上面。
问题又来了:如何获取歌单id呢?可以从用户创建和收藏的歌单里获取。代码如下:
user = cloudmusic.getUser(265360741)
# 通过用户id获取user对象
playlists = user.getPlayList()
上述代码中,变量playlists包含了该用户创建和收藏的所有歌单。是不是很方便?但这里又遇到一个问题了:怎么获取用户id呢?
获取歌曲id方法二:从用户的听歌排行里获取
代码如下:
user = cloudmusic.getUser(265360741)
# 通过用户id获取user对象
musiclist = user.getRecord()
变量musiclist及包含了用户听歌排行中的所有我们想要的歌曲id。但是用户id该怎么获取呢?
上述两种获取歌曲id的方法都需要用户id。也就是说,只要有了用户id,就会有源源不断的歌曲id。如何获取用户id呢?一个方案是从评论中获取。先获取一首歌的评论,每条评论的评论用户就可以拿来用了!代码如下:
music = cloudmusic.getMusic(26349642)
# 先老样子通过歌曲id获得music对象
comments = music.getHotComments()
# 获取本首歌的所有热评,返回值是列表
for comment in comments:
print(comment['userId'])
# 打印出每条评论的用户id
看到这里,读者可能就会问了:饶了一大圈,还是要通过歌曲id,才能获得用户id呀。但这正是我们想要的,不知道大家有没有发现,这是一个圈,一个永无止境的圈。我们先人工找到一首歌的歌曲id,通过这个歌曲id获得了每条热评的用户id,再通过用户id获取用户的歌单或听歌排行,通过歌单或听歌排行获取歌曲id,再通过歌曲id获取用户id,再…
总结一下,这个圈长这样:
这样的话,只要一个起步的歌曲id,就可以按着这个圈一圈一圈的转,永无止境。只要转到的歌曲、用户或评论是没爬取过的,就把数据存储到本地。只要ip不被封,这个圈就可以一直转下去。
这就是我的思路,之后花了一天多的时间把他变为了现实。中间也遇到了一些困难,比如我要歌曲信息、用户信息、评论信息一起爬,速度太慢,但多线程一起跑太快了又容易被封ip。于是加入了ip池等设计,就可以快乐的爬爬爬了。最后开了一台云服务器,50线程并行爬了一整天,效果还算比较满意。
具体的代码我稍后会整理一下发出来。