上一版的行政区划过于复杂,是因为博主那时候还不习惯用beautifulsoup,然后一直用正则表达式硬撑,后面对pandas和beautifulsoup了解的深了,也发现正则表达式直接搜寻网页元素的麻烦之处,所以正好回来可以改一下,直接上代码,注释都有了,然后想细究的可以直接看网页源代码对照一下~

import requests
from bs4 import BeautifulSoup as bs
import time
import os
import pandas as pd
import re
def retry(url):try:req=requests.get(url,headers=agent)except:print('稍等几秒')time.sleep(5)req.encoding='GBK'#不要用req.encoding=req.apparent_encoding,这会导致编码为gb2312,有很多复杂的地名会无法解码,具体原因请百度return req
start_time=time.time()#计时开始
match_tag=['provincetr','citytr','countytr','towntr','villagetr']#这是每一级数据在网站中对应的标签名
choose_ls=[depth*2 if depth<=3 else 3*(depth-1) for depth in range(1,6)]#根据不同级数大小取12位代码前**位
rootdir='分级区划(新)'#设置根目录(凭需求改)
agent={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'}
initurl='http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2020/index.html'#原始网站
filelen=len(os.listdir(rootdir))#检验此时根目录下的文件数量,从而可以从上次爬取的某一级接续爬取
name_ls=['省级','地级','县级','乡级','村级']#表示每一级对应的名称
def execute(href_ls):#传入这一级的所有链接(一个链接代表一个级),对每一链接爬取其下一级的所有名称、代码以及(可能有的)下一级链接frame_ls=[]#生成一个空的列表来装载每个链接下面的dataframe格式的名称、代码、链接for href_code in range(len(href_ls)):href=href_ls[href_code]#取链接while True:if href:#如果href不为空字符串(下面有解释href为空字符串是怎么来的)strip_href=href.replace(href.split('/')[-1],'')#基本网页应该做一个变换以匹配页面中下一级链接href属性的取值(具体请自己看一下)req=retry(href)#进行retry以访问到网页soup=bs(req.text,'lxml')#beautifulsoup解析if depth!=4:col_name=['%s代码'%name_ls[depth],'%s名称'%name_ls[depth],'下一链接']#如果没爬到村级,那么下一级的信息为代码、名称以及其链接else:col_name=['村级代码','城乡分类代码','村级名称']#爬到村级了就不需要下一链接了,直接搞信息to_tag=soup.find_all(class_=match_tag[depth])#找到对应的标签if not to_tag:#没找到有两种原因:一是被反爬了,返回的页面信息是乱码;二是跳过了一级,例如东莞、中山没有县级(区),直接到乡级(镇),需要我们识别for eachdep in range(depth,5):find_tag=soup.find_all(class_=match_tag[eachdep])if find_tag:break#遍历后面的级数,找到了就breakif not find_tag:print('出现识别错误')#如果没有找到任何的标签匹配,那么肯定出现了反爬,让程序休眠一段时间再次在while true后面运行(大批量出现问题时,断网重连是个较好的措施)time.sleep(6)continueif depth==0:#如果深度为0,即在根网址爬取省级信息#我们不用to_tag识别,转而用属性中href加html的识别所在链接的标签,是因为根网址的源代码结构不大一样,这能更容易的找到每个省份所在的标签to_tag=soup.find_all(attrs={'href':re.compile(r'\d+\.html')})namelist=[each.text for each in to_tag]#每个标签的text即每个省份的名字next_href=[strip_href+each.attrs['href'] for each in to_tag]#用之前的strip_href加到这里标签中的href凑成一个完整的链接name_code=[each.attrs['href'][:2] for each in to_tag]#由于省份代码(包括下面的各级代码)是12位不满的部分取0的,对于省份只需要前两位即可,下同zip_ls=list(zip(name_code,namelist,next_href))#用zip打包这些信息elif to_tag:if depth==4:#如果深度为4,开始爬村级,那么只要识别到每个to_tag的信息即可,用列表生成式顺序取zip_ls=[[i.text for i in each.find_all('td')] for each in to_tag]else:zip_ls=[]for each_tag in to_tag:#这里面每一个tag里面都有两个a标签(前面一个a是代码后面一个是名称),而属性的href都是一样的,只要取一个即可level_code=each_tag.find_all('td')[0].text[:choose_ls[depth]]#也是只取代码前一部分即可level_name=each_tag.find_all('td')[1].text#下一级没有链接的情况:村级或者市辖区(举例:广东省-深圳市-市辖区),所以注意区分,如果没找到的话,level_href为空字符串level_href=strip_href+each_tag.a.attrs['href'] if 'href' in str(each_tag) else ''zip_ls.append((level_code,level_name,level_href))#加入zip_ls中else:zip_ls=[('','',href)]#如果没有识别到to_tag,但有下一级的信息,证明是东莞等城市,这一级的代码、名称即为空,链接也转为下一级的链接再来识别else:zip_ls=[['']*3]#如果href为空字符串,那么下一级的三项数据全部填为空字符串(即某一路径五级填不满的情况,虽然事实证明应该只有市辖区是如此,但应该防患于未然)each_frame=pd.DataFrame(data=zip_ls,columns=col_name)#用dataframe包装这一链接下所有下一级的信息each_frame['index']=len(each_frame)*[href_code]#标注一下这一级每个链接所在的索引并传给这个dataframeprint(href_code)#打印索引以便定位frame_ls.append(each_frame)break#所有序列完成后break出while true的循环return frame_ls#返回这一级链接的所有下一级信息
for depth in range(filelen,5):print('开始爬取%s'%name_ls[depth])if depth==0:href_ls=[initurl]#第0级(最开始)的根节点就只有一个根链接else:file=pd.read_csv(rootdir+'\\%s.csv'%name_ls[depth-1],keep_default_na=False)href_ls=list(file['当前链接'])#其他的通过读取反映frame_ls=execute(href_ls)#通过上面的函数返回下一级的信息total_frame=pd.concat(frame_ls,ignore_index=True)#将他们组装起来if depth==0:merge_frame=total_frame#如果是第0级,不用匹配else:file['index']=file.index#标记这一级的索引merge_frame=pd.merge(file,total_frame,on=['index'])#通过下一级信息dataframe中的index和这一级的匹配,merge在一起del merge_frame['当前链接']#删除当前链接del merge_frame['index']#删除索引列,这个不必要保留,只做mergeif depth!=4:merge_frame.rename(columns={'下一链接':'当前链接'},inplace=True)#将下一链接改名为当前链接,在下一步作为当前链接进行层次遍历merge_frame.to_csv(rootdir+'\\%s.csv'%name_ls[depth],index=False)#每一级信息保存print('爬到%s,总用时%d秒'%(name_ls[depth],time.time()-start_time))#记录时间

最近国家统计局这方面反爬好像加强了,用校园网爬的很不顺畅而且响应也慢,而且很可能一直反爬(ip),所以最理想的结果是在一个网比较好的环境,而且最好有两个及以上的无线网环境,便于反爬后切换


之后又用多线程搞了一版代码,参考了其他多线程爬虫博主的一些格式,这个要快很多,前三级可以十秒左右弄完,然而后面反爬很严重,基本每隔三千多个就出问题而且设置程序休眠也无法解决,可能是从ip根源上反爬的,所以建议大家要么用代理ip(博主不想付费)或者多无线网的环境便于切换,要么就不停断网重连,只有这种方案了;大家可以根据自己的网速和网络环境择机选择这两种代码方案:

import requests
from bs4 import BeautifulSoup as bs
import time
import os
import pandas as pd
from queue import Queue
from threading import Thread
import re
start_time=time.time()
match_tag=['provincetr','citytr','countytr','towntr','villagetr']
choose_ls=[depth*2 if depth<=3 else 3*(depth-1) for depth in range(1,6)]#根据不同级数大小取12位代码前**位
rootdir='分级区划(多线程)'
agent={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'}
initurl='http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2020/index.html'
filelen=len(os.listdir(rootdir))
name_ls=['省级','地级','县级','乡级','村级']
def execute(in_q,out_q):while not in_q.empty():href_code=in_q.get()href=href_ls[href_code]while True:if href:strip_href=href.replace(href.split('/')[-1],'')try:href_req=requests.get(href,headers=agent)except:print('稍等几秒')time.sleep(5)continuehref_req.encoding='GBK'soup=bs(href_req.text,'lxml')if depth!=4:col_name=['%s代码'%name_ls[depth],'%s名称'%name_ls[depth],'下一链接']else:col_name=['村级代码','城乡分类代码','村级名称']to_tag=soup.find_all(class_=match_tag[depth])if not to_tag:for eachdep in range(depth,5):find_tag=soup.find_all(class_=match_tag[eachdep])if find_tag:breakif not find_tag:print('出现识别错误')time.sleep(6)continueif depth==0:to_tag=soup.find_all(attrs={'href':re.compile(r'\d+\.html')})namelist=[each.text for each in to_tag]next_href=[strip_href+each.attrs['href'] for each in to_tag]name_code=[each.attrs['href'][:2] for each in to_tag]zip_ls=list(zip(name_code,namelist,next_href))else:if to_tag:if depth==4:zip_ls=[[i.text for i in each.find_all('td')] for each in to_tag]else: zip_ls=[]for each_tag in to_tag:level_code=each_tag.find_all('td')[0].text[:choose_ls[depth]]level_name=each_tag.find_all('td')[1].textlevel_href=strip_href+each_tag.a.attrs['href'] if 'href' in str(each_tag) else ''zip_ls.append((level_code,level_name,level_href))else:zip_ls=[('','',href)]else:zip_ls=[['']*3]each_frame=pd.DataFrame(data=zip_ls,columns=col_name)each_frame['index']=len(each_frame)*[href_code]breakout_q.put(each_frame)in_q.task_done()print(href_code)
for depth in range(filelen,5):print('开始爬取%s'%name_ls[depth])if depth==0:href_ls=[initurl]else:file=pd.read_csv(rootdir+'\\%s.csv'%name_ls[depth-1],keep_default_na=False)href_ls=list(file['当前链接'])href_q=Queue()#定义一个保存当前链接的队列out_queue=Queue()#定义一个返回下一级信息的队列for index in range(len(href_ls)):href_q.put(index)#放进去for number in range(20):#开20个线程thread=Thread(target=execute,args=(href_q,out_queue,))thread.daemon=Truethread.start()href_q.join()frame_ls=[]for each in range(len(href_ls)):frame_ls.append(out_queue.get())#逐个取出返回信息的元素total_frame=pd.concat(frame_ls,ignore_index=True)if depth==0:merge_frame=total_frameelse:file['index']=file.indexmerge_frame=pd.merge(file,total_frame,on=['index'])del merge_frame['当前链接']del merge_frame['index']if depth!=4:merge_frame.rename(columns={'下一链接':'当前链接'},inplace=True)merge_frame.to_csv(rootdir+'\\%s.csv'%name_ls[depth],index=False)print('爬到%s,总用时%d秒'%(name_ls[depth],time.time()-start_time))

爬取行政区划(改版)相关推荐

  1. java爬取行政区划代码

    1.导入依赖 <dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifac ...

  2. 使用java爬取国家统计局的12位行政区划代码

    前言: 本文基于j2ee的原始url进行都写,解析指定内容时也是使用很傻的形式去查找指定格式的字符串来实现的. 更优雅的方式是可以使用apache的HttpClient和某些文档模型将HTML字符串构 ...

  3. 【Java】Java爬取国家统计局五级行政区划编码(省、市(州)、县(区)、乡(镇)、村)

    今天使用了idea+java爬取国家统计局12位行政区划编码,包括省.市(州).县(区).乡(镇).以及村委会/委员会等的行政编码和名称,将区划编码以及名称保存在数据库中. 本文内容包括数据库数据效果 ...

  4. Python 爬虫 中国行政区划信息爬取 (初学者)

    Python 爬虫 中国行政区划信息爬取 (初学者) 背景 环境准备 代码片段 1.定义地址信息对象 2.地址解析对象 2.1 获取web信息 2.2 web信息解析 2.3 区划信息提取 2.4 省 ...

  5. Python爬取国家统计局行政区划信息

    1. 简介: 2020年统计用区划代码和城乡划分代码,将其中的行政区划爬取并保存成树状结构,以支持类似如下查询: dic['北京市']['市辖区'].keys() dict_keys(['东城区', ...

  6. 爬取全国城市及辖区的人口、面积、行政区划代码及邮编

    前言 最近实习一直在弄爬虫相关的内容,顺便开个博客整理记录一下自己学习的过程,方便自己以后回顾. 当然如果恰好对你有帮助欢迎点赞~ 需求:获取全国各省份的城市及辖区的人口.面积.行政区划代码及邮编 目 ...

  7. 中国行政区划数据爬取并层级体系与编码标准

    中国行政区域划分,既行政区划,大体上分省.市.区县.乡镇街道四级,行政区划的勘界.调整.命名等,由国家各级民政部门负责. 每个月,国家民政部会在官网上公示全部县以上行政区划编码和县以下行政区划变更情况 ...

  8. python+selenium+Chrome(无头版)爬取国家地表水水质自动监测实时数据发布系统(修改版)——动态网页爬虫

    这是一篇动态网页的爬虫教程,新手可以操作一下,简单实用. 一.前言 这篇blog跟python+selenium+phantomJS爬取国家地表水水质自动监测实时数据发布系统--动态网页爬虫的爬虫思路 ...

  9. 爬取2017年底最新中国全国五级行政区划代码省市区县乡镇村MySQL数据库

    刚开始学习爬虫,学了pyspider,就想练练手.想到不久前需要一些云南地区的行政数据,还是在网络百度半天才下载的.现在既然会爬虫了,那就自己动手,随时可以用相对新的数据了(因为统计局最新的才更新到2 ...

  10. Python爬虫:爬取今日头条“街拍”图片(修改版)

    前言 在参考<Python3网络爬虫开发实战>学习爬虫时,练习项目中使用 requests ajax 爬取今日头条的"街拍"图片,发现书上的源代码有些已经不适合现在了, ...

最新文章

  1. BBI综述:在微生物组研究中使用宏转录组
  2. 想要快速获客?送你 2 个小程序互推方法
  3. boost asio 简单示例
  4. 假如,只是假如把支付宝存储服务器炸了,里面的钱还在么?
  5. 33%制造企业跑步上云,云MES市场将达到23.4亿美元
  6. 粤教版管理计算机中的文件教案,最新粤教版初中信息技术第一册教案(全册).docx...
  7. [react] React中怎么操作虚拟DOM的Class属性
  8. myeclipse 怎么安装与激活
  9. 橱窗布置(信息学奥赛一本通-T1279)
  10. 图解SQL inner join、left join、right join、full outer join、union、union all的区别
  11. 脑语言v0.5.8 2500令【单字编程】
  12. 阿里云域名转入/转出操作教程
  13. 农村饮用水项目微信支付完整代码
  14. 用Powerpoint (PPT)制作并导出矢量图、高分辨率图
  15. 导致谷歌账号停用的原因
  16. android zuk彩蛋,联想ZUK Z2你真的会玩吗?来看U-Touch 2.0的那些小彩蛋
  17. 一键切换固定IP地址和自动分配IP地址的脚本
  18. 哈工大 计算机系统安全 复习整理 作业答案
  19. 切,老掉牙的TCP知识
  20. html让下拉框自动选择,html下拉框设置连接 html怎么设置下拉列表必须选择

热门文章

  1. QTouch Linux 组态软件
  2. 用友u8不显示服务器名,用友u8提示对数据库服务器名
  3. linux操作系统期末考试试题及答案,Linux操作系统期末复习题(含答案).doc
  4. 关于Mysql以及Sqlyog的下载以及使用记录
  5. 使用SQLyog远程连接数据库
  6. qq代码大全可复制_给QQ换上“彩色动态昵称”,太酷了!
  7. 2022最新分布式面试题合集,轻松应对Java面试
  8. Java 分布式框架面试题合集
  9. VS2012下MFC程序的换肤(Skin++、SkinMagic、USkin、SkinSharp)
  10. 《我是一只IT小小鸟》会员书评