當你在一個城市,穿越大街小巷,跑步跑了幾千千米以後,一個顯而易見的想法是,若是能把在這個城市的全部路線所有畫出來,會是怎樣的景象呢?html
文章代碼比較多,爲了避免吊人胃口,先看看最終效果,上到北七家,下到南三環,西到大望路,東到首都機場。二環32千米,三環50千米,這是極限,四環先暫時不考慮了。。。。node
(本文工程已經託管在Github,https://github.com/ferventdesert/gpx-crawler)python
首先須要原始位置信息,手機上有衆多跑步軟件,但它們共同的問題是不容許自由導入導出(多是爲了防止用戶脫離吧)。所以有一塊智能運動手錶應該是不二之選。個人是Garmin Fenix3,推薦一下:git
與此同時,益動GPS算是業界良心了,可以同步咕咚,Garmin手錶,悅跑圈的數據,所以我將其做爲一個入口,抓取全部的GPS數據。程序員
至於如何同步,可參考網站上的相關介紹,下面是我登陸該網站後的截圖:github
http://edooon.com/user/5699607196/record/15414378web
隨便點進去之後,就能夠看到導出路線的按鈕:正則表達式
無比坑爹的是,它不提供批量導出的按鈕,幾百條記錄,依次導出都累死了。因而考慮用代碼來自動化吧。json
登陸以後,能夠看出它是動態加載,當滾輪滾到最下時,自動加載後面的內容。原本是應該嗅探和分析http請求的。後來我懶惰了,採起折中方案,拖到底,所有加載完畢後,保存了當前的html文件。bash
接下來就是解析這個Html,基本上是經過XPath的來作的。有經驗的同窗看了下圖就都明白了:
圖中高亮的部分,就是要下載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文件。
所謂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,並將一個字典返回。並獲得相似下面的一張表:
由於咱們只須要繪製北京的區域,所以須要一個座標表達式篩掉北京以外的地區。篩選代碼使用了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)]
這樣,咱們就將全部在北京完成的運動數據篩選了出來。
反覆造輪子是很差玩的,繪製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,解壓以後,
perl ./Makefile.PL
make
make install
便可
這份gpx繪製庫是這麼介紹本身的:
This folder contains several Perl scripts for processing and plottin GPS track data in .GPX format.
固然咱們不廢話,把全部的gpx數據拷貝到sample_gpx文件夾下,而後華麗麗的運行
./runme.sh
若是沒有問題的話,應該是下面這樣:
我假設各位讀者對bash都已經很熟悉了,更多的需求能夠查看runme.sh。
最後獲得的結果以下圖:
當時看到這個結果,我都驚呆了!這是本身跑了2000千米左右的結果,北京三環內(主要集中在長安街以北)主要的道路都跑遍了,朝陽公園,天壇公園,尤爲北三環和北土城路(10號線北段)被我各類虐。每一段白線都是一段故事,每個點都是個人一個腳印啊!
這文章寫得顯然不夠詳細,遠遠沒有hand by hand。並且並無提供更多的數據分析(顯然這些工做我都作了)不過相信跑步的程序員必定都很厲害,我這就權做拋磚引玉了。
其實徹底能夠作成一個web服務,跑友們上傳本身的跑步軟件的id,就能夠自動渲染出各類漂亮的跑步路徑和分析圖,應該會頗有意義吧!
這件事情花費了我七八個小時,簡直吐血,大量的時間用在瞭如何安裝GD上,而不是下載數據上。教訓告訴我,必定要讀安裝包裏自帶的說明文檔,由於庫和庫之間的版本不一樣,所以可能形成版本地獄,到時候新版本卸載不了,老版本無法用的時候可別說我沒提醒啊!
值得一提的是,益動gps下載的gpx文件不帶換行符,這致使gpx_disualization庫沒法解析它(這貨正則表達式寫錯了),我懶得再去動perl正則,因而經過替換增長了換行符。
GD還須要libpng等一衆perl庫,在附件裏都有提供下載。