Python和Perl绘制中国北京跑步地图的方法


Posted in Python onMarch 03, 2016

当你在一个城市,穿越大街小巷,跑步跑了几千公里之后,一个显而易见的想法是,我到底和之前比快了多少,跑量有何变化,如果能把在这个城市的所有路线全部画出来,会是怎样的景象呢?

1.数据来源:益动GPS

文章代码比较多,为了不吊人胃口,先看看最终效果:

Python和Perl绘制中国北京跑步地图的方法[/code]

首先需要有原始数据信息,手机上众多跑步软件提供了详细的记录,但它们共同的问题是不允许自由导入导出(可能是为了用户粘性吧)。因此有一块智能运动手表应该是不二之选。我的是Garmin Fenix3,推荐一下:

Python和Perl绘制中国北京跑步地图的方法

益动GPS算是业界良心了,能够同步咕咚,Garmin手表,悦跑圈的数据,因此我将其作为一个入口,抓取所有的GPS数据。

至于如何同步,可参考网站上的相关介绍,下面是我登录该网站后的截图:

http://edooon.com/user/5699607196/record/15414378

Python和Perl绘制中国北京跑步地图的方法

随便点进去以后,就可以看到导出路线的按钮:

Python和Perl绘制中国北京跑步地图的方法

无比坑爹的是,它不提供批量导出的按钮,几百条记录,依次导出都累死了。于是考虑用代码来编辑吧。

2. 获取益动网站上的数据

登录之后,可以看出它是动态加载,当滚轮滚到最下时,自动加载后面的内容。本来是应该嗅探和分析http请求的,后来懒惰了。当拖到底,全部加载完毕后,保存了当前的html文件。

接下来就是解析这个Html,基本上是通过XPath的来做的。有经验的同学看了下图就都明白了:

Python和Perl绘制中国北京跑步地图的方法

图中高亮的部分,就是要下载gpx文件的实际地址。我们将其保存在urllist中。同时,元数据被保存在json文件里。

folder = u'D:/buptzym的同步盘/百度云/我的文档/数据分析/datasets/rungps/';
cookie='JSESSIONID=69DF607B71B1F14AFEC090F520B14B55; logincookie=5699607196$6098898D08E533587E82B33DD9D02196; persistent_cookie=5699607196$42C885AD38F59DCA407E09C95BE1A60B; uname_forloginform="buptzym@qq.com"; __utma=54733311.82935663.1447906150.1447937410.1456907433.7; __utmb=54733311.5.10.1456907433; __utmc=54733311; __utmz=54733311.1456907433.7.3.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; cookie_site=auto'
userid='5699607196';
f = codecs.open(folder + 'desert.htm', 'r', 'utf-8');
html = f.read();
f.close();
root = etree.HTML(html)
tree = etree.ElementTree(root);
listnode=tree.xpath('//*[@id="feedList"]');
numre=re.compile(u'骑行|跑步|公里|,|耗时|消耗|大卡');
urllists=[]
records=[];
for child in listnode[0].iterchildren():
record={};
temp=child.xpath('div[2]/div[1]/a[2]')
if len(temp)==0:
continue;
source= temp[0].attrib['href'];
record['id']=source.split('/')[-1];
info=temp[0].text;
numinfo= numre.split(info);
if len(numinfo)<6:
continue;
record['type']= info[0:2];
record['distance']= numinfo[1];
record['hot']=numinfo[6];
urllists.append('http://edooon.com/user/%s/record/export?type=gpx&id=%s' % (userid, record['id']));

值得注意的是,因为下载时需要cookie,因此读者需要将自己在益动GPS的userid和登录的cookie都替换掉。

接下来就是下载的过程,获取导出数据按钮的URL的XPath,构造一个带cookie的请求,然后保存文件即可,非常容易。

opener = urllib.request.build_opener()
opener.addheaders.append(('Cookie', cookie));
path='//*[@id="exportList"]/li[1]/a';
for everyURL in urllists:
id = everyURL.split('=')[-1];
print(id);
url='http://edooon.com/user/%s/record/%s' % (userid, id);
f = opener.open(url);
html = f.read();
f.close();
root = etree.HTML(html)
tree = etree.ElementTree(root);
fs = str(tree.xpath(path)[0]);
if fs is None:
continue;
furl = 'http://edooon.com/user/%s/record/%s' % (userid, fs);
f = opener.open(furl);
html = f.read();
f.close();
filename=folder+'id'+'.gpx';
xmlfile = codecs.open(filename, 'wb');
xmlfile.write(html);
xmlfile.close();

之后,我们便保存了大约300多个gpx文件

3. 解析gpx数据

所谓gpx数据,是一种通用规范的GPS数据格式,详细的资料可自行搜索。

我们需要使用python的gpx解析器, gpxpy是个好选择,使用

pip3 install gpxpy 即可安装。

gpxpy提供了丰富的接口,当然为了统计,我们只需要提取一部分数据:

def readgpx(x):
file= open(dir+x+'.gpx','r')
txt=file.read()
gpx=gpxpy.parse(txt)
mv=gpx.get_moving_data()
dat= {'移动时间':mv.moving_time,'静止时间':mv.stopped_time,'移动距离':mv.moving_distance,'暂停距离':mv.stopped_distance,'最大速度':mv.max_speed};
dat['总时间']=(gpx.get_duration())
dat['id']=str(x)
updown=gpx.get_uphill_downhill()
dat['上山']=(updown.uphill);
dat['下山']=(updown.downhill)
timebound=gpx.get_time_bounds();
dat['开始时间']=(timebound.start_time)
dat['结束时间']=(timebound.end_time)
p=gpx.get_points_data()[0]
dat['lat']=p.point.latitude
dat['lng']=p.point.longitude
file.close()
return dat

readgpx函数会读取文件名x,并将一个字典返回。并得到类似下面的一张表:

Python和Perl绘制中国北京跑步地图的方法

因为我们只需要绘制北京的区域,因此需要一个坐标表达式筛掉北京之外的地区。筛选代码使用了pandas,在附件里有更详细的代码。

exceptids=详细[(详细.lng<116.1)|(详细.lng>116.7)|(详细.lat<39.9)|(详细.lat>40.1)].id

def filtercity(r):
sp=r.split('/')[-1].split('.')
if sp[1]!='gpx':
return False;
if sp[0] in exceptids.values:
return False;
return True; 
bjids= [r for r in gpxs if filtercity(r)]

这样,我们就将所有在北京完成的运动数据筛选了出来。

4.绘制GPS数据

反复造轮子是不好玩的,绘制gpx已经有比较强大的库,地址在http://avtanski.net/projects/gps/

很不幸,这个库使用Perl作为开发语言,并使用了GD作为视觉渲染库。我花费了大量的时间,在安装GD上面。

Ubuntu默认安装Perl, GD是需要libgd的,libgd却在官网上极难下载,下载后却又发现版本不对,这让我在国外互联网上遨游了好几个小时,都要死掉了。。。到最后,我才发现,安装libgd库只要下面这一步就可以了:

apt-get install libgd-gd2-perl

我觉得这就是apt-get方式坑爹的地方,apt get gd 或者libgd根本找不到,如果不去查,谁知道这么写啊! 至于Perl的CPan管理工具,哎,不说了都是泪。

接下来下载gd 2.56,算是非常新的版本。找了各种中文版的安装步骤,发现都有问题。这种事情,最好的办法还是看README.MD啊!

解压之后,perl ./Makefile.PL

之后make

make install

然后就可以了。。。。。。

这份gpx绘制库是这么介绍自己的:

This folder contains several Perl scripts for processing and plotting

GPS track data in .GPX format. 它的readme有不少使用上的说明,当然我们不废话,把所有的gpx数据拷贝到sample_gpx文件夹下,然后华丽丽的运行 ./runme.sh 如果没有问题的话,应该是下面这样:

Python和Perl绘制中国北京跑步地图的方法[/code

我假设各位读者对bash都已经很熟悉了,修改runme.sh文件,可查看更多的选项。 最后得到的结果如下图:

Python和Perl绘制中国北京跑步地图的方法当时看到这个结果,我都惊呆了!这是自己跑了2000公里左右的结果,北京三环内(主要集中在长安街以北)主要的道路都遍了。尤其北三环和北土城路(10号线北段)被我各种虐。每一段白线都是一段故事,每一个点都是我的一个脚印啊!

5.总结

这文章写得显然不够详细,远远没有hand by hand。而且并没有提供更多的数据分析(显然这些工作我都做了)不过相信跑步的程序员一定都很厉害,我这就权作抛砖引玉了。

其实完全可以做成一个web服务,跑友们上传自己的跑步软件的id,就可以自动渲染出各种漂亮的跑步路径和分析图,应该会很有意义吧!

这件事情花费了我七八个小时,简直吐血,大量的时间用在了如何安装GD上,而不是下载数据上。教训告诉我,一定要读安装包里自带的说明文档,因为库和库之间的版本不同,因此可能造成版本地狱,到时候新版本卸载不了,老版本没法用的时候可别说我没提醒啊!

值得一提的是,益动gps下载的gpx文件不带换行符,这导致gpx_disualization库无法解析它(这货正则表达式写错了),我懒得再去动perl正则,于是通过替换增加了换行符。

以上是小编给大家介绍的Python和Perl绘制中国北京跑步地图的方法,希望对大家有所帮助!

Python 相关文章推荐
初学python数组的处理代码
Jan 04 Python
基于Django用户认证系统详解
Feb 21 Python
对python使用http、https代理的实例讲解
May 07 Python
cmd运行python文件时对结果进行保存的方法
May 16 Python
python入门:这篇文章带你直接学会python
Sep 14 Python
tensorflow的ckpt及pb模型持久化方式及转化详解
Feb 12 Python
浅谈tensorflow 中的图片读取和裁剪方式
Jun 30 Python
python如何安装下载后的模块
Jul 03 Python
详解appium自动化测试工具(monitor、uiautomatorviewer)
Jan 27 Python
python自动化办公操作PPT的实现
Feb 05 Python
Python基础之常用库常用方法整理
Apr 30 Python
python入门学习关于for else的特殊特性讲解
Nov 20 Python
python套接字流重定向实例汇总
Mar 03 #Python
Python设计模式中单例模式的实现及在Tornado中的应用
Mar 02 #Python
Python使用设计模式中的责任链模式与迭代器模式的示例
Mar 02 #Python
详解Python设计模式编程中观察者模式与策略模式的运用
Mar 02 #Python
Python设计模式编程中解释器模式的简单程序示例分享
Mar 02 #Python
分析Python中设计模式之Decorator装饰器模式的要点
Mar 02 #Python
实例解析Python设计模式编程之桥接模式的运用
Mar 02 #Python
You might like
全国FM电台频率大全 - 16 河南省
2020/03/11 无线电
十天学会php之第八天
2006/10/09 PHP
发布一个迷你php+AJAX聊天程序[聊天室]提供下载
2007/07/21 PHP
ecshop实现smtp发送邮件
2015/02/03 PHP
php获取网页里所有图片并存入数组的方法
2015/04/06 PHP
PHP json_encode() 函数详解及中文乱码问题
2015/11/05 PHP
用一段js程序来实现动画功能
2007/03/06 Javascript
javascript基本语法分析说明
2008/06/15 Javascript
给超链接添加特效鼠标移动展示提示信息且随鼠标移动
2013/10/17 Javascript
jquery中的查找parents与closest方法之间的区别
2013/12/02 Javascript
jquery数组封装使用方法分享(jquery数组遍历)
2014/03/25 Javascript
jquery插件之文字间歇自动向上滚动效果代码
2016/02/25 Javascript
漂亮! js实现颜色渐变效果
2016/08/12 Javascript
Bootstrap源码解读表单(2)
2016/12/22 Javascript
webpack配置文件和常用配置项介绍
2017/04/28 Javascript
Vue.js中兄弟组件之间互相传值实例
2017/06/01 Javascript
详解Vue单元测试Karma+Mocha学习笔记
2018/01/31 Javascript
Fundebug支持监控微信小程序HTTP请求错误的方法
2019/02/21 Javascript
vue使用Proxy实现双向绑定的方法示例
2019/03/20 Javascript
基于vue实现图片验证码倒计时60s功能
2019/12/10 Javascript
Python正则表达式匹配ip地址实例
2014/10/09 Python
python 排序算法总结及实例详解
2016/09/28 Python
Python 专题三 字符串的基础知识
2017/03/19 Python
基于数据归一化以及Python实现方式
2018/07/11 Python
Python简单读写Xls格式文档的方法示例
2018/08/17 Python
python创建学生管理系统
2019/11/22 Python
Python3实现将一维数组按标准长度分隔为二维数组
2019/11/29 Python
Python求平面内点到直线距离的实现
2020/01/19 Python
html5 更新图片颜色示例代码
2014/07/29 HTML / CSS
Julep官网:美容产品和指甲油
2017/02/25 全球购物
租房协议书范本
2014/04/09 职场文书
村级个人对照检查材料
2014/08/22 职场文书
2016年清明节寄语
2015/12/04 职场文书
导游词之镇江焦山
2019/11/21 职场文书
mysql5.7使用binlog 恢复数据的方法
2021/06/03 MySQL
vue route新窗口跳转页面并且携带与接收参数
2022/04/10 Vue.js