1 引言
由于前面几篇关于百度迁徙获取数据的文章反响不错,有好多dalao联系我。在十一月份的时候,一位老师联系到我,并且表示还需要腾讯位置大数据,然后给我发来一篇博客问我能不能模仿着实现,她给我发的这篇博客确实让我受益匪浅。这篇博客来自于河海大学的吴同学,里面的代码应该也是他原创的,于是乎我就厚着脸皮在他原有的代码上进行拓展,并且厚着脸皮写下了这篇博客。刚好在早先我拜读过吴同学关于腾讯位置大数据的这篇论文,这也有助于我理解他博客,论文如下:
本博客中,关于爬取部分的代码思路主要来自于吴同学的这篇博客,而后面对数据进行清洗的代码思路是原创的。
首先,我们注意到,腾讯位置大数据的url虽然已经变了,但是吴同学之前实验提供的url仍然可以用,当时我为了图省事也没改,所以下面代码部分的url还是基于这个。打开这个url,网页大概长这样:
所以,这篇博客的任务就是——爬取特定时间分辨率下的腾讯位置大数据,并且进行制图。
2 数据爬取
2.1 代码
import requests
import json
import pandas as pd
import time
import datetime
import threading
def get_TecentData(count=4,rank=0): # 先默认为从rank从0开始
url='https://xingyun.map.qq.com/api/getXingyunPoints'
# url = 'https://heat.qq.com/'
locs=''
paload={'count':count,'rank':rank}
response=requests.post(url,data=json.dumps(paload))
datas=response.text
dictdatas=json.loads(datas) #d umps是将dict转化成str格式,loads是将str转化成dict格式
times=dictdatas["time"] # 有了dict格式就可以根据关键字提取数据了,先提取时间
print(times)
locs=dictdatas["locs"] # 再提取locs(这个需要进一步分析提取出经纬度和定位次数)
locss=locs.split(",")
temp=[] # 空数组以存放数据
for i in range(int(len(locss)/3)):
lat = locss[0+3*i] # 纬度
lon = locss[1+3*i] # 经度
count = locss[2+3*i]
temp.append([times,int(lat)/100,int(lon)/100,count]) # 容器追加四个字段的数据:时间,纬度,经度和定位次数
return temp
def write_TecentData():
now = str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
print('now: ', now)
print('=========================================================')
for i in range(4):
temp = get_TecentData(4, i)
now = now.replace(':','-')
result=pd.DataFrame(temp)
result.dropna() # 数据过滤
if i == 0:
result.columns = ['time', 'lat', 'lon','count']
result.to_csv(f'Tencent Data/TecentData_{now}.csv',mode='a',index = False) # 输出路径
print('=========================================================')
def restart_TecentData():
try:
write_TecentData()
print('完成 ============================ 等待中 === 1')
except:
print('遇到了一个错误---------------------正在重新启动')
time.sleep(7)
try:
write_TecentData()
print('完成 ============================ 等待中 === 2')
except:
print('重启过程中再次遇到错误-----------正在再次重新启动')
time.sleep(8)
try:
write_TecentData()
print('完成 ============================ 等待中=== 3')
except:
print('重启过程中再再次遇到错误-----------正在再次重新启动')
time.sleep(9)
try:
write_TecentData()
print('完成 ============================ 等待中=== 4')
except:
print('重启过程中再再再次遇到错误-----------正在再次重新启动')
time.sleep(10)
write_TecentData()
print('完成 ============================ 等待中 === 5')
def automated_module():
print('===================================================================================')
thr = threading.Timer(1800, automated_module) # 每30分钟
thr.start()
now1 = datetime.datetime.now()
print(f'{now1} ----- 开始执行')
restart_TecentData()
now2 = datetime.datetime.now()
print(f'{now2} ----- 执行结束 用时{now2 - now1}')
print('===================================================================================\n\n\n')
automated_module()
代码解析都在注释里,照例不多说。
该代码利用的是threading的循环定时器,在定时爬取期间不占用内存,并且时间比较准确,可以长期放在服务器上跑。并且,出现错误的时候可以进行五次重启,基本上运行后挂着就不用管它了。
我代码是放在办公室的主机上24小时不间断爬取的,我的时间分辨率是30分钟(即每30分钟爬取,代码里可以调整),到写下这篇博客的时候已经连续爬3个月了,没有出现任何问题。
2.2 结果
我特定开了远程到办公室主机上截个图,输出终端大概长这样:
一个时间输出一个csv文件到指定文件夹里,csv文件的命名方式带有时间,时间精确到秒。大概长这样:
随便打开一个csv,time字段里是日期格式,lat是纬度,lon是精度,count是定位次数(和人口密度似乎是正相关),具体长这样:
吴同学写完博客后似乎腾讯只让爬取0.05经纬度分辨率的数据了,空间分辨率大概只有5km,这导致一个时间的文件只有26m了(不然空间分辨率太高我也存不下这么多。。。)。所以,可能不太适合做小尺度的研究,我最近做一个相关的论文使用到这个做验证,县域尺度的大概只有100个点左右,市域的只有500个,空间分辨率实在是很差。
3 数据清洗
3.1 代码
首先有必要说明本代码大概只能整合四个csv文件,对四个文件里的各坐标点进行经纬度筛选——合并——去重。如果有需要做多个文件处理的,可以对代码进行修改。
import csv
import pandas as pd
def reader_csv(filepath): # 读取数据
csv_data = pd.read_csv(str(filepath)) # 读取数据
df = pd.DataFrame(csv_data) # 转化为df格式
return df
def coordinates_filter(data, lat, lon): # 坐标筛选器
lat_min = lat[0] # 分别获取经纬度最大值和最小值
lat_max = lat[1]
lon_min = lon[0]
lon_max = lon[1]
regional_data = data[(data['lat']>=lat_min) & (data['lat']<=lat_max) & (data['lon']>=lon_min) & (data['lon']<=lon_max)]
return regional_data
def append_multidata(data1, data2, data3, data4): # 合并多个文件夹数据
d1 = data1.append(data2)
d2 = d1.append(data3)
d3 = d2.append(data4)
data = d3
return data
def consolidate_duplicate(data): # 对重复坐标的值取平均值
# data = pd.DataFrame(data)
mean_functions = {'count': 'mean'}
consolidation = data.groupby(['lat', 'lon']).agg(mean_functions)
return consolidation
def writer_csv(data, outpath): # 写入csv
data.to_csv(str(outpath), header=True, index=True)
print('完成')
filepath1 = r'新建文件夹 (2)\TecentData_2020-12-20 02-00-27.csv'
filepath2 = r'新建文件夹 (2)\TecentData_2020-12-20 06-00-24.csv'
filepath3 = r'新建文件夹 (2)\TecentData_2020-12-20 10-00-20.csv'
filepath4 = r'新建文件夹 (2)\TecentData_2020-12-20 14-00-25.csv'
outpath = r'新建文件夹 (2)\output.csv'
pop_data1 = reader_csv(filepath1) # 读取数据
pop_data2 = reader_csv(filepath2)
pop_data3 = reader_csv(filepath3)
pop_data4 = reader_csv(filepath4)
data = append_multidata(pop_data1, pop_data2, pop_data3, pop_data4) # 合并多个数据
print(data)
region_data = coordinates_filter(data, [-4, 78], [65, 155]) # 坐标筛选,获取区域性数据
consolidation = consolidate_duplicate(region_data) # 多坐标重复的数据取平均值
writer_csv(consolidation, outpath) # 输出清洗后的数据
3.2 结果
数据清晰后输出的csv大概长这样:
只剩下坐标和值的数据了。
4 可视化展示
很惭愧,为了不让我这可怜的电脑爆炸,我坐标筛选出了东亚地区的,可视化也只做了东亚地区的。时间好像是2020年12月的某一周的2点6点10点14点18点22点整合的。
操作基本上就是把csv导入进去,然后导出个shp,把在海里的点删掉,然后对shp点数据调个色变个形状就完成了。我对这个数据的要求没有那么严格,所以就没认真制图了,这个可视化只是给大家一个参考。
5 后记
关于这个数据,其真实性和准确性我也没深究,因为要用到这种时间分辨率这么高的情况实在太少了,而且也不好验证(除非能拿到手机信令数据之类的做验证)。
但是如果是与小时间分辨率的数据做验证,效果还是可以的。比如我前几天拿2020年12月合成的腾讯位置大数据和WorldPop的2020年人口分布数据做相关性分析(空间分辨率为5km,我对WorldPop做了空间重采样),全东北地区的相关性在0.8以上,其中各市大概都在0.6以上。把全东北分为市辖区和县,显示市辖区在0.8左右,而县在0.6左右,这说明腾讯位置大数据在人多的地方可能相对靠谱,人少的地方就一般。
我是从2020年12月17日开始爬取到2021年3月11日停止。如果需要获取数据的话,可以通过邮箱(chinshuuichi@qq.com)联系我(不建议用私信,上csdn很随缘),会收一点点辛苦费。
最后最后,如果觉得有帮助,希望大家能打赏支持一下(我的乞讨码在下面)~
-----------------------分割线(以下是乞讨内容)-----------------------