ddddocr滑块验证码:一场技术与艺术的融合
·
在数据科学与网络爬虫的世界里,每一行代码都承载着探索未知的使命。本文将带你走进一个精心设计的Python爬虫项目,该项目旨在从信用中国_广东中山:
aHR0cHM6Ly9jcmVkaXQuenMuZ292LmNuL3B1YmxpY2l0eS9wdWJsaWNpdHl0eXBlL3RvRGF0YUxpc3Q/YWxpYXM9WFpDRiZuYXZQYWdlPTE=
一、项目概述
广东信用网是一个公开的政府网站,提供了大量的行政处罚信息。这些信息对于研究政府监管、企业合规等方面具有重要意义。我们的目标是通过Python爬虫,自动化地抓取这些信息,并进行解析和存储。
二、代码结构
项目的核心类是 CreditGuangDong,它包含了以下几个主要方法:
-
初始化方法 (
__init__):- 初始化基本的URL、请求头、会话对象等。
- 设置验证码识别工具
ddddocr和重试机制retry。
-
获取响应 (
get_response):- 获取并识别验证码。
- 验证验证码的正确性。
- 请求列表页数据。
-
详情页请求 (
detail_response):- 请求详情页数据,并处理请求异常。
-
详情页解析 (
detail_parse):- 解析详情页的HTML内容,提取所需信息。
-
基础解析 (
base_parse):- 解析列表页的JSON数据,提取每条记录的ID,并请求对应的详情页。
- 调用
detail_parse方法解析详情页内容。
-
全站爬取 (
all_spider):- 循环请求每一页的数据,直到所有页面都爬取完毕。
-
主函数 (
main):- 启动爬虫,调用
all_spider方法。
- 启动爬虫,调用
三、详细代码解析
1. 初始化方法 (__init__)
def __init__(self):
self.base_url = "https://credit.zs.gov.cn/publicity/publicitytype/getDataListTpl"
self.get_yzm_url = "https://credit.zs.gov.cn/system/validatecode/getImgSlider"
self.check_yzm_url = "https://credit.zs.gov.cn/system/validatecode/sliderCheck"
self.detail_url = "https://credit.zs.gov.cn/XYGSXZCFDETAIL/"
self.check_yzm_data = {
'distance': '1232'
}
self.list_data = {
"shows": " CF_XDR_MC#A, CF_XDR_SHXYM#A, CF_WSH#B, CF_JDRQ$A, ID#A",
"alias": "XZCF", "zttypefield": "", "page": "1",
"judgePage": "true", "sgsSelType": "A"
}
self.headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36",
}
self.dict_info = {
'_id': 'ID', 'messageid': '详情页的一个参数(无用)', 'recflag': '详情页的一个参数(无用)',
'target': '行政相对人名称', 'ajzh': '想着处罚决定书文号', 'judgementdate': '处罚决定日期',
'sourceurl': '链接', 'sourcename': '数据来源', 'crawldate': '采集时间',
'content': '行政处罚内容'
}
self.session = session()
self.slide = ddddocr.DdddOcr(show_ad=False, det=False, ocr=False)
self.total_page = 5
self.page = 1
- URL:定义了各个接口的URL。
- 数据字典:用于存储和映射抓取到的数据。
- 会话对象:使用
requests.Session维持会话状态。 - 验证码识别工具:使用
ddddocr进行滑块验证码的识别。
2. 获取响应 (get_response)
@retry(tries=5, delay=2, max_delay=100, backoff=2)
def get_response(self):
"""
1: 先获取验证码图片;
2: 识别需要移动验证码的距离
3: 验证识别的验证码距离是否正确, 如果不正确则重复操作1和2
4: 请求列表页数据
:return:
"""
yzm_response = self.session.get(url=self.get_yzm_url, headers=self.headers)
if yzm_response.status_code == 200:
yzm_json = yzm_response.json()
modify_image = base64.b64decode(yzm_json['modifyImg'])
puzzle_image = base64.b64decode(yzm_json['puzzleImg'])
# 开始计算其距离
res = self.slide.slide_match(puzzle_image, modify_image, simple_target=True)
self.check_yzm_data['distance'] = res['target'][0]
# 开始验证验证码是否正确
check_response = self.session.post(url=self.check_yzm_url, headers=self.headers, data=self.check_yzm_data)
if 'false' in check_response.text:
print(f"验证码计算出现错误, 正在重新计算中")
return self.get_response()
list_response = self.session.post(url=self.base_url, headers=self.headers, data=self.list_data)
if list_response.status_code == 200:
return list_response
raise Exception(f"列表页请求状态码: {list_response.status_code}")
raise Exception(f"图片验证码请求状态码: {yzm_response.status_code}")
- 获取验证码:通过
get_yzm_url获取验证码图片。 - 识别验证码:使用
ddddocr计算滑块验证码的移动距离。 - 验证验证码:通过
check_yzm_url验证验证码的正确性。 - 请求列表页:如果验证码正确,请求列表页数据。
3. 详情页请求 (detail_response)
@retry(tries=6, delay=2, max_delay=100, backoff=2)
def detail_response(self, url):
response = requests.get(url=url)
if response.status_code == 200:
return response
raise Exception(f"详情页请求状态码: {response.status_code}")
- 请求详情页:通过
requests.get请求详情页数据。 - 处理异常:使用
retry模块处理请求异常,最多重试6次。
4. 详情页解析 (detail_parse)
def detail_parse(self, response, item):
html = etree.HTML(response.text)
content = html.xpath('//table[@class="detailTb"]')[0]
item['ajzh'] = ''.join(content.xpath('.//tr/td[contains(text(), "行政处罚决定书文号")]/following-sibling::td/text()')).strip()
item['wfxwlx'] = ''.join(content.xpath('.//tr/td[contains(text(), "违法行为类型")]/following-sibling::td/text()')).strip()
item['cfsy'] = ''.join(content.xpath('.//tr/td[contains(text(), "违法事实")]/following-sibling::td/text()')).strip()
item['cfyj'] = ''.join(content.xpath('.//tr/td[contains(text(), "处罚依据")]/following-sibling::td/text()')).strip()
item['cflb'] = ''.join(content.xpath('.//tr/td[contains(text(), "处罚类别")]/following-sibling::td/text()')).strip()
item['target'] = ''.join(content.xpath('.//tr/td[contains(text(), "行政相对人名称")]/following-sibling::td/text()')).strip()
item['fddbr'] = ''.join(content.xpath('.//tr/td[contains(text(), "法定代表人")]/following-sibling::td/text()')).strip()
item['cfjg'] = ''.join(content.xpath('.//tr/td[contains(text(), "处罚内容")]/following-sibling::td/text()')).strip()
item['cfje'] = ''.join(content.xpath('.//tr/td[contains(text(), "罚款金额")]/following-sibling::td/text()')).strip()
item['judgementdate'] = ''.join(content.xpath('.//tr/td[contains(text(), "处罚决定日期")]/following-sibling::td/text()')).strip()
item['department'] = ''.join(content.xpath('.//tr/td[contains(text(), "处罚机关:")]/following-sibling::td/text()')).strip()
item['content'] = etree.tostring(content, encoding='utf-8', method='html').decode('utf-8').replace('\n', '').replace('\r', '').replace(" ", '')
item['crawldate'] = datetime.datetime.now()
print(item)
- 解析HTML:使用
lxml解析详情页的HTML内容。 - 提取信息:通过XPath表达式提取所需的字段。
- 存储信息:将提取的信息存储到
item字典中,并打印出来。
5. 基础解析 (base_parse)
def base_parse(self, response):
json_data = response.json()
if self.page == 1:
count = json_data['count']
total_page = (count // 10) if (count % 10 == 0) else (count // 10 + 1)
self.total_page = total_page
print(f"总共有: {self.total_page}页")
data_list = json_data['dataList']
for data in data_list:
try:
detail_url = f"{self.detail_url}{data['ID']}.html"
detail_response = self.detail_response(url=detail_url)
except Exception as e:
print(f"详情页请求出现错误: {e}")
continue
try:
self.detail_parse(detail_response, item={'url': detail_url})
except Exception as e:
print(f"详情页解析出现错误: {e}")
continue
- 解析JSON:解析列表页返回的JSON数据。
- 计算总页数:如果当前是第一页,计算总页数。
- 请求详情页:遍历每条记录,请求对应的详情页。
- 解析详情页:调用
detail_parse方法解析详情页内容。
6. 全站爬取 (all_spider)
def all_spider(self):
while self.page <= self.total_page:
try:
self.list_data['page'] = str(self.page)
print(f"开始采集第: {self.page}页, 还剩: {self.total_page - self.page}页")
response = self.get_response()
except Exception as e:
print(f"请求出现错误:{e}")
self.page += 1
continue
try:
self.this_page_max_time = None
self.base_parse(response)
except Exception as e:
print(f"解析失败:{e}")
self.page += 1
- 循环请求:循环请求每一页的数据,直到所有页面都爬取完毕。
- 处理异常:捕获并处理请求和解析过程中可能出现的异常。
7. 主函数 (main)
def main(self):
self.all_spider()
- 启动爬虫:调用
all_spider方法启动爬虫。
四、总结
通过上述代码,我们实现了一个完整的爬虫项目,能够自动化地从广东信用网抓取行政处罚信息。这个项目不仅展示了如何处理滑块验证码,还展示了如何解析复杂的HTML结构,以及如何处理请求和解析过程中的异常。希望这篇文章能帮助你更好地理解和掌握Python爬虫技术,为你的数据科学之旅增添一份力量。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)