2020年8月1日更:百度迁徙在5月8日后就不开放了,目前好像只能爬取到3月15日之前的数据,而且爬取的时候会遇到挺多问题的(具体我也不知道,不开放后我就没爬过了,但是最近很多朋友在问)。评论里关于爬取遇到的问题很多我也没遇到过,没办法帮到你们。如果想直接获取数据(5月8日前的数据)的话,可以私聊或者电子邮件(chinshuuichi@qq.com)联系我(会收一点手工费…)。
2020年10月21日更:百度迁徙重新开放了,数据从9月22开始都有。以下旧的代码需要更改一个地方,即把代码里所有r=response.text[3:-1]
全部替换为r=response.text[4:-1]
即可。
简介
百度迁徙 :百度迁徙
不多逼逼,相关的自己了解。趁这几天比较好抓取数据,需要的数据就赶紧抓抓抓。
效果展示
不着急看代码,先给你们看一波效果图,各位看官看完效果图看看是不是自己需要的再看代码。
我是把获得的数据存成一个xls格式,因为csv换列不太方便(我不会)所以我选择了xls。这张图里表是我的家乡泉州一月、二月一共两个月的迁出数据,左边第一列是所有城市的编码(身份证前6位,这也和url要求的编码一样),左边第二列是所有城市的名称,第一行是日期。为什么我要把表弄成这样呢?因为我要把表丢进GIS里做可视化(后面有可视化的图),又懒得改,所以这样方便一点,直接丢进去就可以了。
然后为了让各位看官看到像百度迁徙网站那样的前一百名排序,我就特地点了排序截了一张图(1月1日排序)如下。(这两个是同一个表)
前面说要展示的可视化,我选的好像是泉州的1月9日的迁出。随手一截。
准备——城市编码
在正式搬出代码前,可能需要个字典,要不然都不知道哪个城市是什么编码。
这个我是新建一个py文件,和主程序丢在同一个文件夹里,然后在主程序里直接import调用。
CitiesCode为城市编码,一行代表一个省份,部分比较长的省份我就分了两行。
ProvinceCode为省份编码。
#ChineseAdminiDivisionsDict.py
CitiesCode = {
'北京市':110000,'天津市':120000,
'石家庄市':130100,'唐山市':130200,'秦皇岛市':130300,'邯郸市':130400,'邢台市':130500,'保定市':130600,'张家口市':130700,'承德市':130800,'沧州市':130900,'廊坊市':131000,'衡水市':131100,
'太原市':140100,'大同市':140200,'阳泉市':140300,'长治市':140400,'晋城市':140500,'朔州市':140600,'晋中市':140700,'运城市':140800,'忻州市':140900,'临汾市':141000,'吕梁市':141100,
'呼和浩特市':150100,'包头市':150200,'乌海市':150300,'赤峰市':150400,'通辽市':150500,'鄂尔多斯市':150600,'呼伦贝尔市':150700,'巴彦淖尔市':150800,'乌兰察布市':150900,'兴安盟':152200,'锡林郭勒盟':152500,'阿拉善盟':152900,
'沈阳市':210100,'大连市':210200,'鞍山市':210300,'抚顺市':210400,'本溪市':210500,'丹东市':210600,'锦州市':210700,'营口市':210800,'阜新市':210900,'辽阳市':211000,'盘锦市':211100,'铁岭市':211200,'朝阳市':211300,'葫芦岛市':211400,
'长春市':220100,'吉林市':220200,'四平市':220300,'辽源市':220400,'通化市':220500,'白山市':220600,'松原市':220700,'白城市':220800,'延边朝鲜族自治州':222400,
'哈尔滨市':230100,'齐齐哈尔市':230200,'鸡西市':230300,'鹤岗市':230400,'双鸭山市':230500,'大庆市':230600,'伊春市':230700,'佳木斯市':230800,'七台河市':230900,'牡丹江市':231000,'黑河市':231100,'绥化市':231200,'大兴安岭地区':232700,
'上海市':310000,
'南京市':320100,'无锡市':320200,'徐州市':320300,'常州市':320400,'苏州市':320500,'南通市':320600,'连云港市':320700,'淮安市':320800,'盐城市':320900,'扬州市':321000,'镇江市':321100,'泰州市':321200,'宿迁市':321300,
'杭州市':330100,'宁波市':330200,'温州市':330300,'嘉兴市':330400,'湖州市':330500,'绍兴市':330600,'金华市':330700,'衢州市':330800,'舟山市':330900,'台州市':331000,'丽水市':331100,
'合肥市':340100,'芜湖市':340200,'蚌埠市':340300,'淮南市':340400,'马鞍山市':340500,'淮北市':340600,'铜陵市':340700,'安庆市':340800,'黄山市':341000,'滁州市':341100,'阜阳市':341200,'宿州市':341300,'六安市':341500,'亳州市':341600,'池州市':341700,'宣城市':341800,
'福州市':350100,'厦门市':350200,'莆田市':350300,'三明市':350400,'泉州市':350500,'漳州市':350600,'南平市':350700,'龙岩市':350800,'宁德市':350900,
'南昌市':360100,'景德镇市':360200,'萍乡市':360300,'九江市':360400,'新余市':360500,'鹰潭市':360600,'赣州市':360700,'吉安市':360800,'宜春市':360900,'抚州市':361000,'上饶市':361100,
'济南市':370100,'青岛市':370200,'淄博市':370300,'枣庄市':370400,'东营市':370500,'烟台市':370600,'潍坊市':370700,'济宁市':370800,'泰安市':370900,'威海市':371000,'日照市':371100,'临沂市':371300,'德州市':371400,'聊城市':371500,'滨州市':371600,'菏泽市':371700,
'郑州市':410100,'开封市':410200,'洛阳市':410300,'平顶山市':410400,'安阳市':410500,'鹤壁市':410600,'新乡市':410700,'焦作市':410800,'濮阳市':410900,'许昌市':411000,'漯河市':411100,'三门峡市':411200,'南阳市':411300,'商丘市':411400,'信阳市':411500,'周口市':411600,'驻马店市':411700,'济源市':419001,
'武汉市':420100,'黄石市':420200,'十堰市':420300,'宜昌市':420500,'襄阳市':420600,'鄂州市':420700,'荆门市':420800,'孝感市':420900,'荆州市':421000,'黄冈市':421100,'咸宁市':421200,'随州市':421300,'恩施土家族苗族自治州':422800,'仙桃市':429004,'潜江市':429005,'天门市':429006,'神农架林区':429021,
'长沙市':430100,'株洲市':430200,'湘潭市':430300,'衡阳市':430400,'邵阳市':430500,'岳阳市':430600,'常德市':430700,'张家界市':430800,'益阳市':430900,'郴州市':431000,'永州市':431100,'怀化市':431200,'娄底市':431300,'湘西土家族苗族自治州':433100,
'广州市':440100,'韶关市':440200,'深圳市':440300,'珠海市':440400,'汕头市':440500,'佛山市':440600,'江门市':440700,'湛江市':440800,'茂名市':440900,'肇庆市':441200,'惠州市':441300,'梅州市':441400,'汕尾市':441500,'河源市':441600,'阳江市':441700,'清远市':441800,'东莞市':441900,'中山市':442000,'潮州市':445100,'揭阳市':445200,'云浮市':445300,
'南宁市':450100,'柳州市':450200,'桂林市':450300,'梧州市':450400,'北海市':450500,'防城港市':450600,'钦州市':450700,'贵港市':450800,'玉林市':450900,'百色市':451000,'贺州市':451100,'河池市':451200,'来宾市':451300,'崇左市':451400,
'海口市':460100,'三亚市':460200,'三沙市':460300,'儋州市':460400,'五指山市':469001,'琼海市':469002,'文昌市':469005,'万宁市':469006,'东方市':469007,'定安县':469021,'屯昌县':469022,'澄迈县':469023,'临高县':469024,'白沙黎族自治县':469025,'昌江黎族自治县':469026,'乐东黎族自治县':469027,'陵水黎族自治县':469028,'保亭黎族苗族自治县':469029,'琼中黎族苗族自治县':469030,
'重庆市':500000,
'成都市':510100,'自贡市':510300,'攀枝花市':510400,'泸州市':510500,'德阳市':510600,'绵阳市':510700,'广元市':510800,'遂宁市':510900,'内江市':511000,'乐山市':511100,'南充市':511300,'眉山市':511400,'宜宾市':511500,'广安市':511600,'达州市':511700,'雅安市':511800,'巴中市':511900,'资阳市':512000,'阿坝藏族羌族自治州':513200,'甘孜藏族自治州':513300,'凉山彝族自治州':513400,
'贵阳市':520100,'六盘水市':520200,'遵义市':520300,'安顺市':520400,'毕节市':520500,'铜仁市':520600,'黔西南布依族苗族自治州':522300,'黔东南苗族侗族自治州':522600,'黔南布依族苗族自治州':522700,
'昆明市':530100,'曲靖市':530300,'玉溪市':530400,'保山市':530500,'昭通市':530600,'丽江市':530700,'普洱市':530800,'临沧市':530900,'楚雄彝族自治州':532300,'红河哈尼族彝族自治州':532500,'文山壮族苗族自治州':532600,'西双版纳傣族自治州':532800,'大理白族自治州':532900,'德宏傣族景颇族自治州':533100,'怒江傈僳族自治州':533300,'迪庆藏族自治州':533400,
'拉萨市':540100,'日喀则市':540200,'昌都市':540300,'林芝市':540400,'山南市':540500,'那曲市':540600,'阿里地区':542500,
'西安市':610100,'铜川市':610200,'宝鸡市':610300,'咸阳市':610400,'渭南市':610500,'延安市':610600,'汉中市':610700,'榆林市':610800,'安康市':610900,'商洛市':611000,
'兰州市':620100,'嘉峪关市':620200,'金昌市':620300,'白银市':620400,'天水市':620500,'武威市':620600,'张掖市':620700,'平凉市':620800,'酒泉市':620900,'庆阳市':621000,'定西市':621100,'陇南市':621200,'临夏回族自治州':622900,'甘南藏族自治州':623000,
'西宁市':630100,'海东市':630200,'海北藏族自治州':632200,'黄南藏族自治州':632300,'海南藏族自治州':632500,'果洛藏族自治州':632600,'玉树藏族自治州':632700,'海西蒙古族藏族自治州':632800,
'银川市':640100,'石嘴山市':640200,'吴忠市':640300,'固原市':640400,'中卫市':640500,
'乌鲁木齐市':650100,'克拉玛依市':650200,'吐鲁番市':650400,'哈密市':650500,'昌吉回族自治州':652300,'博尔塔拉蒙古自治州':652700,'巴音郭楞蒙古自治州':652800,'阿克苏地区':652900,'克孜勒苏柯尔克孜自治州':653000,'喀什地区':653100,'和田地区':653200,'伊犁哈萨克自治州':654000,'塔城地区':654200,'阿勒泰地区':654300,
'石河子市':659001,'阿拉尔市':659002,'图木舒克市':659003,'五家渠市':659004,'北屯市':659005,'铁门关市':659006,'双河市':659007,'可克达拉市':659008,'昆玉市':659009,
'台湾省':710000,'香港特别行政区':810000,'澳门特别行政区':820000
}
ProvinceCode = {
'北京市':110000,'天津市':120000,'河北省':130000,'山西省':140000,'内蒙古自治区':150000,
'辽宁省':210000,'吉林省':220000,'黑龙江省':230000,
'上海市':310000,'江苏省':320000,'浙江省':330000,'安徽省':340000,'福建省':350000,'江西省':360000,'山东省':370000,
'河南省':410000,'湖北省':420000,'湖南省':430000,'广东省':440000,'广西自治区':450000,'海南省':460000,
'重庆市':500000,'四川省':510000,'贵州省':520000,'云南省':530000,'西藏自治区':540000,
'陕西省':610000,'甘肃省':620000,'青海省':630000,'宁夏自治区':640000,'新疆自治区':650000,
'台湾省':710000,'香港特别行政区':810000,'澳门特别行政区':820000
}
代码
这个代码运行的话可以直接获取一月份、二月份的数据。三月份由于才过了两天,我就打上了#,因为我有强迫症,三月份到时候再搞。
在调用里,我们记得要调用我们写的字典文件,调用城市编码和省份编码。
# -*- coding: utf-8 -*-
import requests
import json
import time
import xlrd
import xlwt
from ChineseAdminiDivisionsDict import CitiesCode, ProvinceCode
def migration_all_date(areaname,classname,no,direction): #定义生成不同时期,不同城市,不同迁徙方向
if no == -1 :
no = CitiesCode[str(areaname)]
#######创建一个workbook########
workbook = xlwt.Workbook(encoding = 'utf-8') # 创建一个workbook 设置编码
worksheet = workbook.add_sheet('Sheet', cell_overwrite_ok=True) # 创建一个worksheet
#################写入行头各城市代码及其城市名###############
if direction == 'in' :
nameofdire = '迁入来源地'
if direction == 'out':
nameofdire = '迁出目的地'
CitiesOrder = {} #存放城市序号的空字典
worksheet.write(0 , 0 , label='城市代码') #写入行头
worksheet.write(0 , 1 , label=str(nameofdire)) #写入行头
times = 1
for key , value in CitiesCode.items():
worksheet.write(times , 0 , label=str(value)) #写入城市代码
worksheet.write(times , 1 , label=str(key)) #写入城市名
CitiesOrder[str(key)] = times #写入城市序号字典
times += 1
########################设定日期##############################
datelist = [] #日期列表
counter_data = 2 #日期计数器
for date1 in range(20200101,20200132): #一月份
datelist.append(date1)
for date2 in range(20200201,20200230): #二月份
datelist.append(date2)
for date3 in range(20200301,20200302): #三月份
datelist.append(date3)
for date in datelist: #遍历所有日期
datename = date
time.sleep(1)
url=f'http://huiyan.baidu.com/migration/cityrank.jsonp?dt={classname}&id={no}&type=move_{direction}&date={date}'
print(url)
response=requests.get(url, timeout=2) #发出请求并json化处理
time.sleep(1)
r=response.text[4:-1] #去头去尾
data_dict=json.loads(r) #字典化
if data_dict['errmsg']=='SUCCESS':
data_list=data_dict['data']['list']
time.sleep(1)
################写入###############
worksheet.write(0 , counter_data , label=datename) #写入表头————日期
for a in range(len(CitiesCode)):
worksheet.write(a+1 , counter_data , label=0) #先把当前日期下该列所有城市值置0
############获取数据###########
for i in range (len(data_list)):
city_name=data_list[i]['city_name'] #城市名
value=data_list[i]['value'] #当日迁徙量所占百分比值
##############写入#############
worksheet.write(CitiesOrder[str(city_name)] , counter_data , label=value) #查找城市序号字典,在对应的行里写入相应的值
counter_data += 1 #日期计数器自加一
workbook.save(f"{areaname}-{nameofdire}.xls") #保存
def circu_exe_direction(areaname,classname,no):
mukous = ['in','out']
for mukou in mukous:
migration_all_date(areaname,classname,no,mukou)
print(str(areaname)+'---','完成')
if __name__=="__main__":
circu_exe_direction('泰安市','city',-1)
circu_exe_direction('威海市','city',-1)
circu_exe_direction('昌吉回族自治州','city',-1)
circu_exe_direction('福建省','province',350000)
circu_exe_direction('湖北省','province',420000)
circu_exe_direction('北京市','province',110000)
circu_exe_direction('全国','country',0)
print('全部完成')
我可能需要重点说明一下这个函数migration_all_date(areaname,classname,no,direction)
,areaname是给你输出的xls文件命名的;classname是填url的;no是城市编码,如果是城市的话就填-1就行了,它就会自己去字典里找,避免手残输错,如果是省份的话就得手动输入,direction是迁徙方向,因为一个城市有两个迁徙方向(迁入和迁出),所以会生成两个xls表。
因为还要手动填direction好麻烦,所以我就又加了circu_exe_direction(areaname,classname,no)
,具体用法如下。
如果要获取市的数据,直接就circu_exe_direction('泰安市','city',-1)
就行了,最后数字填-1它就自己去字典里查对应的城市编码。另外名字一定要填官方的名字,不能多字少字,不然字典找不到,或者可以事先看看字典里怎么写的,反正我按省份分行的,很好查。
如果是省的话,就需要circu_exe_direction('福建省','province',350500)
,中间要改成province(直辖市也需要改成province),最后的编码要手动输入,不知道编码的百度一下就行。
如果要获取全国数据的话,就需要circu_exe_direction('全国','country',0)
,注意中间变成了country。
编辑日志
3月7日:修正了字典里 永州市 的城市编码。
3月8日:在“准备——城市编码”部分添加了省份编码,并在代码部分添加了相关的模块。
系列文章
【Python】基于Python的百度迁徙2——迁徙规模指数(附代码)
【Python】基于Python的百度迁徙3——城内出行强度(附代码)
【Python】基于Python的百度迁徙4——上班和休闲指数(附代码)
-----------------------分割线(以下是乞讨内容)-----------------------