Python和Perl繪制中國北京跑步地圖的方法
當你在一個城市,穿越大街小巷,跑步跑了幾千公里之后,一個顯而易見的想法是,我到底和之前比快了多少,跑量有何變化,如果能把在這個城市的所有路線全部畫出來,會是怎樣的景象呢?
1.數(shù)據(jù)來源:益動GPS
文章代碼比較多,為了不吊人胃口,先看看最終效果:
首先需要有原始數(shù)據(jù)信息,手機上眾多跑步軟件提供了詳細的記錄,但它們共同的問題是不允許自由導入導出(可能是為了用戶粘性吧)。因此有一塊智能運動手表應(yīng)該是不二之選。我的是Garmin Fenix3,推薦一下:
益動GPS算是業(yè)界良心了,能夠同步咕咚,Garmin手表,悅跑圈的數(shù)據(jù),因此我將其作為一個入口,抓取所有的GPS數(shù)據(jù)。
至于如何同步,可參考網(wǎng)站上的相關(guān)介紹,下面是我登錄該網(wǎng)站后的截圖:
http://edooon.com/user/5699607196/record/15414378
隨便點進去以后,就可以看到導出路線的按鈕:
無比坑爹的是,它不提供批量導出的按鈕,幾百條記錄,依次導出都累死了。于是考慮用代碼來編輯吧。
2. 獲取益動網(wǎng)站上的數(shù)據(jù)
登錄之后,可以看出它是動態(tài)加載,當滾輪滾到最下時,自動加載后面的內(nèi)容。本來是應(yīng)該嗅探和分析http請求的,后來懶惰了。當拖到底,全部加載完畢后,保存了當前的html文件。
接下來就是解析這個Html,基本上是通過XPath的來做的。有經(jīng)驗的同學看了下圖就都明白了:
圖中高亮的部分,就是要下載gpx文件的實際地址。我們將其保存在urllist中。同時,元數(shù)據(jù)被保存在json文件里。
folder = u'D:/buptzym的同步盤/百度云/我的文檔/數(shù)據(jù)分析/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都替換掉。
接下來就是下載的過程,獲取導出數(shù)據(jù)按鈕的URL的XPath,構(gòu)造一個帶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數(shù)據(jù)
所謂gpx數(shù)據(jù),是一種通用規(guī)范的GPS數(shù)據(jù)格式,詳細的資料可自行搜索。
我們需要使用python的gpx解析器, gpxpy是個好選擇,使用
pip3 install gpxpy 即可安裝。
gpxpy提供了豐富的接口,當然為了統(tǒng)計,我們只需要提取一部分數(shù)據(jù):
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['結(jié)束時間']=(timebound.end_time) p=gpx.get_points_data()[0] dat['lat']=p.point.latitude dat['lng']=p.point.longitude file.close() return dat
readgpx函數(shù)會讀取文件名x,并將一個字典返回。并得到類似下面的一張表:
因為我們只需要繪制北京的區(qū)域,因此需要一個坐標表達式篩掉北京之外的地區(qū)。篩選代碼使用了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)]
這樣,我們就將所有在北京完成的運動數(shù)據(jù)篩選了出來。
4.繪制GPS數(shù)據(jù)
反復造輪子是不好玩的,繪制gpx已經(jīng)有比較強大的庫,地址在http://avtanski.net/projects/gps/
很不幸,這個庫使用Perl作為開發(fā)語言,并使用了GD作為視覺渲染庫。我花費了大量的時間,在安裝GD上面。
Ubuntu默認安裝Perl, GD是需要libgd的,libgd卻在官網(wǎng)上極難下載,下載后卻又發(fā)現(xiàn)版本不對,這讓我在國外互聯(lián)網(wǎng)上遨游了好幾個小時,都要死掉了。。。到最后,我才發(fā)現(xiàn),安裝libgd庫只要下面這一步就可以了:
apt-get install libgd-gd2-perl
我覺得這就是apt-get方式坑爹的地方,apt get gd 或者libgd根本找不到,如果不去查,誰知道這么寫啊! 至于Perl的CPan管理工具,哎,不說了都是淚。
接下來下載gd 2.56,算是非常新的版本。找了各種中文版的安裝步驟,發(fā)現(xiàn)都有問題。這種事情,最好的辦法還是看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數(shù)據(jù)拷貝到sample_gpx文件夾下,然后華麗麗的運行 ./runme.sh 如果沒有問題的話,應(yīng)該是下面這樣:
我假設(shè)各位讀者對bash都已經(jīng)很熟悉了,修改runme.sh文件,可查看更多的選項。 最后得到的結(jié)果如下圖:
當時看到這個結(jié)果,我都驚呆了!這是自己跑了2000公里左右的結(jié)果,北京三環(huán)內(nèi)(主要集中在長安街以北)主要的道路都遍了。尤其北三環(huán)和北土城路(10號線北段)被我各種虐。每一段白線都是一段故事,每一個點都是我的一個腳印?。?br />
5.總結(jié)
這文章寫得顯然不夠詳細,遠遠沒有hand by hand。而且并沒有提供更多的數(shù)據(jù)分析(顯然這些工作我都做了)不過相信跑步的程序員一定都很厲害,我這就權(quán)作拋磚引玉了。
其實完全可以做成一個web服務(wù),跑友們上傳自己的跑步軟件的id,就可以自動渲染出各種漂亮的跑步路徑和分析圖,應(yīng)該會很有意義吧!
這件事情花費了我七八個小時,簡直吐血,大量的時間用在了如何安裝GD上,而不是下載數(shù)據(jù)上。教訓告訴我,一定要讀安裝包里自帶的說明文檔,因為庫和庫之間的版本不同,因此可能造成版本地獄,到時候新版本卸載不了,老版本沒法用的時候可別說我沒提醒啊!
值得一提的是,益動gps下載的gpx文件不帶換行符,這導致gpx_disualization庫無法解析它(這貨正則表達式寫錯了),我懶得再去動perl正則,于是通過替換增加了換行符。
以上是小編給大家介紹的Python和Perl繪制中國北京跑步地圖的方法,希望對大家有所幫助!
相關(guān)文章
Python作用域(局部?全局)及global關(guān)鍵字使用詳解
這篇文章主要為大家介紹了Python作用域(局部?全局)及global關(guān)鍵字使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-10-10Python Multinomial Naive Bayes多項貝葉斯模型實現(xiàn)原理介紹
這篇文章主要介紹了Python Multinomial Naive Bayes多項貝葉斯模型實現(xiàn)原理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧2022-09-09jupyter notebook 恢復誤刪單元格或者歷史代碼的實現(xiàn)
這篇文章主要介紹了jupyter notebook 恢復誤刪單元格或者歷史代碼的實現(xiàn),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04Python3中正則模塊re.compile、re.match及re.search函數(shù)用法詳解
這篇文章主要介紹了Python3中正則模塊re.compile、re.match及re.search函數(shù)用法,結(jié)合實例形式較為詳細的分析了re模塊 中re.compile、re.match及re.search函數(shù)的功能、參數(shù)、具體使用技巧與注意事項,需要的朋友可以參考下2018-06-06pycharm設(shè)置默認的UTF-8編碼模式的方法詳解
這篇文章主要介紹了pycharm設(shè)置默認的UTF-8編碼模式,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-06-06python神經(jīng)網(wǎng)絡(luò)使用Keras構(gòu)建RNN訓練
這篇文章主要為大家介紹了python神經(jīng)網(wǎng)絡(luò)使用Keras構(gòu)建RNN網(wǎng)絡(luò)訓練,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪<BR>2022-05-05Python中__repr__和__str__區(qū)別詳解
這篇文章主要介紹了Python中__repr__和__str__區(qū)別詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-11-11