栏目分类

你的位置:天顺注册 > 最新动态 > Python办公——自动爬取《国家统计局2023年统计用区划代码》

Python办公——自动爬取《国家统计局2023年统计用区划代码》

发布日期:2024-08-24 12:49    点击次数:55
一、需求背景    由于《涉农贷款专项统计制度》修订内容变动较大,需要根据《2023年统计用区划代码和城乡分类代码》重新界定农户、农村企业等。    数据来源网址为:国家统计局http://www.stats.gov.cn/sj/tjbz/tjyqhdmhcxhfdm/2023/32.html    手动操作截图如下:

图片

图片

图片

图片

    路径总结为:扬州市→高邮市→三垛镇→辖内村居,显然通过复制粘贴至Excel表格中是不可行的,Python处理后的效果为:

图片

    此处爬取了全省21971条记录,在表格中直接查询也可以,后期再制作成多级联动下拉列表也是不错的选择。二、难点说明    第一、向下钻取一层,网址的变化规律如何?    第二、怎样快速地获取最末级的村居记录?    第三、如何同时获取市级/县级/镇级的记录?    第四、怎样建立四级行政区划的对应关系?三、代码实现1 导入第三方库# 数据读写与处理import pandas as pd# 设置表格样式from openpyxl import load_workbookfrom openpyxl.styles import Border, Side, Alignmentimport xlwings as xw2 预先定义函数2.1 设置表格样式
def formation(path):    # 读取工作簿    wb = load_workbook(path)    for sheet in wb.sheetnames:        # 获取工作表        ws = wb[sheet]        # 设置单元格的边框、对齐方式        for i in range(ws.max_column):            for j in range(1, ws.max_row+1):                row = ws[chr(ord('A')+i) + str(j)]                row.alignment = Alignment(horizontal='center', vertical='center')                row.border = Border(left=Side(border_style='thin'),                                    right=Side(border_style='thin'),                                    top=Side(border_style='thin'),                                    bottom=Side(border_style='thin'))    # 另存为工作簿    wb.save(path)
2.2 调整行高列宽def adjust(path): # 读取工作簿 wb_ = app.books.open(path) for sheet in wb_.sheet_names: # 获取工作表 ws_ = wb_.sheets[sheet] # 实现表格行高或列宽自动调整 ws_.autofit() # 保存工作簿 wb_.save(path) # 关闭工作簿 wb_.close()2.3 更新网页地址
def Newaddress(address,add):    # 按“/”分列    ls = address.split('/')    # 最末级的取倒数两个字符    ls[-1] = ls[-1][-2:]    # 将下一级的添加至列表    ls.append(add)    # 再以“/”连接    address = '/'.join(ls)    # 返回网页地址    return address
2.4 批量爬取数据def Getdata(address): # 读取网页数据 df = pd.read_html(f'http://www.stats.gov.cn/sj/tjbz/tjyqhdmhcxhfdm/2023/{address}.html') # 整理网页数据,去重空值及设计表头 df = df[0].dropna() new_header = df.iloc[0].tolist() df = df.iloc[1:].reset_index(drop=True) df.columns = new_header # 按照【统计用区划代码】的命名规则,确定网址变化规律及递归终止条件 code = df['统计用区划代码'][0] # 点击进入某个市级 if code[-8:] == '0'*8: count = 4 # 点击进入某个县级 elif code[-6:] == '0'*6: count = 6 # 点击进入某个村级 elif code[-3:] == '0'*3: count = 9 # 已达村级,返回数据框 else: return df # 遍历每个【统计用区划代码】 for code in df['统计用区划代码']: # 将市级、县级、镇级分别存储起来,应是唯一的 ## 筛选符合条件的数据记录 label = df[df['统计用区划代码']==code].reset_index(drop=True) # 当前为市级界面,将市级存储起来 if count == 4: location['市级'][0].append(label) # 当前为县级界面,将县级存储起来 elif count == 6: location['县级'][0].append(label) # 当前为镇级界面,将镇级存储起来 elif count == 9: location['镇级'][0].append(label) # 获取下一级的关键字 add = code[:count] # 错误捕捉器的作用为:防止【市辖区】溢出 try: # 深度优先搜索的递归思想,即:将【扬州市-宝应县-鲁垛镇-辖内村】搜索完毕后再进行下一轮 # 先预处理网页地址,再调用递归函数 result = Getdata(Newaddress(address,add)) # 若返回值不为空,将村级存储起来 if not (result is None): location['村级'][0].append(result) except: # 【市辖区】只有县级,人为添加【镇级】与【村级】 location['镇级'][0].append(label) location['村级'][0].append(label)3 自动化主程序3.1 批量获取数据
# 定义初始化start = '32'location = {'市级':[[],4],'县级':[[],6],'镇级':[[],9],'村级':[[],12]}mapping = {'111':'主城区','112':'城乡结合区','121':'镇中心区','122':'镇乡结合区','123':'特殊区域','210':'乡中心区','220':'村庄'}path = 'C:/ZeroTrain/扬州市统计用区划代码和城乡分类代码.xlsx'# 调用定义函数Getdata(start)
3.2 数据处理保存# 遍历主键【市级、县级、镇级、村级】for hierarchy in location: # 纵向合并记录 df_temp = pd.concat(location[hierarchy][0]).reset_index(drop=True) # 填充缺失值,【市辖区】【城乡分类代码】 df_temp = df_temp.fillna('111') # 新增公共字段 for name in location: df_temp[f'公共简码_{name}'] = df_temp['统计用区划代码'].str[:location[name][1]] if hierarchy == '村级': df_temp['城乡分类类型'] = df_temp['城乡分类代码'].map(mapping) # 字段重新命名 df_temp.rename(columns={'统计用区划代码':f'统计用区划代码_{hierarchy}','名称':f'名称_{hierarchy}'},inplace=True) # 添加至字典中 location[hierarchy].append(df_temp)# 分别获取【市级、县级、镇级、村级】记录df_shi = location['市级'][2].drop(columns=['公共简码_县级','公共简码_镇级','公共简码_村级'])df_xian = location['县级'][2].drop(columns=['公共简码_镇级','公共简码_村级'])df_zhen = location['镇级'][2].drop(columns=['公共简码_市级','公共简码_村级'])df_cun = location['村级'][2].drop(columns=['公共简码_市级','公共简码_县级','公共简码_村级'])# 横向合并记录final = df_shi.merge(df_xian,on='公共简码_市级').merge(df_zhen,on='公共简码_县级').merge(df_cun,on='公共简码_镇级')# 保存数据记录final[['名称_市级','名称_县级','名称_镇级','名称_村级','统计用区划代码_村级','城乡分类代码','城乡分类类型']].to_excel(f'{path}',index=False)# 启动Excel程序app = xw.App(visible=False, add_book=False)# 格式化数据记录formation(path)adjust(path)# 退出Excel程序app.quit()四、末尾总结    第一、向下钻取一层,网址的变化规律如何?        首先,【市级】对应【统计用区划代码】前4位,【县级】对应【统计用区划代码】前6位,【镇级】对应【统计用区划代码】前9位;其次,每向下钻取一层,上层的网址要缩减为倒数2位,如:【扬州市】为“32/3210.html”,【高邮市】为“32/10/321084.html”,【三垛镇】为“32/10/84/321084108.html”;    第二、怎样快速地获取最末级的村居记录?        想要重复同样处理的时候用递归会很方便,在本例中使用的递归是“深度优先搜索”,又称“回溯法”,其特征是一直向下搜索,无法继续时返回。例如,扬州市→高邮市→三垛镇→辖内村居,进行逐层点击与访问;

图片

    第三、如何同时获取市级/县级/镇级的记录?    采用了字典的方式,反用了另一种规律,【市级】的【统计用区划代码】后8位均为0,【县级】的【统计用区划代码】后6位均为0,【镇级】的【统计用区划代码】后3位均为0。当界面记录满足相应条件时,筛选记录后直接以数据框的形式存储至列表中,便于Pandas操作;    第四、怎样建立四级行政区划的对应关系?    在进行合并前,可以做一下粗略的校验,【市级】、某市下【县级】数据框的长度应该与网页上展示的一致;【镇级】和【村级】数据框的长度应该相等,要注意在【县级】切换时【村级】记录会增加空值的情形,应予以判断剔除。    通过向上一级的【公共简码】来作为横向连接的公共字段,从而构建庞大的多维数据集。如果想要合并的代码简洁,则尽量保证公共字段的唯一性,否则必须分别指明左右的连接字段。五、多学一点 本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报。

上一篇:B站视频下载最强攻略,手把手教会你
下一篇:全球金融市场暴跌避险情绪弥漫,压低了芝加哥谷物价格