柚子快報激活碼778899分享:【爬蟲】AOI
柚子快報激活碼778899分享:【爬蟲】AOI
目前幾個大廠,高德百度騰訊,都支持POI爬取,而AOI是需要自己找接口的。 換言之,爬蟲需謹慎
1 百度AOI
參考鏈接是: 這兩個鏈接是選定范圍爬取范圍內選定類別的AOI 黑科技 | 百度地圖抓取地塊功能(上) 黑科技 | 百度地圖獲取地塊功能屬性(下)
而這個鏈接是用名稱爬取。我參考的是這個:利用名稱爬取百度AOI https://www.cnblogs.com/zhangqinglan/p/13301425.html
跟Amap一樣,其實是找到了一個接口: https://map.baidu.com/?newmap=1&qt=s&da_src=searchBox.button&wd=‘+Name+’&c=XXX
其中Name為要搜索的名稱。c=XXX的XXX為城市的city_id。這個之前爬風向標的時候已經(jīng)看過了。
比如我輸入朝陽大悅城和c=131
1.1 獲得AOI ID
第一步是先從https://map.baidu.com/?newmap=1&qt=s&da_src=searchBox.button&wd='+Name+'&c=XXX這個接口里找打aoi的id。 跟參考鏈接不一樣的是,我的名字是上一篇爬蟲博客中爬好的csv文件。所以這里改動了下,方便讀取我的格式。 另外參考博客這個層層嵌套的for和try-except,乍一看挺唬人。
在測試時還有個問題,就是try-except有時候會報錯,返回false,因此我沒用它。 以及我開代理爬取時有時成功有時不成功,不知道會不會被鎖ip
還有就是在request語句中,參考博客是用 verify=False。后續(xù)調試代碼時多爬幾次就服務器報錯了。所以也刪掉了。gpt顯示這個錯誤是跟SSH證書有關。
import requests
import pandas as pd
from urllib.parse import quote
import time
import random
import json
HEADERS = {'Accept':'*/*',
'Accept-Encoding':'gzip, deflate, sdch, br',
'Accept-Language':'zh-CN,zh;q=0.8',
'Connection':'keep-alive',
'Cookie':'BAIDUID=C4D08149D7EE627DC037119413418CA3:FG=1;'\
'BIDUPSID=C4D08149D7EE627DC037119413418CA3; PSTM=1540284487;'\
'pgv_pvi=9789244416; BDUSS=GF-S3Y5c1MybnhoTkhwMUxyWEhHM3ZreW1'\
'UTURiQk1TUFllMWc5V1ZWeUVHNGhkRVFBQUFBJCQAAAAAAAAAAAEAAAA~7j4'\
'5ztLKx8DtuaTIyzMyMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'\
'AAAAAAAAAAAAAAAAAAAAAAAAAAISOYF2EjmBdV; session_id=1567581077599;'\
'session_name=; validate=31187; MCITY=-%3A; M_LG_UID=960425535;'\
'M_LG_SALT=2cf3bbbbd3e5466b66a2529c037b982b',
'Host':'map.baidu.com',
'Referer':'https://map.baidu.com/search/%E9%83%91%E5%B7%9E%E5%B8%82%E4'\
'%BA%8C%E4%B8%83%E4%B8%87%E8%BE%BE%E4%B8%89%E5%8F%B7%E9%99%A2/@'\
'12650489.832882352,4101769.7450000006,18.35z/maptype%3DB_EARTH_'\
'MAP?querytype=s&da_src=shareurl&wd=%E9%83%91%E5%B7%9E%E5%B8%82%'\
'E4%BA%8C%E4%B8%83%E4%B8%87%E8%BE%BE%E4%B8%89%E5%8F%B7%E9%99%A2&c'\
'=268&src=0&pn=0&sug=0&l=18&b=(12650755.24571287,4101867.11178217'\
'83;12651854.04020792,4102020.4126732675)&from=webmap&biz_forward='\
'%7B%22scaler%22:1,%22styles%22:%22pl%22%7D&device_ratio=1',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) '
'AppleWebKit/537.36 (KHTML, like Gecko)'
'Chrome/55.0.2883.87 Safari/537.36',}
table=pd.read_csv(r"文件")
result_df = pd.DataFrame()
# 依次讀取每個城市的名稱和內容
for city in table.columns:
city_name = city
if city_name=='XXX':
code=aaa;
elif city_name=='XXX':
code=aaa
city_content = table[city].values.tolist()
city_content = list(filter(lambda x: str(x) != "nan", city_content))
list_aoiid=[]
for mall in city_content:
encoded_mall = quote(mall)
url = "https://map.baidu.com/?newmap=1&qt=s&da_src=searchBox.button&wd={}&c={}".format(
encoded_mall, code)
print(url)
delay = random.randint(2, 5) # 生成1到2之間的隨機整數(shù)
time.sleep(delay) # 延時隨機秒數(shù)
r = requests.get(url,headers=HEADERS, allow_redirects=True)
data = r.content
data=data.decode('utf-8')
data = json.loads(data)
aoi_id = data['result']['profile_uid']
print(aoi_id)
list_aoiid.append(aoi_id)
city_data = pd.DataFrame({
city_name: city_content,
'aoiid': list_aoiid})
result_df = pd.concat([result_df, city_data], ignore_index=True, axis=1)
print(result_df)
可以看見最后獲得的dataframe結果是這樣的。是的我個人很喜歡搞完一步就存dataframe。 沒有表頭自己加一下就好。然后我們隨機挑選幾個進行驗證。
驗證鏈接就是前面代碼print(url)輸出的鏈接,或者自己按照前面的方法,設置name和city id,也行。 也是很佩服參考鏈接的博主怎么找到這個是aoi id 的,以及發(fā)現(xiàn)aoi的接口
1.2 AOI獲取
不知道博主從哪里找到的接口: https://map.baidu.com/?newmap=1&qt=ext&uid=‘+AOI ID+’&ext_ver=new&ie=utf-8&l=1 更改里面的AOI ID就行。下圖中的Geo就是我們需要的 根據(jù)黑科技 | 百度地圖獲取地塊功能屬性(下)鏈接中的講解, aoi抓取到的數(shù)據(jù)是百度米制坐標,也就是百度墨卡托投影坐標系。而我們一般使用的都是wgs84大地坐標系。 需要轉換【百度米制】到【百度經(jīng)緯度坐標】再到【wgs84】。也就是【bd09mc】到【bd09】到【wgs84】 也就是要將下圖中右邊各個點的坐標進行轉換 這里的轉換跟黑科技 | 百度地圖獲取地塊功能屬性(下)提供的下載包中的轉換代碼做了對比,【bd09mc】到【bd09】沒有差別,是一樣的,而【bd09】到【wgs84】有出入??聪胍姆N吧。我懶得換了。
#from station import stations
import warnings
import xdrlib ,sys
import xlrd
import time
import socket
#bd墨卡托轉BD-09
import math
pi = 3.1415926535897932384626
def Yr(lnglat,b):
if b!='':
c=b[0]+b[1]*abs(lnglat[0])
d=abs(lnglat[1]/b[9])
d=b[2]+b[3]*d+b[4]*d*d+b[5]*d*d*d+b[6]*d*d*d*d+b[7]*d*d*d*d*d+b[8]*d*d*d*d*d*d
if 0>lnglat[0]:
bd=-1*c
else:
bd=c
lnglat[0]=bd
if 0 > lnglat[0]:
bd2 = -1 * d
else:
bd2 = d
lnglat[1] = bd2
return lnglat
return
def Mecator2BD09(lng,lat):
lnglat=[0,0]
Au=[[1.410526172116255E-8, 8.98305509648872E-6, -1.9939833816331, 200.9824383106796, -187.2403703815547,
91.6087516669843, -23.38765649603339, 2.57121317296198, -0.03801003308653, 1.73379812E7],
[- 7.435856389565537E-9, 8.983055097726239E-6, -0.78625201886289, 96.32687599759846, -1.85204757529826,
-59.36935905485877, 47.40033549296737, -16.50741931063887, 2.28786674699375, 1.026014486E7],
[- 3.030883460898826E-8, 8.98305509983578E-6, 0.30071316287616, 59.74293618442277, 7.357984074871,
-25.38371002664745, 13.45380521110908, -3.29883767235584, 0.32710905363475, 6856817.37],
[- 1.981981304930552E-8, 8.983055099779535E-6, 0.03278182852591, 40.31678527705744, 0.65659298677277,
-4.44255534477492, 0.85341911805263, 0.12923347998204, -0.04625736007561, 4482777.06],
[3.09191371068437E-9, 8.983055096812155E-6, 6.995724062E-5, 23.10934304144901, -2.3663490511E-4,
-0.6321817810242, -0.00663494467273, 0.03430082397953, -0.00466043876332, 2555164.4],
[2.890871144776878E-9, 8.983055095805407E-6, -3.068298E-8, 7.47137025468032, -3.53937994E-6, -0.02145144861037,
-1.234426596E-5, 1.0322952773E-4, -3.23890364E-6, 826088.5]]
Sp=[1.289059486E7, 8362377.87, 5591021, 3481989.83, 1678043.12, 0 ]
lnglat[0]=math.fabs(lng)
lnglat[1] =abs(lat)
for d in range(0,6):
if lnglat[1]>=Sp[d]:
c=Au[d]
break
lnglat=Yr(lnglat,c)
return lnglat
def BD092WGS84(lnglat):
#bd09-gcj
x_pi = 3.14159265358979324 * 3000.0 / 180.0
pi = 3.1415926535897932384626 # π
a = 6378245.0 # 長半軸
ee = 0.00669342162296594323 # 扁率
x = lnglat[0] - 0.0065
y = lnglat[1] - 0.006
z = math.sqrt(x * x + y * y) - 0.00002 * math.sin(y * x_pi)
theta = math.atan2(y, x) - 0.000003 * math.cos(x * x_pi)
lnglat[0] = z * math.cos(theta)
lnglat[1] = z * math.sin(theta)
dlat = tranlat1(lnglat[0] - 105.0, lnglat[1] - 35.0)
dlng = tranlng1(lnglat[0] - 105.0, lnglat[1] - 35.0)
radlat = lnglat[1] / 180.0 * pi
magic = math.sin(radlat)
magic = 1 - ee * magic * magic
sqrtmagic = math.sqrt(magic)
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi)
dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi)
mglat = lnglat[1] + dlat
mglng = lnglat[0] + dlng
return [lnglat[0]* 2 - mglng, lnglat[1] * 2 - mglat]
def tranlat1(lng, lat):
ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * math.sqrt(math.fabs(lng))
ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
math.sin(2.0 * lng * pi)) * 2.0 / 3.0
ret += (20.0 * math.sin(lat * pi) + 40.0 *
math.sin(lat / 3.0 * pi)) * 2.0 / 3.0
ret += (160.0 * math.sin(lat / 12.0 * pi) + 320 *
math.sin(lat * pi / 30.0)) * 2.0 / 3.0
return ret
def tranlng1(lng, lat):
ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + \
0.1 * lng * lat + 0.1 * math.sqrt(math.fabs(lng))
ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
math.sin(2.0 * lng * pi)) * 2.0 / 3.0
ret += (20.0 * math.sin(lng * pi) + 40.0 *
math.sin(lng / 3.0 * pi)) * 2.0 / 3.0
ret += (150.0 * math.sin(lng / 12.0 * pi) + 300.0 *
math.sin(lng / 30.0 * pi)) * 2.0 / 3.0
return ret
大體跟按照名稱進行aoi提取的代碼是一樣的,沒怎么改動。只不過原代碼因為是id和aoi坐標嵌套的,所以最后輸入坐標時可以直接用名稱。我這里還需要自己再改改。
import requests
import pandas as pd
from urllib.parse import quote
import time
import random
import json
table=pd.read_csv(r"XXXXX")
none_aoiid=[]
with open(r"XXXXX",
'a',newline='') as f:
for z in range(0,4):
print('現(xiàn)在的數(shù)字是',z)
city_mall=table.iloc[:,2*z]
id_mall=table.iloc[:,2*z+1]
id_content = id_mall.values.tolist()
id_content = list(filter(lambda x: str(x) != "nan", id_content))
for aoiid in id_content:
url_AOI = 'https://map.baidu.com/?newmap=1&qt=ext&uid={}'\
'&ext_ver=new&ie=utf-8&l=11'.format(aoiid)
print('處理鏈接',url_AOI)
r_AOI = requests.get(url_AOI,headers=HEADERS, allow_redirects=True)
data = r_AOI.content.decode('utf-8')
data = json.loads(data)
if 'geo' in data['content']:
geo_AOI = data['content']['geo']
geo_AOI = geo_AOI.split('|')
point = geo_AOI[2].split(",")
point_transform=[]
for i in range(int(len(point)/2)):#全部點的坐標,分別是x,y,的形式
if i==0: #[2:]的作用:刪除第一個坐標的‘1-’字符
point[2*i] = point[2*i][2:]
if i==int((len(point)/2)-1): #刪除最后一個坐標的‘;’字符
point[2*i+1] = point[2*i+1][:-1]
# print('第'+str(i)+'個點的坐標',float(point[2*i]),float(point[2*i+1]))#打印出各點的坐標
point_Mecator2BD09 = Mecator2BD09(float(point[2*i]),float(point[2*i+1]))
point_BD092WGS84 = BD092WGS84(point_Mecator2BD09)
point_transform.append(point_BD092WGS84)
point_str = '' #這是創(chuàng)建一個文本存儲
for j in range(len(point_transform)):
point_str = point_str+(str(point_transform[j])).replace(' ','')[1:-1]+';'
print(str(aoiid)+' 處理完畢。開始寫入')
line=aoiid+' '+point_str+'\n'
f.write(line)
else:
print(aoiid+'沒有找到坐標')
none_aoiid.append(aoiid)
print('沒有信息的aoi',str(none_aoiid))
將txt的iaoiid和csv文件進行匹配替換,最后結果是下面這樣
1.3 小結
Amap的爬蟲是我之前就做過的,用到就是下面的鏈接方法。需要一個個自己輸入,比較麻煩。 但是抓包工具比自己的代碼更強大,能搞定Amap的反扒機制。很強。
由于信息做過篩選所以百度這里只有坐標,最后生成AOI的shapefile的話也沒有什么信息。這個還需要改進其實。畢竟信息都爬下來了。
1.4 誤差原因
1.2的代碼中最后有輸出一個沒有爬取到的aoi_id信息。而在對上一篇爬蟲文里獲得的百度風向標結果進行分析時看見,有一些地方的id是重復的。一開始我以為是觸發(fā)了反扒機制,所以有些返回錯誤。剛剛對AOI生成的shapefile進行校驗時發(fā)現(xiàn),是百度地圖的AOI有些不準確,有的范圍太大了把其他區(qū)域也包括進去了。所以可能返回的商場是相同的id。
經(jīng)過我自己在高德和百度的實驗,百度aoi的位置更準確,也就是前面的代碼獲得最后轉wgs84的aoi在arcgis pro的底圖中很貼合。而高德使用下面的鏈接POI的體量 - AOI數(shù)據(jù)獲取腳本分享獲得不太準確,偏移較大。 所以下面鏈接的半自動化代碼其實也是需要改進的。
Amap AOI
這個是一個半自動化的抓取方式。用抓包工具Fiddler POI的體量 - AOI數(shù)據(jù)獲取腳本分享 這個鏈接現(xiàn)在會觸發(fā)高德反扒滑動條,如果躲不了就無法用:Python批量爬取高德AOI邊界數(shù)據(jù)+GIS可視化(超詳細)
柚子快報激活碼778899分享:【爬蟲】AOI
參考鏈接
本文內容根據(jù)網(wǎng)絡資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉載請注明,如有侵權,聯(lián)系刪除。