卡证检测模型入门: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协议。绝对不要去爬取个人隐私信息、受版权严格保护的商业图库,或者明确禁止爬虫的网站。
那么,去哪里找呢?这里有一些思路:
- 公开的素材网站:一些提供“无版权”或“免费商用”图片的网站,可能会有证件、卡片类的模板或示意图。务必仔细阅读网站的使用条款。
- 学术数据集的相关页面:有些研究机构在发布论文时,会提供示例图片的网页,这些通常是公开可用的。
- 模拟数据生成网站:有些网站专门生成用于测试的、虚构的证件图片,这类数据非常适合模型训练。
假设我们找到了一个合规的素材网站“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. 处理多页面与翻页
一个分类页的图片通常有限,我们需要让爬虫学会“翻页”,遍历整个分类的所有页面。
如何翻页取决于网站的设计。最常见的有两种:
- 页码在URL中:比如
page=1,page=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_urls4.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星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
