1. 程式人生 > >acfun網站400W使用者資料分析和pyecharts視覺化

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中文說明文件