Blog

Keep up to date with the latest news

acfun网站400W用户数据分析和pyecharts可视化

首先在这给我心爱的Acfun说句抱歉了,这几天进行的数据爬取如果对猴山产生了不好的影响,请接受我的道歉。 本次所有代码都会上传到GitHub上:爬虫部分和ip搜索部分 sql文件地址:百度云盘 密码:5xov 项目代码分成三个部分: 1、爬取基础数据 2、根据ip地址查询相对应的省市地址 3、统计:将你想查看的html复制下来然后网页打开就能看到效果了

本次实例是通过分析A站获取用户数据的接口,通过scrapy获取每个用户的一些基本资料。包括ip,用户名,最后登录时间,注册时间等。 本次总共获取的详细数据有4302457条,详细数据有:798817。数据丢失量在5%左右,由于A站的多次宕机和高层变动等原因,以及今年上半年‘凉了’的故事,或许对数据有一定的影响。导致本次数据获取与统计,在14年前的统计感觉有失真实性。姑且就先这样吧。 本次统计有: 1、从建站以来到2018-8月每年用户注册数量和消失数量柱状图 2、所有记录中性别比例饼图 3、所有修改了个性签名用户中,出现最频繁的词,生成词云图 4、从2018-01-01以来,所有登录过A站的用户全国省分布图 (正常情况下应该统计的事距离查询完日期后,往前两个月或者一个月仍会登录的用户为活跃用户) 5、每年注册人数和十二个月中,每个月注册人数折线图和柱状图 本次所有统计生成工具为pyecharts。 为了方便展示,我在用pycharts生成文件时,生成了png,其实这个生成html所形成的效果图是最直观的。页面上会有一些动态操作可以进行。 统计1: 从图中可以看出,17年的各种动荡和视频内容的不完善与落后,让许多Acer的脚步停留在了17年里。 而18年的“A站已凉”更是加剧了这种显现的出现。一直到几年8月份,A站活跃用户和新增的数量也往往不及前两年。

统计2:

对,相信自己的眼睛,这大部分都是女性。 事实上是真的嘛? 不是的。今年上半年有一次数据调整,猴子在修改还是转移数据的时候,将大部分人的性别修改成了女性 统计3: 词云图生成可以看: 虽然A站的用户以基佬遍天下而乐于自嘲,但是在个签上能体现出的真不多,大多数是up主的一些微博微信qq群啥的,但是由此也能看到一些正常的感悟人生和个人兴趣。 统计4: 由图中可看出,A站用户主要还是分布在中部和东部地区。 在数据统计当中,还有国外的数据未统计在地图中,计划是在世界地图中展示,然而pyecharts的作者们没有添加世界地图国家经纬度搜索,需要手动进行。有时间再做吧。需要一个个查坐标的。。 但是看在控制台输出的数据中,各个发达国家和日本韩国登录用户较多,也就是说大多数都是留学生出国在外的人访问的多。(还有一些战乱国家也有登录的,大兄弟!牛逼!) 统计5: 由这个统计可以看出来,每年的秋冬季节是注册人数的高峰期,或许是因为天气变冷,大家都不想出门,开始存膘过冬的习性,宅家里进行一些网上娱乐就变多了。而春夏季节,则是减少的。春天了,又到了交配的季节了。。。你懂的,多出门约小姐姐,解决终身大事吧。 统计的相关代码:

# -*- coding: utf-8 -*-

from pyecharts import Bar

from pyecharts import Pie

from pyecharts import Line

from pyecharts import Geo

import urllib.request

import urllib.parse

import json

import pymysql

# 获取指定区间内男女比例

def create_gender_round():

sql = "select gender,count(*) from user_info group by gender "

datas = get_all_data(sql)

info_name = ['隐藏', '男性', '女性', 'Acer']

man = 0

women = 0

Xman = 0

acer = 0

for i in datas:

if i[0] == -1:

Xman = i[1]

elif i[0] == 1:

man = i[1]

elif i[0] == 0:

women = i[1]

elif i[0] == 2:

acer = i[1]

pie = Pie('男女用户比例')

pie.add('性别比例图', info_name, [Xman, man, women, acer], radius=None, center=None, rosetype='')

# rosetype 是否展示成南丁格尔图,通过半径区分数据大小,有

# 'radius'和'area'两种模式。默认为

# 'radius'

# radius:扇区圆心角展现数据的百分比,半径展现数据的大小

# area:所有扇区圆心角相同,仅通过半径展现数据大小

# pie.render('detail\性别比例图.html')

pie.render('detail\比例图.png')

# 每年注册人数

def create_bar_year():

sql = "select regtime from user_info order by regtime"

data = get_all_data(sql)

yera = {}

for i in data:

y = i[0][0:4]

if y in yera:

count = yera.get(y)

count += 1

yera[y] = count

else:

yera[y] = 0

bar = Bar("每年注册人数", "按年划分")

bar.add("", list(yera.keys()), list(yera.values()))

# 生成折线图

create_lin('每年注册人数', list(yera.keys()), list(yera.values()), '每年注册人数')

bar.render(path='detail\注册人数划分_年.html')

# 每个月注册人数

def create_bar_month():

sql = "select regtime from user_info order by regtime"

data = get_all_data(sql)

months = {'01': 0,

'02': 0,

'03': 0,

'04': 0,

'05': 0,

'06': 0,

'07': 0,

'08': 0,

'09': 0,

'10': 0,

'11': 0,

'12': 0,

}

for i in data:

regTime = i[0][5:7]

count = months.get(regTime)

count += 1

months[regTime] = count

create_lin('每个月注册人数', list(months.keys()), list(months.values()), '')

bar = Bar("每个月注册人数", "按月划分")

bar.add("", list(months.keys()), list(months.values()))

#生成折线图

create_lin('注册人数划分_月',list(months.keys()),list(months.values()),'注册人数划分_月')

bar.render(path='detail\注册人数划分_月.html') # 生成本地 HTML 文件

# 根据sql获取指定区间内的数据

def get_all_data(sql):

conn = pymysql.connect(host="localhost", user="root", passwd="Cs123456.", db="acfun", charset="utf8")

cursor = conn.cursor()

cursor.execute(sql)

data = cursor.fetchall()

cursor.close()

conn.close()

return data

# 注册人数与当年活跃人数对比图

def year_2():

sql = "select regtime,lastLoginTime from user_info order by regtime"

data = get_all_data(sql)

yera = {}

for i in data:

y = i[0][0:4]

y2 = str(i[1])[0:4]

if y in yera:

count = yera.get(y)[0]

count += 1

yera[y][0] = count

if y2 in yera:

count_2 = yera.get(y2)[1]

count_2 += 1

yera[y2][1] = count_2

else:

yera[y2] = [0, 0]

else:

yera[y] = [0, 0]

bar = Bar("年注册人数与每年最后一次上线人数", "按年划分")

bar.add("", [k for k in sorted(yera.keys())], [yera[k][0] for k in sorted(yera.keys())])

bar.add("", [k for k in sorted(yera.keys())], [yera[k][1] for k in sorted(yera.keys())])

bar.render(path='detail\每年注册人数与每年最后一次上线人数.html')

# 折线图,若想显示两条或多条,自己处理下,就是多加个add的事情

def create_lin(h_name, k, val, line_name):

line = Line(h_name)

line.add(line_name, k, val, mark_point=["average"])

line.render('detail\%s_折线图.html' % h_name)

#全国地图点状图用到的方法

def geo_formatter(params):

return params.name + ' : ' + params.value[2]

# map图,指定区间内,全国省用户分布图

def Geo_create():

sql = "select comeFrom,count(*) from user_info where 1=1 and comeFrom is not NULL and comeFrom !='未知' and comeFrom !='' and lastLoginTime >= '2018-01-01 00:00:00' group by comeFrom order by comeFrom"

datas = get_all_data(sql)

city = {}

country = {}

for data in datas:

#数据整理

b = data[0].find(',')

s = data[0].encode('utf-8').decode('utf-8').find('市')

sheng = data[0].encode('utf-8').decode('utf-8').find('省')

zzq = data[0].encode('utf-8').decode('utf-8').find('自治区')

if b is not -1:

res, count = get_city_name(data, b, city)

# print('b',data[0], '---', res, '-----', count, '----', sheng)

if res in city:

count = city[res]

count += data[1]

# print(res, '---', count)

city[res] = count

else:

city[res] = data[1]

elif zzq is not -1:

res, count = get_city_name(data, zzq, city)

# print('zzq',data[0], '---', res, '-----', count, '----', sheng)

if res in city:

count = city[res]

count += data[1]

# print(res, '---', count)

city[res] = count

else:

city[res] = data[1]

elif sheng is not -1:

res, count = get_city_name(data, sheng, city)

# print('sheng',data[0], '---', res, '-----', count, '----', sheng)

if res in city:

count = city[res]

count += data[1]

# print(res, '---', count)

city[res] = count

else:

city[res] = data[1]

elif s is not -1:

res, count = get_city_name(data, b, city)

# print('s',data[0], '---', res, '-----', count, '----', sheng)

if res in city:

count = city[res]

count += data[1]

# print(res, '---', count)

city[res] = count

else:

city[res] = data[1]

else:

# print(data[0],'------',data[1])

if data[0] in country:

count = country[data[0]]

count += data[1]

else:

country[data[0]] = data[1]

#去掉不识别的数据

del city['海外']

del country['AFRINIC']

del country['APNIC']

del country['RIPE']

del country['IANA']

del country['运营商级NAT']

country['中国'] = 0

for i in city:

country['中国'] += city[i]

f_country = {}

for i in list(country.keys()):

f_country[fanyi(i)] = country.pop(i)

# print(city)

print(f_country)

create_geo('2018截止8月全国Acer省分布情况', '', city, 'detail/2018截止8月全国Acer省分布情况.html', 'china')

# create_geo('2018截止8月全世界Acer省分布情况', '', f_country, 'detail/2018截止8月世界Acer省分布情况.html', 'world')

#原本打算做世界地图的,所以做了中文翻译的请求

def fanyi(content):

url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&sessionFrom=http://fanyi.youdao.com/'

# 有道翻译查询入口

data = { # 表单数据

'i': content,

'from': 'AUTO',

'to': 'AUTO',

'smartresult': 'dict',

'client': 'fanyideskweb',

'doctype': 'json',

'version': '2.1',

'keyfrom': 'fanyi.web',

'action': 'FY_BY_CLICKBUTTION',

'typoResult': 'false'

}

data = urllib.parse.urlencode(data).encode('utf-8')

# 对POST数据进行编码

response = urllib.request.urlopen(url, data)

# 发出POST请求并获取HTTP响应

html = response.read().decode('utf-8')

# 获取网页内容,并进行解码解码

target = json.loads(html)

# json解析

return target['translateResult'][0][0]['tgt']

#屏蔽的全国地图的点状图

def create_geo(pname, cname, data, path, map_type):

# geo = Geo(pname, cname, title_color="#fff", title_pos="center", width=1200, height=600,

# background_color="#404a59", )

# attr, value = geo.cast(data)

# geo.add("", attr, value, type="heatmap", is_random=True, is_legend_show=False,

# maptype=map_type,

# tooltip_formatter=geo_formatter, # 重点在这里,将函数直接传递为参数。

# effect_scale=5)

#

geo = Geo(

pname,

cname,

title_color="#fff",

title_pos="center",

width=1200,

height=600,

background_color="#404a59",

)

attr, value = geo.cast(data)

geo.add(

"",

attr,

value,

type="heatmap",

maptype=map_type,

is_visualmap=True,

visual_range=[0, 300],

visual_text_color="#fff",

)

geo.render(path=path)

#对查询到的城市名称数据进行过滤和数字统计

def get_city_name(data, n_len, city_list):

res = data[0][0:n_len]

count = 0

if res in city_list:

count = city_list[res]

count += data[1]

else:

count = data[1]

return res, count

if __name__ == '__main__':

#create_gender_round()

#create_bar_month()

#create_bar_year()

#year_2()

Geo_create()

好了。本次统计到此结束。谢谢观看。 pyecharts真的是一个非常方便的数据图形展示工具,我这里只是使用了最简单的几个样板,还有更多更有趣也更科学的关系图形展示,详情请点击:pyecharts中文说明文档