当前位置: 首页 > news >正文

卡证检测模型入门:Python爬虫采集训练数据

卡证检测模型入门:Python爬虫采集训练数据

想训练一个识别身份证、银行卡、驾照的模型,第一步也是最头疼的一步,就是找数据。网上公开的卡证数据集就那么几个,用的人多了,模型很容易“脸盲”,泛化能力上不去。自己拍?效率太低,种类也有限。

这时候,Python爬虫就成了我们的“数据采集员”。它能从那些允许爬取的公开网站上,自动、批量地帮我们收集各种卡证图片,快速扩充你的训练集。今天,我就带你从零开始,写一个专为卡证检测模型服务的Python爬虫,把数据采集这个“脏活累活”自动化起来。

整个过程,我们会聚焦在如何合规、高效地获取图片,并做好初步的清洗,让你拿到手的数据基本能用。放心,代码都很简单,哪怕你刚接触Python也能跟上。

1. 准备工作:环境与目标网站

在开始写代码之前,我们需要把“战场”准备好。这包括安装必要的工具,以及最重要的——找到一个合适的“数据源”。

1.1 安装必要的Python库

我们主要会用到几个库来处理网络请求和解析网页。打开你的终端或命令行,用pip安装它们:

pip install requests beautifulsoup4 pillow

简单解释一下它们是干嘛的:

  • requests:用来向网站发送请求,获取网页的HTML代码,就像你的浏览器一样。
  • beautifulsoup4:简称bs4,是个解析HTML的神器。网页代码像一团乱麻,它能帮你理清头绪,轻松找到图片链接。
  • PIL(通过pillow安装):Python的图像处理库。我们用它来打开下载的图片,进行简单的检查和格式统一。

1.2 寻找合规的图片源

这是最关键也最需要谨慎的一步。我们必须严格遵守法律法规和网站的robots.txt协议。绝对不要去爬取个人隐私信息、受版权严格保护的商业图库,或者明确禁止爬虫的网站。

那么,去哪里找呢?这里有一些思路:

  1. 公开的素材网站:一些提供“无版权”或“免费商用”图片的网站,可能会有证件、卡片类的模板或示意图。务必仔细阅读网站的使用条款
  2. 学术数据集的相关页面:有些研究机构在发布论文时,会提供示例图片的网页,这些通常是公开可用的。
  3. 模拟数据生成网站:有些网站专门生成用于测试的、虚构的证件图片,这类数据非常适合模型训练。

假设我们找到了一个合规的素材网站“example-stock.com”,它有一个“证件模板”分类页,列出了很多卡片图片。我们的目标就是从这个页面开始,爬取所有卡证图片。

重要原则:在编写和运行爬虫前,请务必:

  • 检查目标网站的robots.txt文件(通常在网站根目录,如https://example-stock.com/robots.txt)。
  • 控制请求频率,在代码中添加延时,避免对对方服务器造成压力。
  • 仅将数据用于个人学习和研究用途。

2. 编写爬虫核心:解析与下载

环境准备好了,目标也确定了,现在开始动手写爬虫的核心部分。我们会分两步走:先拿到图片的“地址”,再把图片“搬”回家。

2.1 解析网页,提取图片链接

首先,我们要让爬虫学会看网页,并从中找出所有图片的链接。我们以“example-stock.com/docs”这个假设的页面为例。

import requests from bs4 import BeautifulSoup import time def fetch_image_urls(page_url): """ 从给定页面中提取所有卡证图片的链接。 """ headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' } try: # 1. 发送请求获取网页内容 response = requests.get(page_url, headers=headers, timeout=10) response.raise_for_status() # 检查请求是否成功 response.encoding = response.apparent_encoding except requests.RequestException as e: print(f"请求页面失败: {e}") return [] # 2. 用BeautifulSoup解析HTML soup = BeautifulSoup(response.text, 'html.parser') # 3. 寻找图片标签。这里假设图片都在 <img> 标签里,并且是jpg/png格式 # 实际情况需要根据目标网站的HTML结构来调整选择器 image_elements = soup.find_all('img', src=True) image_urls = [] for img in image_elements: src = img['src'] # 构建完整的图片URL(处理相对路径) if src.startswith('http'): full_url = src else: # 简单的相对路径处理,实际情况可能更复杂 full_url = requests.compat.urljoin(page_url, src) # 过滤一下,只收集我们感兴趣的图片(例如,链接中包含‘card’或‘id’关键词,或者是指定格式) if full_url.lower().endswith(('.jpg', '.jpeg', '.png', '.bmp')): # 可以添加更多过滤条件,比如URL中包含‘id_card’, ‘license’等 image_urls.append(full_url) print(f"从页面 {page_url} 中找到 {len(image_urls)} 张图片。") return image_urls # 测试一下这个函数 if __name__ == '__main__': test_url = "https://example-stock.com/docs" # 请替换为实际可访问的测试URL urls = fetch_image_urls(test_url) for url in urls[:3]: # 打印前3个链接看看 print(url)

这段代码做了几件事:伪装成浏览器访问网页,把网页代码解析成清晰的结构树,然后在这棵树上找到所有<img>标签,并把它们的src属性(图片地址)拿出来。我们还做了简单的过滤,只保留常见格式的图片链接。

2.2 下载并保存图片

拿到链接列表后,下一步就是逐个下载并保存到本地文件夹。

import os from urllib.parse import urlparse def download_images(image_urls, save_dir='card_dataset_raw'): """ 下载图片列表并保存到指定文件夹。 """ # 创建保存目录 if not os.path.exists(save_dir): os.makedirs(save_dir) headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } downloaded_count = 0 for i, img_url in enumerate(image_urls): try: # 添加延时,做个有礼貌的爬虫 time.sleep(0.5) # 发送请求获取图片二进制内容 img_response = requests.get(img_url, headers=headers, timeout=15) img_response.raise_for_status() # 从URL中提取图片文件名 parsed_url = urlparse(img_url) filename = os.path.basename(parsed_url.path) if not filename: filename = f"image_{i}.jpg" # 构建完整的保存路径 save_path = os.path.join(save_dir, filename) # 防止文件名重复 counter = 1 while os.path.exists(save_path): name, ext = os.path.splitext(filename) save_path = os.path.join(save_dir, f"{name}_{counter}{ext}") counter += 1 # 保存图片 with open(save_path, 'wb') as f: f.write(img_response.content) downloaded_count += 1 print(f"已下载: {save_path}") except Exception as e: print(f"下载失败 {img_url}: {e}") continue print(f"下载完成!共成功下载 {downloaded_count} 张图片到 '{save_dir}' 目录。") # 将上一节获取的链接用于下载 if __name__ == '__main__': # 假设我们已经有了一个图片链接列表 sample_urls = [ 'https://example.com/image1.jpg', 'https://example.com/image2.png', ] # 此处应替换为 fetch_image_urls 函数返回的真实结果 download_images(sample_urls)

下载器会为每张图片创建一个独立的请求,并以二进制形式将内容写入本地文件。代码里包含了简单的错误处理和文件名去重逻辑,非常实用。

3. 处理多页面与翻页

一个分类页的图片通常有限,我们需要让爬虫学会“翻页”,遍历整个分类的所有页面。

如何翻页取决于网站的设计。最常见的有两种:

  1. 页码在URL中:比如page=1,page=2
  2. “加载更多”按钮或无限滚动:这通常需要分析网页的AJAX请求,稍微复杂一点。

我们以第一种简单情况为例:

def crawl_multiple_pages(base_url, total_pages=5): """ 爬取多个页面的图片。 假设翻页URL模式为: base_url + ‘?page=’ + 页码 """ all_image_urls = [] for page in range(1, total_pages + 1): print(f"正在爬取第 {page} 页...") page_url = f"{base_url}?page={page}" # 复用之前写的 fetch_image_urls 函数 urls_on_this_page = fetch_image_urls(page_url) all_image_urls.extend(urls_on_this_page) # 爬取每页后休息一下,避免请求过快 time.sleep(1) # 去重 unique_urls = list(set(all_image_urls)) print(f"总共收集到 {len(unique_urls)} 个唯一的图片链接。") return unique_urls # 使用示例 if __name__ == '__main__': base_url = "https://example-stock.com/category/ids" # 假设的基地址 all_urls = crawl_multiple_pages(base_url, total_pages=3) # 然后可以调用 download_images(all_urls) 进行下载

这样,我们就能自动抓取前N页的所有图片了。对于第二种“加载更多”的情况,你需要用浏览器的开发者工具(F12),查看网络请求,找到加载新数据时发送的真实请求地址和参数,然后用requests去模拟那个请求。

4. 数据清洗与初步整理

爬下来的图片不可能直接扔给模型训练。里面很可能有损坏的图片、完全不相关的图片,或者重复的图片。我们需要做一次初步的“大扫除”。

4.1 过滤非卡证图片

我们爬取的页面可能混有其他类型的图片。一个简单的方法是根据文件名或URL中的关键词进行过滤。但更可靠的方法是用已经训练好的简单分类模型或者规则进行初筛。这里我们先演示一个基于文件名的简单规则过滤。

def filter_card_images(image_urls, keywords=['id', 'card', 'license', 'passport', 'drive']): """ 根据URL中的关键词初步过滤卡证图片。 这是一个非常初级的方法,实际效果有限。 """ filtered_urls = [] for url in image_urls: url_lower = url.lower() if any(keyword in url_lower for keyword in keywords): filtered_urls.append(url) print(f"关键词过滤后,剩余 {len(filtered_urls)} 张图片。") return filtered_urls

4.2 检查并删除损坏图片

下载过程中可能产生损坏的图片文件,我们需要识别并删除它们。PIL库可以帮我们轻松完成这个任务。

from PIL import Image import os def remove_corrupted_images(image_dir): """ 检查目录中的图片文件,删除无法用PIL打开的损坏文件。 """ valid_extensions = ('.jpg', '.jpeg', '.png', '.bmp', '.gif') corrupted_count = 0 for filename in os.listdir(image_dir): filepath = os.path.join(image_dir, filename) # 只检查图片文件 if not filename.lower().endswith(valid_extensions): continue try: # 尝试打开图片 with Image.open(filepath) as img: img.verify() # 验证文件完整性 # 如果是PIL可读的格式,再转换一下模式确保没问题(可选) with Image.open(filepath) as img: img.load() except (IOError, SyntaxError, Exception) as e: print(f"损坏文件: {filename}, 错误: {e}") os.remove(filepath) corrupted_count += 1 print(f"清理完成,删除了 {corrupted_count} 个损坏的图片文件。")

4.3 基于内容的简单去重

完全相同的图片我们不需要多份。一个最基础的基于文件哈希值的去重方法如下:

import hashlib def deduplicate_by_hash(image_dir): """ 通过计算图片文件的MD5哈希值来去除完全相同的重复图片。 """ hashes = {} duplicates = [] for filename in os.listdir(image_dir): filepath = os.path.join(image_dir, filename) try: with open(filepath, 'rb') as f: file_hash = hashlib.md5(f.read()).hexdigest() if file_hash in hashes: duplicates.append(filepath) print(f"发现重复: {filename} 与 {hashes[file_hash]}") else: hashes[file_hash] = filename except Exception as e: print(f"处理文件 {filename} 时出错: {e}") # 删除重复文件 for dup in duplicates: os.remove(dup) print(f"去重完成,删除了 {len(duplicates)} 张重复图片。")

运行完这几步清洗,你的card_dataset_raw文件夹里的数据就干净多了,可以作为卡证检测模型训练集的补充素材了。当然,要用于正式训练,可能还需要人工进行更精细的标注(画框、分类),但数据采集的“苦力活”已经由爬虫高效完成了。

5. 总结

走完这一趟,你应该已经拥有了一个能自动从合规网站抓取卡证图片的小工具。整个过程的核心其实就三步:找到目标(解析网页)、获取数据(下载图片)、整理仓库(清洗去重)。

用爬虫来扩充数据集,最大的好处就是效率多样性。你可以针对不同样式、不同国家/地区的卡证,定制爬取策略,让模型见多识广。不过在实际操作中,有几点体会想分享一下:

首先,网站的HTML结构千变万化。我给的例子是比较理想的情况,真实网站可能需要你仔细分析,调整BeautifulSoup的选择器,甚至要处理JavaScript渲染的动态内容(这时可能需要用到Selenium)。

其次,礼貌和合规永远是第一位的。务必设置请求间隔(time.sleep),遵守robots.txt,不要给目标网站服务器带来负担。我们的目的是获取学习研究数据,不是攻击。

最后,爬虫得到的是原始数据。对于卡证检测这种任务,后续的标注(用LabelImg等工具标出卡片的位置)才是更大的工作量,但有了丰富的图片素材,标注工作才能开展。你可以把这个爬虫脚本当作一个数据流水线的起点,后续可以加入自动化的初步筛选(比如用一个简单的分类模型先过滤一遍),让整个数据准备流程更智能。

希望这个教程能帮你打开思路,顺利构建起自己的专属卡证数据集。数据处理是模型训练的基础,基础打好了,后面的路会顺很多。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

http://www.cnnetsun.cn/news/1972784.html

相关文章:

  • 进化版Toast-----snackbar已经完成
  • 告别Facebook WDA!2024年用Appium官方版搞定iOS自动化测试(附最新证书配置避坑)
  • 从影子到全局:EPWM多模块同步加载机制深度解析
  • CoPaw在供应链管理中的应用:需求预测与异常物流事件分析
  • python打包成 .so的实现步骤
  • IDE高效开发配置:使用IDEA进行cv_resnet101_face-detection模型Python后端调试
  • ESP32新手避坑:明明装了工具链,为啥还报‘xtensa-esp32-elf-gcc: Command not found‘?
  • Qwen3-ASR-1.7B部署避坑指南:常见问题与解决方案全解析
  • StructBERT在智能招聘中的应用:候选人简历与JD关键词语义匹配效果展示
  • ANIMATEDIFF PROGPU算力适配:RTX 4090双卡并行推理可行性与负载均衡
  • ollama一键部署QwQ-32B:64层高推理能力模型的低成本GPU算力实践
  • 12 论火箭回收的逆向思维落地方法 总结篇:逆向思维火箭回收方法核心成果与工程落地价值复盘
  • 如何对查询结果进行多字段排序_点击表头与ORDER BY手动编写结合
  • Qwen3-14B低代码开发应用:基于Dify快速构建AI智能体(Agent)
  • 处理10GB以上金融数据?我用Datatable的.jay格式把读取时间从‘喝杯咖啡’压缩到‘眨个眼’
  • Intv_ai_mk11一键部署与Node.js环境配置:打造全栈AI应用
  • Pi0机器人控制惊艳效果:上传三张图片,AI自动生成6自由度动作
  • Spring_couplet_generation 创意效果展示:AI生成多风格春联作品集
  • 告别窗口遮挡烦恼:3种方法让PinWin成为你的桌面效率助手
  • WAN2.2+SDXL_Prompt风格效果展示:‘未来科技发布会’提示词生成专业级视频
  • jQuery 选择器
  • 避坑指南:在PlatformIO上为ESP32-S3移植LVGL、AI语音和摄像头时,我遇到的5个典型问题
  • AMD Ryzen硬件调试终极指南:掌握SMUDebugTool的5个实战技巧
  • **全同态加密实战:用Python构建安全计算的“黑箱”系统**在现代数据隐私保护日益重要的背景下,**全同态加密(F
  • Qwen3.5-9B-AWQ-4bit实战案例:建筑图纸局部识别+材料规格中文提取
  • 【2026奇点智能技术大会权威解码】:AI代码性能分析的5大反直觉发现,92%工程师尚未掌握
  • LFM2.5-1.2B-Thinking-GGUF实操手册:32K上下文实测边界与长文本截断处理技巧
  • 从按键到启动:Rockchip RK3588双系统切换的硬件与软件协同设计
  • 线上故障排查思路与流程
  • 终极解决方案:如何让Calibre完美保留中文路径,告别拼音目录困扰