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 sys.path详细介绍
Oct 17 Python
Python实现数据库编程方法详解
Jun 09 Python
Python2.7简单连接与操作MySQL的方法
Apr 27 Python
PyCharm代码回滚,恢复历史版本的解决方法
Oct 22 Python
python 并发编程 阻塞IO模型原理解析
Aug 20 Python
Python爬虫解析网页的4种方式实例及原理解析
Dec 30 Python
Pycharm中切换pytorch的环境和配置的教程详解
Mar 13 Python
关于Python解包知识点总结
May 05 Python
详解Pycharm与anaconda安装配置指南
Aug 25 Python
python如何停止递归
Sep 09 Python
tensorflow中的梯度求解及梯度裁剪操作
May 26 Python
用Python创建简易网站图文教程
Jun 11 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版)
2006/10/09 PHP
php采集文章中的图片获取替换到本地(实现代码)
2013/07/08 PHP
php导入大量数据到mysql性能优化技巧
2014/12/29 PHP
Python中使用django form表单验证的方法
2017/01/16 PHP
php mysql PDO 查询操作的实例详解
2017/09/23 PHP
php中访问修饰符的知识点总结
2019/01/27 PHP
Yii框架常见缓存应用实例小结
2019/09/09 PHP
Ubuntu 11.10 安装Node.js的方法
2011/11/30 Javascript
jQuery(js)获取文字宽度(显示长度)示例代码
2013/12/31 Javascript
使用CoffeeScrip优美方式编写javascript代码
2015/10/28 Javascript
简单实现IONIC购物车功能
2017/01/10 Javascript
利用Node.js+Koa框架实现前后端交互的方法
2017/02/27 Javascript
webpack多入口文件页面打包配置详解
2018/01/09 Javascript
node前端开发模板引擎Jade的入门
2018/05/11 Javascript
vue实现弹框遮罩点击其他区域弹框关闭及v-if与v-show的区别介绍
2018/09/29 Javascript
jquery 插件重新绑定的处理方法分析
2019/11/23 jQuery
python中将阿拉伯数字转换成中文的实现代码
2011/05/19 Python
Python的ORM框架SQLAlchemy入门教程
2014/04/28 Python
在Django中同时使用多个配置文件的方法
2015/07/22 Python
Python出现segfault错误解决方法
2016/04/16 Python
解决Shell执行python文件,传参空格引起的问题
2018/10/30 Python
如何使用Python自动控制windows桌面
2019/07/11 Python
python 利用pyttsx3文字转语音过程详解
2019/09/25 Python
python 实现让字典的value 成为列表
2019/12/16 Python
css3 transform导致子元素固定定位变成绝对定位的方法
2020/03/06 HTML / CSS
html5拖曳操作 HTML5实现网页元素的拖放操作
2013/01/02 HTML / CSS
中国最大的名表商城:万表网
2016/08/29 全球购物
中国一家专注拼团的社交购物网站:拼多多
2018/06/13 全球购物
美术教师自我鉴定
2014/02/12 职场文书
生物制药专业自我鉴定
2014/02/19 职场文书
应届毕业生求职信范文
2014/05/08 职场文书
文明城市标语
2014/06/16 职场文书
公司行政主管岗位职责
2015/04/09 职场文书
母亲去世追悼词
2015/06/23 职场文书
初一英语教学反思
2016/02/15 职场文书
Python循环之while无限迭代
2022/04/30 Python