有什么问题欢迎大家加QQ群:565712652进行讨论!

制作网易云音乐歌手粉丝地域分布热力图

Python爬虫 Jason zhou 4850℃

爬完网易云歌曲评论之后就想看一下歌手的粉丝的地域分布情况,于是我就把歌手的全部粉丝数据爬取下来,提取其中的地理位置信息来制作一个热力图,这样就能生动地展示歌手全部粉丝的地域分布情况了。下面我就来分享一下如何制作网易云歌手粉丝地域分布热力图,我们就以AlanWalker为例,看看他的粉丝地域分布情况。

一,制作思路

首先找到歌手的个人主页,接着爬取粉丝的个人id号,由于这里没有粉丝的地理位置信息,因此我们需要通过粉丝的id号,我们构造粉丝个人主页的URL,提取他的地理位置信息,因为地理位置信息是6位的编码,我们又需要将6位的编码转换成中文地理位置,中文地址通过百度地图的正地理编码服务  将地理位置转换为经纬度。然后统计相同地域下有多少粉丝,根据 地理位置:粉丝数量 的字典形式写入到热力图的模板文件中去,最后展示网页格式的热力图。

二,爬取歌手粉丝的id号

AlanWalker的个人主页

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中,获取全部源代码:网易云音乐歌手粉丝地域分布热力图。下面来看一下歌手薛之谦部分粉丝地域分布热力图:

点击显示热力图,缩放地图即可查看!

转载请注明:志颖博客 » 制作网易云音乐歌手粉丝地域分布热力图

喜欢 (12)or分享 (0)