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继承问题
May 29 Python
Python中运算符&quot;==&quot;和&quot;is&quot;的详解
Oct 08 Python
如何使用 Pylint 来规范 Python 代码风格(来自IBM)
Apr 06 Python
Pandas过滤dataframe中包含特定字符串的数据方法
Nov 07 Python
Python数据分析:手把手教你用Pandas生成可视化图表的教程
Dec 15 Python
使用python将最新的测试报告以附件的形式发到指定邮箱
Sep 20 Python
python随机生成大小写字母数字混合密码(仅20行代码)
Feb 01 Python
mac在matplotlib中显示中文的操作方法
Mar 06 Python
如何利用Python识别图片中的文字
May 31 Python
Pycharm2020最新激活码|永久激活(附最新激活码和插件的详细教程)
Sep 29 Python
Python机器学习之KNN近邻算法
May 14 Python
python numpy中multiply与*及matul 的区别说明
May 26 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
php获取当前时间的毫秒数的方法
2014/01/26 PHP
分享PHP-pcntl 实现多进程代码
2016/09/30 PHP
php学习笔记之mb_strstr的基本使用
2018/02/03 PHP
PHP 观察者模式深入理解与应用分析
2019/09/25 PHP
在html页面中包含共享页面的方法
2008/10/24 Javascript
JavaScript 异步调用框架 (Part 6 - 实例 &amp; 模式)
2009/08/04 Javascript
JS实现程序暂停与继续功能代码解读
2013/10/10 Javascript
javascript动态设置样式style实例分析
2015/05/13 Javascript
使用JavaScript制作一个简单的计数器的方法
2015/07/07 Javascript
BootStrap扔进Django里的方法详解
2016/05/13 Javascript
jquery解析XML及获取XML节点名称的实现代码
2016/05/18 Javascript
图解prototype、proto和constructor的三角关系
2016/07/31 Javascript
JS 拼凑字符串的简单实例
2016/09/02 Javascript
JS实现禁止鼠标右键的功能
2016/10/15 Javascript
JS正则替换掉小括号及内容的方法
2016/11/29 Javascript
Servlet实现文件上传,可多文件上传示例
2016/12/05 Javascript
数组Array的排序sort方法
2017/02/17 Javascript
JS实现问卷星自动填问卷脚本并在两秒自动提交功能
2020/06/17 Javascript
Nodejs 和Session 原理及实战技巧小结
2017/08/25 NodeJs
简述Vue中容易被忽视的知识点
2019/12/09 Javascript
JavaScript对象字面量和构造函数原理与用法详解
2020/04/18 Javascript
Python黑帽编程 3.4 跨越VLAN详解
2016/09/28 Python
python中lambda()的用法
2017/11/16 Python
PyQt4实现下拉菜单可供选择并打印出来
2018/04/20 Python
使用Python爬虫库requests发送表单数据和JSON数据
2020/01/25 Python
django前端页面下拉选择框默认值设置方式
2020/08/09 Python
通过实例解析Python文件操作实现步骤
2020/09/21 Python
英国设计的甲板鞋和船鞋:Chatham
2018/12/06 全球购物
Jones New York官网:美国女装品牌,受白领女性欢迎
2019/11/26 全球购物
异常和异常类的概念
2014/09/12 面试题
医院后勤自我鉴定
2013/10/13 职场文书
应届毕业生自荐书
2014/06/18 职场文书
2015年119消防宣传日活动总结
2015/03/24 职场文书
2015年管理人员工作总结
2015/05/13 职场文书
环境卫生标语
2015/08/03 职场文书
大学文艺委员竞选稿
2015/11/19 职场文书