python支付宝蚂蚁森林_Python数据可视化-支付宝蚂蚁森林能量收取记录

支付宝蚂蚁森林模块最早从2016年推出,题主最开始从支付宝集福活动开始接触。期间懒懒散散收过一些能量,但是相比朋友圈动辄几十几百公斤的能量值,我的能量值只有20Kg,想种棵胡杨连零头都不够。所以,本着节流开源的想法,题目决定利用Python分析一下,平时自己的能量都去哪了。

1、获取蚂蚁森林的收取记录

由于蚂蚁森林的收取记录只在手机App上显示,所以想要获得还得想些办法。经过一番查找,决定使用AutoJs,这是一个使用JS来进行自动化测试的软件。截止现在,免费版的Android版本在酷安软件市场已经下载不到了,题主的是之前安装的版本4.0.1。

但是目前支付宝版本升级之后,现有代码基本失效,有能力的童鞋可以自行修改,运行之后会在目录下生成recordEnergy.txt。我使用的是19年4月份抓取的数据记录,共抓取了49天的数据。

JS代码分析

收取记录的页面是一直可以往下翻的,加载时间约为0.5秒。所以写一个循环,一直翻页就好了。

auto()

toast("开始测试")

var isDown = true

for(var i=0; i<85; i++){

if(isDown){

sleep(random(3,6)*1000)

getInfo()

isDown = scrollDown()

log("动一下--》"+i)

}

else{

log("滑动失败")

sleep(100)

scrollUp()

sleep(100)

isDown = scrollDown()

sleep(random(3,6)*1000)

log("尝试滑动一下-----》"+i)

}

}

将获取到的记录信息写入文件:日期及时间、姓名、操作种类及能量数目。

function intoFile(information){

files.append("recordEnergy.txt", information+"\n")

}

主要获取信息的函数,遍历所有子控件,如果控件可见,就获取信息,也是为了避免重复抓取。

function getInfo(){

// 获取可见控件的信息

var first = className("android.webkit.WebView").findOnce()

var second = first.child(0).child(0).children()

second.forEach(

function(childPara){

if(childPara.visibleToUser() == true){

if(childPara.childCount() == 0){

var dayStr = childPara.contentDescription

log(dayStr)

}

else{

var timeStr = childPara.child(3).contentDescription

var nameStr = childPara.child(2).child(0).contentDescription

var numStr = childPara.child(2).child(1).contentDescription

var info = timeStr+"\t"+nameStr+"\t"+numStr+"\t"+dayStr

intoFile(info)

}

}

}

)

}

2、对原始数据进行清洗

对抓取到的.txt文件进行简单处理,这里题主使用的Excel。文件的信息有4类,其中对于姓名一栏,抓取的是人物昵称,需要一一核对替换;操作使用的是Excel的分列操作,当然直接使用正则表达式进行提取也是可以的;数量一栏,是以克为单位,没什么好说的;日期一栏是直接抓取的格式,后面会进行处理。另存为蚂蚁森林收取记录.csv文件即可。

姓名

操作

数量

日期

果子

帮忙收取/浇水/收取

12

2019/4/19 19:06

3、Python绘图展示

这里是本次的重点,使用的Python包为Numpy、Pandas、Matplotlib、Seaborn,请自行安装。下面开始介绍代码主体。

首先导入此次的包文件及一些设置

import numpy as np

import pandas as pd

import seaborn as sns

import matplotlib.pyplot as plt

# 显示中文和负号,务必确保安装了黑体的字体

plt.rcParams['font.sans-serif']=['SimHei']

plt.rcParams['axes.unicode_minus']=False

# 一些matplotlib画图的设置

large = 16; med = 12; small = 10

params = {'axes.titlesize': large,

'legend.fontsize': med,

'figure.figsize': (9, 6),

'axes.labelsize': large,

'axes.titlesize': med,

'xtick.labelsize': med,

'ytick.labelsize': med,

'figure.titlesize': large}

plt.rcParams.update(params)

# 设置使用漫画绘图模式,禁用可以返回普通模式

plt.xkcd()

a、数据格式处理

代码如下,都是一些pandas的基础操作,没什么好讲的。

origindData = pd.read_csv("蚂蚁森林收取记录.csv", encoding="gbk")

# 提取别人收取能量的记录

recordData = origindData[origindData["操作"]=="收取"]

# 重置索引

recordData.reset_index(drop=True, inplace=True)

# 转换日期格式

recordData['time'] = pd.to_datetime(recordData['时间'],infer_datetime_format=True)

对于人名,题主决定采用名称的缩写,保护一下别人的隐私。

# xpinyin这个python包

from xpinyin import Pinyin

p = Pinyin()

# 转换拼音

recordData["name"] = recordData["姓名"].apply(lambda x : p.get_initials(x, ""))

b、绘制收取能量的排行图

首先获取排行排名的数据

# 数据聚合

sumSeries = recordData.groupby("name")["数量"].sum()

# 将聚合的结果转换为dataframe

sumData = pd.DataFrame({"name": sumSeries.index, "count":sumSeries.values})

# 排序

sumData.sort_values("count", ascending=False, inplace=True)

# 重置索引

sumData.reset_index(drop=True, inplace=True)

然后对sumData绘图

fig, ax = plt.subplots()

# 共画15个

for i in range(15):

# 制定颜色

color = plt.cm.tab10_r(sumData.loc[i, "count"]/550)

# 画排行的竖直线

ax.vlines(sumData.loc[i, "name"], 0, sumData.loc[i, "count"], color=color, linewidth=2)

# 画竖直线上面的球

ax.scatter(sumData.loc[i, "name"], sumData.loc[i, "count"], color=color, s=50)

# 标注文字

ax.text(sumData.loc[i, "name"], sumData.loc[i, "count"]+15, color=color, s=str(sumData.loc[i, "count"]), fontsize=11, horizontalalignment='center', verticalalignment='bottom')

# 设置x坐标范围

ax.set_ylim(0,600)

# 设置标签

ax.set_xlabel("Short Name")

ax.set_ylabel("Number of Energy/g")

# ax.set_title("蚂蚁森林能量收取排行榜前15", size=20, loc="center")

# 设置坐表轴隐藏

ax.spines['right'].set_color('none')

ax.spines['top'].set_color('none')

# 保存图像

plt.savefig("XKCD-能量收取排行前15.png", dpi=300)

结果

蚂蚁森林能量收取排行前15.jpg

c、绘制每天各时段能量被收取的序列图

画主体图形

首先准备数据

# 将时间格式里面的小时和分钟,计算成分钟数

recordData["timeSeries"] = recordData["time"].apply(lambda x: x.hour*60+x.minute)

# 创建每半个小时的时间分箱数据

# 创建分箱的标签范围

def getTimeLabels(x=0,y=24,step=1):

timeLabels = []

for i in range(x,y,step):

for j in [":00", ":30"]:

timeLabels.append(str(i)+j)

return timeLabels

# 分箱的数值范围

timeBins = np.linspace(0, 1440, 49)

# 分箱的标签范围

timeLabels = getTimeLabels()

# 分箱操作

recordData["timeBins"] = pd.cut(recordData["timeSeries"], bins=timeBins, labels=timeLabels)

# 进行聚合操作

tempData = recordData.groupby("timeBins")["数量"].sum()

# 将结果转换为dataframe

recordBinsData = pd.DataFrame({"time":tempData.index, "number":tempData.values})

绘制图形

fig, ax = plt.subplots()

# 绘制所有时段的

for i in (recordBinsData.index):

# 产生颜色

color = plt.cm.tab10_r(recordBinsData.loc[i, "number"]/310)

# 画竖直线

ax.vlines(i, 0, recordBinsData.loc[i, "number"], color=color, linewidth=3)

# 画柱子上的球

ax.scatter(i, recordBinsData.loc[i, "number"], color=color, s=3)

# 设置坐标轴

ax.set_xlim(0, len(recordBinsData))

ax.set_ylim(0,1400)

# 设置Y轴刻度间隔

ax.yaxis.set_minor_locator(plt.MultipleLocator(100))

# 设置X轴间隔为1

ax.xaxis.set_minor_locator(plt.MultipleLocator(1))

# 设置X轴标签

plt.xticks( np.arange(0, 48, 5), recordBinsData[::5]["time"] )

# 设置坐表轴隐藏

ax.spines['right'].set_color('none')

ax.spines['top'].set_color('none')

# 设置网格线

ax.grid(alpha=0.1)

# 设置标签

ax.set_xlabel("Time")

ax.set_ylabel("Number of Energy/g")

添加子图操作

# 创建1分钟的分箱结果

# 创建分箱的标签范围

def getTimeLabels(x=7,step=1):

timeLabels = []

for j in range(0,60,step):

timeLabels.append(str(x)+":"+str(j))

return timeLabels

# 分箱的数值范围

timeSmallBins = np.arange(420, 481)

# 分箱的标签范围

timeSambllLabels = getTimeLabels()

# 分箱操作

recordData["timeSmallBins"] = pd.cut(recordData["timeSeries"], bins=timeSmallBins, labels=timeSambllLabels)

# 进行聚合操作

tempData = recordData.groupby("timeSmallBins")["数量"].sum()

recordSmallBinsData = pd.DataFrame({"time":tempData.index, "number":tempData.values})

绘制图形

# 添加子图

ax1 = fig.add_axes([0.5, 0.4, 0.4, 0.4])

# 添加图形

ax1.plot(recordSmallBinsData.index, recordSmallBinsData["number"], color="darkred", linewidth=1)

# 充填直线的颜色

plt.fill_between(np.arange(0,31), 0, 650, color="red", alpha=0.05)

plt.fill_between(np.arange(30,61), 0, 650, color="blue", alpha=0.05)

# 设置坐标轴

ax1.set_xlim(0,60)

ax1.set_ylim(0,250)

# 设置X轴间隔为1

ax1.xaxis.set_minor_locator(plt.MultipleLocator(2))

# 设置X轴标签

plt.xticks( np.arange(0, 61, 10), recordSmallBinsData[::10]["time"] )

# 设置标签

ax1.set_xlabel("Time", fontsize=med-1)

ax1.set_ylabel("Number of Energy/g", fontsize=med-1)

# 设置坐表轴隐藏

ax1.spines['right'].set_color('none')

ax1.spines['top'].set_color('none')

# 设置网格线

ax1.grid(alpha=0.1)

# ax.set_title("蚂蚁森林森林能量每天时段收取统计", size=20, loc="center")

# 保存图像

plt.savefig("XKCD-蚂蚁森林森林能量每天平均收取统计.png", dpi=300)

结果

蚂蚁森林森林能量每天平均收取统计.jpg

d、绘制这49天来的每天被收取能量的记录

首先获取数据

# 处理得到日期

recordData["date"] = recordData["time"].apply(lambda x : x.strftime("%Y-%m-%d"))

# 聚合操作

tempData = recordData.groupby("date")["数量"].sum()

# 将结果整理成dataframe操作

dateData = pd.DataFrame({"date":tempData.index, "number":tempData.values})

绘制折线图

fig, ax = plt.subplots()

# 画折线图

ax.plot(dateData.index, dateData["number"], color="darkred" , alpha=0.7, linewidth=1.5)

# 填充颜色

plt.fill_between(np.arange(0,27), 0, 350, color="green", alpha=0.04)

# 设置X轴坐标

ax.set_xlim(0, len(dateData))

ax.set_ylim(0, 350)

# 设置X轴间隔为1

ax.xaxis.set_minor_locator(plt.MultipleLocator(2))

# 设置X轴刻度

plt.xticks(np.arange(len(dateData)+1)[::12], [dateData.loc[x, "date"] for x in range(0, len(dateData), 12)])

# 设置标签

ax.set_xlabel("Date")

ax.set_ylabel("Number of Energy/g")

# 设置坐表轴隐藏

ax.spines['right'].set_color('none')

ax.spines['top'].set_color('none')

# 设置网格

ax.grid(alpha=0.1)

# ax.set_title("蚂蚁森林森林能量每天收取统计", size=20, loc="center")

# 保存图像

plt.savefig("XKCD-蚂蚁森林森林能量每天收取统计.png", dpi=300)

结果

蚂蚁森林森林能量每天收取统计.jpg

4、结果简单分析

a、从第一张排行图可以看出,能量收取最多的克数成阶梯状分布,以500、400、300、200左右具有台阶。这个分布并不是预想的顺滑下降;

b、从第2张每天的时段序列图可以看出,每天的7-8点、1-2点以及晚上的7-8点半是收取能量的高峰,基本都是吃完以后的休息时间啊。能量收取最多的时间段为早上的7点-8点,高峰开始的时间为7:28左右,别人都是早起收能量的啊;

c、最后一张日期分布图,左边阴影部分是假期时间,左边的峰值与低谷与右边的具有明显区别,看来假期和在校的日常活动不再同一个水平啊。

所以最后要想收集能量多,还是早点起床收能量吧,哈哈。

最后,转载请注明出处!!!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值