零基礎掌握百度地圖興趣點獲取POI爬蟲(python語言爬取)(代碼篇)


好,現在進入高階代碼篇。 
目的: 
爬取昆明市中學的興趣點POI。 
關鍵詞:中學 
已有ak:9s5GSYZsWbMaFU8Ps2V2VWvDlDlqGaaO 
昆明市坐標范圍: 
左下角:24.390894,102.174112 
右上角:26.548645,103.678942 
URL模板: 
http://api.map.baidu.com/place/v2/search?query=中學& bounds=24.390894,102.174112,26.548645,103.678942&page_size=20&page_num=0&output=json&ak=9s5GSYZsWbMaFU8Ps2V2VWvDlDlqGaaO 
工具:python2.7 
我們將使用python語言來寫爬蟲代碼。

1.功能分解 
先把這個爬蟲要實現的功能做一個分解。 
已經知道在這個URL中,變量是bounds和page_num的值。 
Bounds范圍值要采取矩形分割,分4個矩形,就是4組坐標范圍,page_num的值從0到19之間。 
1組坐標范圍20個page_num值,4×20=80。要生成的URL陣列是80個。 
每個URL都能生成一個網頁,每個網頁上的信息都要被爬下來,保存到一個txt文件中。

A.根據bounds和page_num組合生成URL。 
B.根據URL爬取網頁數據,添加到txt文件中。 
這將是一個循環代碼: 
Bounds=[矩形1,矩形2,矩形3,矩形4] 
Page_nums=[0、1、2……19]

For 矩形 in bounds: 
For page_num in page_nums: 
URL=http://api.map.baidu.com/place/v2/search?query=中學& bounds=矩形&page_size=20&page_num=page_num&output=json&ak=9s5GSYZsWbMaFU8Ps2V2VWvDlDlqGaaO 
URL內容爬取,添加入txt文件 
Next 
Next 
End 
這個代碼的框架說完了。 
然后進入每個功能的代碼如何實現環節。

2.功能代碼實現。 
代碼要實現的功能是哪幾個呢? 
按照步驟分: 
A.bounds列表的生成。 
B.URL列表的生成。 
C.爬取的網頁內容保存到txt文本中。

(1)bounds列表生成 
再說一下,因為這個是零基礎教程,所以我會講解得非常細致,python代碼會由淺入深,從最簡單最基礎的開始。 
我們看一下坐標范圍: 
左下角:24.390894,102.174112 
右上角:26.548645,103.678942 
緯度差是2.157751,經度差是1.50483。 
用代碼表示一下坐標范圍: 
lat_1=24.390894 
lon_1=102.174112 
lat_2=26.548645 
lon_2=103.678942 
lat是緯度的英文,lon是經度的英文。 
我們切分矩形的話,這個矩形的坐標肯定是由上面這幾個坐標范圍計算的來的,內插運算。 
為了計算簡便,我們就切方形吧,這個方形的邊長我們設定一個值,假設是las(length of a side,邊長英文)。 

那么第一個矩形的左下角坐標是lat_1+las,lon_1,右上角坐標是lat_1+las*2,lon_1+las;第二個矩形的左下角坐標是lat_1+las,lon_1+las,右上角坐標是lat_1+las*2,lon_1+las*2…… 
我們設定的計算規則是: 
整個坐標范圍的大矩形我們叫它矩形A,切分的小矩形我們叫它矩形B。 
矩形A的左下角坐標是:lat_1,lon_1,右上角坐標是lat_2,lon_2; 
矩形B的邊長是las。 
那么計算一下矩形B的數量: 
(int((lat_2-lat_1)/las)+1)*(int((lon_2-lon_1)/las)+1) 
int是一個取整函數。 
int(1.334)=1 
int((lat_2-lat_1)/las)+1計算的是在緯度上切了幾個,int((lon_2-lon_1)/las)+1計算的是在經度上切了幾個,乘積就是一共幾個矩形。 
我們看下面一段代碼:

at_1=24.390894
lon_1=102.174112
lat_2=26.548645
lon_2=103.678942   #坐標范圍
las=1  #給las一個值1
lat_count=int((lat_2-lat_1)/las+1)
lon_count=int((lon_2-lon_1)/las+1)
for lat_c in range(0,lat_count):
    lat_b1=lat_1+las*lat_c
    for lon_c in range(0,lon_count):
        lon_b1=lon_1+las*lon_c
        print str(lat_b1)+','+str(lon_b1)
        #這段代碼生成的是矩形B的左下角坐標

在IDLE中敲入這些代碼,運行結果是: 
24.390894,102.174112 
24.390894,103.174112 
25.390894,102.174112 
25.390894,103.174112 
26.390894,102.174112 
26.390894,103.174112 
因為我把las設置為1了,所以切出來6個矩形,這是這六個矩形的左下角坐標。 
這行代碼很簡單,只涉及到兩組內嵌的循環語句:for lat_c in range(0,lat_count): 
用VB語言翻譯一下這行就是 for lat_c=0 to lat_count step 1。 
說明幾個注意點: 
a.python語言不需要聲明變量。 
b.for語句后面的:別忘了。 
c.range(0,3)是[0,1,2],3不在數組里面,好好理解一下函數關系,這么個算法,說明左下角坐標是正好的,不會多一個。 
d.python沒有結束循環的語句,靠回車,表示嵌套關系靠的“ ”,四個空格,for語句冒號后面跟着的那行,比for語句后退了四個空格,說明這個語句是在for循環中的,如果語句要跳出for循環的話,那么就刪掉四個空格,表示跳出循環。這是一個很有意思的python寫碼規則。 
我們把這段代碼改一改,獲取矩形B的范圍坐標:

lat_1=24.390894
lon_1=102.174112
lat_2=26.548645
lon_2=103.678942   #坐標范圍
las=1  #給las一個值1
lat_count=int((lat_2-lat_1)/las+1)
lon_count=int((lon_2-lon_1)/las+1)
for lat_c in range(0,lat_count):
    lat_b1=lat_1+las*lat_c
    for lon_c in range(0,lon_count):
        lon_b1=lon_1+las*lon_c
        print str(lat_b1)+','+str(lon_b1)+','+str(lat_b1+las)+','+str(lon_b1+las)
        #這段代碼生成的是矩形B的范圍坐標

運行結果如下: 
24.390894,102.174112,25.390894,103.174112 
24.390894,103.174112,25.390894,104.174112 
25.390894,102.174112,26.390894,103.174112 
25.390894,103.174112,26.390894,104.174112 
26.390894,102.174112,27.390894,103.174112 
26.390894,103.174112,27.390894,104.174112 
好好理解一下這行代碼。

(2)URL列表生成: 
bounds列表生成之后,page_num在range(0,20)中遍歷一遍,就生成了URL列表了。 
代碼如下: 

看看這張圖,好好理解一下循環與空格之間的關系,python沒有結束循環的語句,就靠空格來做嵌套。 
把這段代碼完善一下,主要是URL那段怎么寫。 

其中: 
url=’http://api.map.baidu.com/place/v2/search?query=中學& bounds=’+str(lat_b1)+’,’+str(lon_b1)+’,’+str(lat_b1+las)+’,’+str(lon_b1+las)+’&page_size=20&page_num=’+str(page_num)+’&output=json&ak=9s5GSYZsWbMaFU8Ps2V2VWvDlDlqGaaO’ 
print url 
URL列表也生成了,是不是曙光在望了? 
繼續!

(3)網頁解析 
我們先學習一下網頁的爬取,依然用這行URL來學習。 
http://api.map.baidu.com/place/v2/search?query=中學& bounds=24.390894,102.174112,26.548645,103.678942&page_size=20&page_num=0&output=json&ak=9s5GSYZsWbMaFU8Ps2V2VWvDlDlqGaaO 
我用的python2.7,我們寫一段代碼,把這個URL上的數據爬下來。 
打開IDLE,file——new file(ctrl+n),新建一個py文件,在里面敲代碼。當然也可以在python shell里面一行一行敲,對於初學者來說,這種方式比較合適,一行一行敲,錯了就有提示。 
我們簡單敲入一段代碼,看看怎么爬取網頁: 

在代碼的最開始,我們看到導入了兩個庫,一個是urllib2庫,一個是json,這是要解析百度開放平台URL必須要導入的兩個庫,urllib2是做網頁解析的,而URL中,我們仔細查看,會看到“output=json”,URL的網頁輸出是以這種格式輸出的。 
輸出結果如下: 

但顯然,我們不需要這樣的數據,在結果“results”中,我們只需要name、lat、lng、address的值,這時候,就需要對json數據格式進行解析了。 
我們把這段代碼修改一下: 

上文不同的是,我們還導入了一個sys庫,解釋如圖。 
用加載的方式,json.load(response)在python中載入了URL生成的json數據,用一個循環讀入了json數據中的results中name,仔細觀察json數據結構就能理解這些代碼。 
運行結果如下: 

當然,我們要獲取的是四個值,name、lat、lng、address,那么把這行代碼改寫一下吧! 
改寫的代碼部分如下:

for item in data['results']:
    jname=item['name']
    jlat=item['location']['lat']
    jlon=item['location']['lng']
    jadd=item['address']

(5)python默認編碼問題。 
python默認的編碼是ASCII,不過URL解析的json文件編碼是uft-8。 
如果不對編碼方式進行重新設定,就會出現中文亂碼問題。 
把python默認編碼從ascii轉到uft-8的代碼是固定的。

# -*- coding:utf-8 -*
import os
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

把這段代碼放在代碼前端即可。 
我們將要實現的代碼前端如圖,保證代碼行的順序。 

(6)txt文件寫入

f=open(r'D:\python\kunmingschool.txt','a')
f.write('zhongxue')
f.close()

這是一段最簡單的文本寫入代碼,打開D:\python\kunmingschool.txt這個文件,以添加方式寫入,寫入zhongxue,把文件關閉。 
A.文件全路徑前面加一個r,這是防止字符轉譯的,就是怕識別不了路徑。 
B.a的意思是以添加方式寫入,如果是w的話,就是覆蓋方式寫入。 
C.寫入完成后,要把文件關閉,close(),括號別忘了。 
把網頁解析和txt文件寫入,聯合一下。 
還是把這個URL上的內容寫入txt文件,文件的全路徑是D:\python\kunmingschool.txt。 
http://api.map.baidu.com/place/v2/search?query=中學& bounds=24.390894,102.174112,26.548645,103.678942&page_size=20&page_num=0&output=json&ak=9s5GSYZsWbMaFU8Ps2V2VWvDlDlqGaaO 
這段的代碼如下: 

n\是python里面的換行符。 
運行結果如下圖: 

至此,要用到的功能代碼,我們都會了,現在只要把它們都組合到一切就可以了。 
3.全部代碼

# -*- coding:utf-8 -*
import json  #導入json庫
import os
import urllib2 #導入urllib2庫
import sys #我知道了,這個東東是為了把默認編碼從ascii轉到uft-8。
reload(sys)
sys.setdefaultencoding('utf-8')

lat_1=24.390894
lon_1=102.174112
lat_2=26.548645
lon_2=103.678942   #坐標范圍
las=1  #給las一個值1
ak='9s5GSYZsWbMaFU8Ps2V2VWvDlDlqGaaO'
keyword='中學'
push=r'D:\python\12345.txt'
#我們把變量都放在前面,后面就不涉及到變量了,如果要爬取別的POI,修改這幾個變量就可以了,不用改代碼了。
f=open(push,'a')
lat_count=int((lat_2-lat_1)/las+1)
lon_count=int((lon_2-lon_1)/las+1)
for lat_c in range(0,lat_count):
    lat_b1=lat_1+las*lat_c
    for lon_c in range(0,lon_count):
        lon_b1=lon_1+las*lon_c
        for i in range(0,20):
            page_num=str(i)
            url='http://api.map.baidu.com/place/v2/search?query='keyword'& bounds='+str(lat_b1)+','+str(lon_b1)+','+str(lat_b1+las)+','+str(lon_b1+las)+'&page_size=20&page_num='+str(page_num)+'&output=json&ak='+ak
            response = urllib2.urlopen(url2)
            data=json.load(response)
            for item in data['results']:
                jname=item['name']
                jlat=item['location']['lat']
                jlon=item['location']['lng']
                jadd=item['address']
                j_str=jname+','+str(jlat)+','+str(jlon)+','+jadd+'\n'
                f.write(j_str)
f.close()

說實話,一個腳本里面嵌入了四個循環,程序員見了能打人,不過能用就行。

接下來將要進入進階篇教程,在這里會涉及到如何獲取區域范圍,例如昆明市的bounds值;如何更合理的切分矩形;如何簡化代碼,如何將代碼移植到python3中;可否用別的方式、函數語句獲取poi數據;通過什么樣的設置可以更高效的獲取poi;python中文亂碼的解決方式;request、time等模塊的應用;過程參考資料匯總……

 

轉自-----http://blog.csdn.net/sinat_41310868/article/details/78746224


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM