前言

本文记录抓取民政部数据时,出现的坑。主要抓取页面中县以上行政区划代码链接的具体内容。本文章仅用于笔者记录学习过程,请遵守相关法律法规,严禁用于非法途径。若读者因此作出任何危害网络安全的行为,后果自负,与笔者无关。

确定数据来源

首先需要确认县以上行政区划代码链接是否在响应中,右键查看网页源代码,在页面中搜索“2020年11月份县以上行政区划代码”,发现存在该关键字,可以确定能够从网页响应中获取需要的数据。

接着,在超链接“2020年11月份县以上行政区划代码”上右键检查,查看所指向的url地址,如下图所示:

image-20221219150724564

分析数据

点击url地址,发现页面跳转后的地址与点击的url地址不符

image-20221219150858325

怀疑在点击页面后,触发JS脚本链接重定向,于是将页面的响应打印输出,观察响应中是否存在页面跳转后的url地址,最终发现是有的,于是利用xpath表达式对真正的url地址进行提取。

编写程序

以下代码是根据上文的分析,利用requests库实现的;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
'''
使用requests库爬取民政部数据
'''
import requests
from fake_useragent import UserAgent
from lxml import etree


class MzbSpider:
def __init__(self):
self.url = 'https://www.mca.gov.cn/article/sj/xzqh/2020/'

def get_headers(self):
headers = {'User-Agent': UserAgent().random}
return headers

def get_html(self, url):
headers = self.get_headers()
html = requests.get(url=url, headers=headers).text
return html

def parse_data(self, url):
# 向真实二级页面发送请求
html = self.get_html(url)
eobj = etree.HTML(html)
city = eobj.xpath('//tr[@height="19"]')
for item in city:
li = {}
city_id = item.xpath('./td[2]//text()')[0]
city_name = item.xpath('./td[3]/text()')[0]
li[city_id] = city_name
print(li)

def parse_html(self):
html = self.get_html(self.url)
eobj = etree.HTML(html)
link = eobj.xpath('//ul[@class="alist_ul"]/table//tr[1]//a/@href')
href = 'https://www.mca.gov.cn' + link[0]
# 向子页面发起请求
html = self.get_html(href)
# 测试:查看子页面响应内容
# with open('index.html','w') as f:
# f.write(html)
# 获取真实的链接地址
target = etree.HTML(html).xpath('//body/script[1]/text()')[0].strip()
target_href = target.split('"')[1]
self.parse_data(target_href)


if __name__ == '__main__':
spider = MzbSpider()
spider.parse_html()

以下代码是利用selenium实现的,利用selenium无需考虑网站链接重定向的问题,此外以下代码还利用redis数据库做了增量爬虫;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
'''
使用selenium民政部数据爬取
'''
import sys
from selenium import webdriver
import redis
import time
from hashlib import md5


class MzbSpider:
def __init__(self):
# 打开浏览器并访问
options = webdriver.ChromeOptions()
options.add_argument('--headless')
self.driver = webdriver.Chrome(options=options)
self.driver.get('http://www.mca.gov.cn/article/sj/xzqh/2020/')
self.r = redis.Redis(host='localhost', port=6379)

def md5_href(self, href):
m = md5()
m.update(href.encode())
return m.hexdigest()

def parse_html(self):
# 查找第一个县级行政区代码链接
a = self.driver.find_element_by_partial_link_text('县以上行政区划代码')
# 判断网页是否被抓取
href = a.get_attribute('href')
if self.r.sadd('mzbSpider', self.md5_href(href)) == 0:
sys.exit('结束')
a.click()
time.sleep(1)
# 切换句柄
all_handles = self.driver.window_handles
self.driver.switch_to.window(all_handles[1])
# 获取网页内容
info = self.driver.find_elements_by_xpath('//tr[@height="19"]')
for item in info:
info_dic = {}
li = item.text.split()
info_dic['code'] = li[0]
info_dic['name'] = li[1]
print(info_dic)


if __name__ == '__main__':
spider = MzbSpider()
spider.parse_html()