python利用高德接口,爬取武汉地区的POI--一个不太成熟的BUG,程序总是跑着跑着就假死了。
生活随笔
收集整理的這篇文章主要介紹了
python利用高德接口,爬取武汉地区的POI--一个不太成熟的BUG,程序总是跑着跑着就假死了。
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
說明
1.遇到的問題
可是爬取過程中總是不順利,程序總是爬著爬著就不動了,有時爬幾千條假死,有時爬幾萬條假死。數據庫中沒有新數據增加,程序也不報錯,也不中止。CPU,內存占用也不高,硬盤中也還有空間,現在是實在不知道如何解決了。所以想讓請教一番。
2.需求背景
畢業設計需要用到一些城市的POI數據,本著自己動手豐衣足食的原則,就從自己寫了段python代碼從高德地圖爬取POI數據。
3.高德獲取POI數據接口說明
多邊形搜索API接口,請求方式gethttps://restapi.amap.com/v3/place/polygon? //請求參數:polygon:如果多邊形為矩形,則需要左上,右下經緯度坐標 左上角:113.705304,31.366201 右下角:115.089744,29.974252 以上為例,polygon = 113.705304,31.366201|115.089744,29.974252types=010000:POI數據的地物類型 ,比如汽車服務,居民住宅等offset=10,每頁返回的數據量,最大為25page=1,頁碼從0開始,第0頁和第1頁相同,最大100 補充:接口文檔說一個區域最多1000個數據,實測只有800多數據。4.代碼思路
由于一個區域只能獲取800多數據。
因此當對一個矩形區域進行爬取時,如果返回的數據大于800,則認為該區域的POI數據超過接口規定上限,對該區域進行四等分,然后再逐個進行爬取。如果返回的數據小于800,則認為已經獲取了該區域所有的POI,將這些POI寫入mysql數據庫。代碼
運行環境
IDE:pycharm3.3
環境:python3.6
系統:64bit win10
內存:16G
CPU:i7 7700hq
數據庫:mysql
源碼
import requests import pymysql import time import math import socket''' https://restapi.amap.com/v3/place/polygon?polygon=113.705304,31.366201|115.089744,29.974252&key=10518669c9fd0a0532e41189d61e1e9b&extensions=all&types=010000&offset=10&page=90 ''' # 初始區域的經緯度 lon_l = 113.705304 lan_l = 31.366201 lon_r = 115.089744 lan_r = 29.974252# 要爬取POI的類型 types = '010000|020000|030000|040000|050000|060000|' \'070000|080000|090000|100000|110000|120000|' \'130000|140000|150000|160000|170000|180000|' \'190000|200000|210000|220000|230000|240000|' \'970000|990000'# 獲取POI的接口 url = 'https://restapi.amap.com/v3/place/polygon?' \'polygon={lon_l},{lan_l}|{lon_r},{lan_r}' \'&key=10518669c9fd0a0532e41189d61e1e9b&extensions=all' \'&types={types}&offset=25&page={page}'# point class Point:"""用經緯度來描述一個點"""def __init__(self, lon, lan):self.lon = lon # 經度self.lan = lan # 緯度# area class Rectangle:"""用左上角的經緯度和右下角的經緯度描述一個矩形區域"""def __init__(self, p_l, p_r):self.p_l = p_l # 左上角的點self.p_r = p_r # 右下角的點# 初始矩形的左上點和右下點 p_l = Point(lon_l,lan_l) p_r = Point(lon_r,lan_r)# 初始矩形,內含兩點,左上,右下 rec = Rectangle(p_l,p_r)''' 打開一個URL,獲取返回信息 ''' def open_html(real_url):NET_STATUS=Falsewhile not NET_STATUS:try:data = requests.get(real_url).json()return dataexcept socket.timeout:print("NET_STATURS IS NOT GOOD")NET_STATUS=Falseexcept :print("OTHER WRONG")# 把一個區域的POI點存進數據庫 def get_pois(rec,url,data_count):url = url.format(lon_l = rec.p_l.lon , lan_l = rec.p_l.lan ,lon_r = rec.p_r.lon , lan_r = rec.p_r.lan ,types = types,page="{page}")f_url = open("url.txt","a",encoding="UTF-8")data= open_html(url.format(page=0))if data["status"] == "1":# 執行到這里,說明url中含有poi數據,下面開始爬取all_page=math.ceil(data_count/25)for page in range(all_page):try:# 從第1頁開始到第最后一頁url_real = url.format(page = page+1)f_url.write(url_real+'\n')data = open_html(url_real)if data["status"] == "1" : # 判斷第page+1頁是否有內容pois = data["pois"]# 將數據儲存在數據庫# 優化點:db先創建好,一次用完不關,最后再關global db_globaldb = db_globalcursor = db.cursor()str_sql = 'insert into t_poi(id,name,address,typecode,lon,lan,pcode,pname,citycode,cityname,adcode,adname) ' \'values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)'count=0for poi in pois:try:count += 1value = [poi['id'], poi['name'], poi["address"], poi['typecode'],poi['location'].split(',')[0], poi['location'].split(',')[1],poi['pcode'], poi['pname'], poi['citycode'], poi['cityname'], poi['adcode'], poi['adname']]if [] in value:value[value.index([])]=''try:cursor.execute(str_sql,value)db.commit()except:Exception# 打印日志文件f=open("wrong.txt",'a',encoding="UTF-8")time_fomat = '%Y-%m-%d %X'time_current = time.strftime(time_fomat)f.write(time_current+ ' 第{page}頁,第{index}個出錯\n'.format(page=page,index=count))except:passcursor.close()except:pass#檢測器 run_count = 0# 爬取,分析一個區域的POI數量,多于800則將區域四等分,并遞歸,低于800則進行爬取 def crawl_pois(rec,url):# 計算進行了幾次分析的計數器,判斷程序是否卡死global run_count;run_count += 1;f_count = open("count.txt",'a',encoding="UTF-8");f_count.write("這是第{_count}次運行分析一個區域\n".format(_count=run_count))# 根據矩形區域的經緯度坐標,拼接urlurl_real = url.format(lon_l=rec.p_l.lon, lan_l=rec.p_l.lan,lon_r=rec.p_r.lon, lan_r=rec.p_r.lan,types=types, page="{page}")# 獲取url返回的數據data = open_html(url_real.format(page=0))if data["status"] == "1":# 執行到這里,說明url中含有poi數據,下面開始判斷區域POI數量data_count = int(data['count'])if data_count> 800:# 如果區域POI數據大于800則進行四等分rec_A = Rectangle(Point(0,0),Point(0,0))rec_B = Rectangle(Point(0,0),Point(0,0))rec_C = Rectangle(Point(0,0),Point(0,0))rec_D = Rectangle(Point(0,0),Point(0,0))# 經緯度差lon_d = (rec.p_r.lon - rec.p_l.lon)/2lan_d = (rec.p_l.lan - rec.p_r.lan)/2# 計算每個小矩形的左上點,和右下點rec_A.p_l.lon = float(format(rec.p_l.lon,'6f'))rec_A.p_l.lan = float(format(rec.p_l.lan,'6f'))rec_A.p_r.lon = float(format(rec.p_l.lon + lon_d,'6f'))rec_A.p_r.lan = float(format(rec.p_r.lan + lan_d,'6f'))rec_B.p_l.lon = float(format(rec.p_l.lon + lon_d,"6f"))rec_B.p_l.lan = float(format(rec.p_l.lan,"6f"))rec_B.p_r.lon = float(format(rec.p_r.lon,"6f"))rec_B.p_r.lan = float(format(rec.p_r.lan + lan_d,"6f"))rec_C.p_l.lon = float(format(rec.p_l.lon,"6f"))rec_C.p_l.lan = float(format(rec.p_r.lan + lan_d,"6f"))rec_C.p_r.lon = float(format(rec.p_l.lon + lon_d,"6f"))rec_C.p_r.lan = float(format(rec.p_r.lan,"6f"))rec_D.p_l.lon = float(format(rec.p_l.lon + lon_d,"6f"))rec_D.p_l.lan = float(format(rec.p_r.lan + lan_d,"6f"))rec_D.p_r.lon = float(format(rec.p_r.lon,"6f"))rec_D.p_r.lan = float(format(rec.p_r.lan,"6f"))recs = []recs.append(rec_A)recs.append(rec_B)recs.append(rec_C)recs.append(rec_D)# 對四個小矩形分別進行爬取,這里使用遞歸for rec_s in recs :# 如果一個區域出現異常,就進行下個區域try:crawl_pois(rec_s,url)except:passelse:# 如果該矩形區域poi點的數量少于800就進行爬取get_pois(rec,url,data_count)else:print("出錯")''' 下面是程序的入口 ''' # 創建一個全局的連接 db_global = pymysql.connect("localhost", "root", "111111", "poi")# 對一個矩形進行爬取分析,這里是對武漢地區的左上角和右下角的經緯度圍成的矩形進行爬取 crawl_pois(rec,url)# 關閉數據庫 db_global.close()代碼的思路我自我感覺沒什么大問題,遞歸也有出口,就是程序跑著跑著就假死了,我也不能確定到底是哪里有問題,路過的大手子們
總結
以上是生活随笔為你收集整理的python利用高德接口,爬取武汉地区的POI--一个不太成熟的BUG,程序总是跑着跑着就假死了。的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PD-QC-AFC多协议诱骗芯片《LDR
- 下一篇: Android 地图导航调用百度地图、高