好,現在進入高階代碼篇。
目的:
爬取昆明市中學的興趣點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