爬完网易云歌曲评论之后就想看一下歌手的粉丝的地域分布情况,于是我就把歌手的全部粉丝数据爬取下来,提取其中的地理位置信息来制作一个热力图,这样就能生动地展示歌手全部粉丝的地域分布情况了。下面我就来分享一下如何制作网易云歌手粉丝地域分布热力图,我们就以AlanWalker为例,看看他的粉丝地域分布情况。
一,制作思路
首先找到歌手的个人主页,接着爬取粉丝的个人id号,由于这里没有粉丝的地理位置信息,因此我们需要通过粉丝的id号,我们构造粉丝个人主页的URL,提取他的地理位置信息,因为地理位置信息是6位的编码,我们又需要将6位的编码转换成中文地理位置,中文地址通过百度地图的正地理编码服务 将地理位置转换为经纬度。然后统计相同地域下有多少粉丝,根据 地理位置:粉丝数量 的字典形式写入到热力图的模板文件中去,最后展示网页格式的热力图。
二,爬取歌手粉丝的id号
https://music.163.com/#/user/home?id=1292848462
点击粉丝数据,我们便能看到他的全部粉丝,由于他的粉丝特别多,有206万。所以分了很多页来展示,每页有20个。这和歌曲评论的展示类似,分析发现它也是通过Ajax来加载的,而且加密了,加密方式同歌曲评论。URL为:
https://music.163.com/weapi/user/getfolloweds?csrf_token=
打开控制台的调试工具,我们来看一下它的加密变量的变化规律,通过调试发现:
# aid为歌手的id号 id_msg = '{userId: "' + aid + '", offset: ' + str(offset) + ', total: "true", limit: "20", csrf_token: "cdee144903c5a32e6752f50180329fc9"}'
知道了第一个值我们就能通过加密得到post的data值,从而发起post请求就能获取到歌手粉丝的id号。
三,获取粉丝的地址编码
我们点击任意一个粉丝进入到他(她)的个人主页,打开浏览器的控制面板点击–network–xhr–再点击左上角地址栏旁边的重新加载,你会发现一个URL为:
https://music.163.com/weapi/user/playlist?csrf_token=
的XHR请求,这个请求的返回的json中有粉丝的地址信息,来看一下这个json文件中的部分数据:
code: 200 more: false playlist: [{subscribers: [], subscribed: false,…}, {subscribers: [], subscribed: false,…},…] 0: {subscribers: [], subscribed: false,…} adType: 0 anonimous: false artists: null cloudTrackCount: 0 commentThreadId: "A_PL_0_2241455810" coverImgId: 528865094312508 coverImgUrl: "http://p1.music.126.net/Hd_kop7Wk57OLK9OVH8JQg==/528865094312508.jpg" createTime: 1527297408633 creator: {defaultAvatar: false, province: 110000, authStatus: 0, followed: false,…} accountStatus: 0 authStatus: 0 authority: 0 avatarImgId: 109951163316895860 avatarImgIdStr: "109951163316895858" avatarImgId_str: "109951163316895858" avatarUrl: "http://p1.music.126.net/cWSe1oW60F99c4L-XbiVcQ==/109951163316895858.jpg" backgroundImgId: 109951162868128400 backgroundImgIdStr: "109951162868128395" backgroundUrl: "http://p1.music.126.net/2zSNIqTcpHL2jIvU6hG0EA==/109951162868128395.jpg" birthday: -2209017600000 city: 110101 defaultAvatar: false description: "" detailDescription: "" djStatus: 0 expertTags: null experts: null followed: false gender: 2 mutual: false nickname: "十五娘711003" province: 110000 remarkName: null signature: "" userId: 1467902687 userType: 0 vipType: 0 description: null highQuality: false id: 2241455810 name: "十五娘711003喜欢的音乐" newImported: false ordered: false playCount: 33 privacy: 0 specialType: 5 status: 0 subscribed: false subscribedCount: 0 subscribers: [] tags: [] totalDuration: 0 trackCount: 42 trackNumberUpdateTime: 1537483987060 trackUpdateTime: 1538709284756 tracks: null updateTime: 1537483987060 userId: 1467902687
她的地址信息为:city: 110101,她的用户id号为:userId: 1467902687。仔细分析发现这又是一个Ajax请求,而且也做了加密,加密方式同上。因此我们需要分析它的加密内容,调试后发现:因此我们可以得到window.asrsea()函数的第一个参数为:
# uid 为粉丝的id号,其他都是固定值 id_msg = '{uid: "' + str(uid) + '", wordwrap: "7", offset: "0", total: "true", limit: "36", csrf_token: ""}'
这样根据前面获取到的粉丝id号,我们可以得到粉丝的地址编码。注意:这两步的调试断点的位置一定要打在合适的位置,否则难以得到window.asrsea()函数第一个参数的值。
四,将地址编码转换为中文位置
由于六位的城市编码是不能通过百度地图开放平台的web服务API来获取经纬度信息的,因此我们需要将六位的城市编码转换成中文地址。我的做法是通过2018年8月中华人民共和国县以上行政区划代码 进行转换的。先将该网站上的代码 地理位置信息爬取下来制成字典,再利用字典的键值关系进行转换。
五,统计同一地理位置的粉丝个数
定义一个函数来统计粉丝数,并返回格式为{“中文地理位置”: “该地理位置的粉丝个数”}的字典
# 返回格式为{"中文地理位置": "该地理位置的粉丝个数"}的字典 def convert_code_loc(locs): counts = {} ls = [] i = 1 for line in open('fansinfo.txt', encoding='utf-8').readlines(): ls.append(eval(line)['location']) i += 1 # 用于计算粉丝个数 # print("有{}行".format(i)) for word in ls: counts[word] = counts.get(word, 0) + 1 loc_counts = {} # 统计没有对应中文地理位置的城市编码个数 j = 1 for key in counts.keys(): if str(key) in locs: loc_counts[locs[str(key)]] = counts[key] else: print("城市编码为{}没有对应的中文地理位置".format(key)) j += 1 pass # 统计没有对应中文地址的编码个数 # print("总共有{}个城市编码没有对应的中文地理位置".format(j)) # print(loc_counts) return loc_counts
六,经纬度转换
这里我们要用到百度地图开放平台的正地理编码服务,使用前请先阅读一下官方的参考文档,这里我就直接定义一个函数进行经纬度的转换:
# 获取地理位置的经纬度 def getlnglat(address): url = "http://api.map.baidu.com/geocoder/v2/" output = 'json' # 密钥需要到百度开发者平台申请 ak = '这里填写你申请的百度开发者密钥' addr = quote(address) uri = url + '?' + 'address=' + addr + '&output=' + output + '&ak=' + ak req = urlopen(uri) res = req.read().decode() temp = json.loads(res) return temp
获取服务密钥(ak),返回的是json 格式的数据。
七,制作热力图
我们将经纬度转换后形如:
{"lat":30.800965168237234,"lng":106.10555398379239,"count":43}
的数据插入到热力图模板文件中,然后在浏览器中打开HTML格式的热力图文件,我们就能看到歌手粉丝地域分布的热力图了。热力图模板文件(html格式)在我的github的README.md中,获取全部源代码:网易云音乐歌手粉丝地域分布热力图。下面来看一下歌手薛之谦部分粉丝地域分布热力图:
点击显示热力图,缩放地图即可查看!
转载请注明:志颖博客 » 制作网易云音乐歌手粉丝地域分布热力图