资讯动态

Python爬虫实战:批量下载旗帜图片源码解析与避坑指南

发布时间:2026/10/15 7:02:26 来源:尧图企业网站定制
简介这份资源是面向Python爬虫初学者与数据分析入门者的实战源码包围绕东京奥运会奖牌国家及地区旗帜图片的抓取与处理展开帮助读者把网页请求、页面解析、图片下载与本地存储串成一条完整链路。包内以HTML与Jupyter Notebook两类文件为主Notebook便于边运行边观察结果HTML则用于呈现页面结构与解析目标压缩包整体约54KB轻量易上手。内容涉及requests发送HTTP请求、BeautifulSoup解析HTML、CSS选择器定位图片链接、PIL图像处理、CSV或JSON数据存储以及异常处理与robots.txt合规意识等知识点适合作为爬虫练手项目或课程案例。目前已有217人学习下载读者可据此掌握从网页抓取到图片落盘的完整流程并理解爬虫稳定运行与合规采集的基本思路。1. 从零拆解旗帜图片爬取一份能直接跑的源码包到底长什么样做数据标注、做视觉素材库、做地理信息可视化的人迟早会碰到同一个需求手里要有一批干净、命名规范、尺寸统一的旗帜图片。手动一张张右键另存几十张还能忍上百张就是纯体力活而且命名混乱、格式不一后期清洗的时间比下载还长。这份「部分国家及地区旗帜图片数据爬取源代码.zip」解决的正是这个环节——它把「找到图源、批量拉取、按规则落盘」这条链路固化成了可复用的脚本而不是一次性手工操作。它适合三类人一是需要快速搭建本地旗帜素材库的开发者二是想拿一个真实可跑的小项目练手爬虫基础请求、解析、下载、异常处理的新手三是做数据集预处理、需要把图片按统一命名归档的从业者。源码包本身不绑定特定平台核心逻辑就是「请求页面 → 提取图片链接 → 下载到本地目录」你拿到后改几个参数就能套用到别的图片采集场景。下面我按实际拆包的顺序把这份源码怎么用、参数怎么调、哪里容易翻车讲清楚。2. 源码结构与运行环境先看清目录再动手拿到压缩包别急着双击运行先解压看结构。这类爬取源码包通常不会太复杂但目录组织方式直接决定了你改代码时找不找得到地方。我拆过的同类包里常见的组织是「入口脚本 配置区 输出目录」三块有的会把请求头和下载逻辑拆成单独模块有的全塞在一个文件里。先花两分钟确认结构比后面满屏找变量强。2.1 典型目录构成与各文件职责解压后大概率会看到类似这样的布局不同作者命名习惯不同但职责大同小异flags_crawler/ ├── main.py # 入口串联抓取与下载流程 ├── config.py # 或写在 main 顶部的常量区URL、路径、并发数 ├── requirements.txt # 依赖清单通常只有 requests / beautifulsoup4 ├── output/ # 图片落盘目录可能预置了 .gitkeep └── README.md # 简短说明别指望写得很全main.py是主战场抓取逻辑、解析逻辑、保存逻辑基本都在这里。config.py或者文件顶部的常量区是你最该先看的地方——目标 URL、保存路径、请求超时、重试次数这些参数都在这儿。requirements.txt决定了你要装什么这类图片爬取项目依赖通常很轻requests负责发请求beautifulsoup4或lxml负责解析 HTML偶尔会用os、time、random这些标准库做路径处理和限速。提示如果包里没有requirements.txt直接看 import 语句把第三方库名记下来手动装别猜。2.2 环境准备与依赖安装环境这块不用搞太复杂Python 3.7 以上都能跑。我一般习惯先建虚拟环境避免和系统里其他项目的包版本打架# 创建并激活虚拟环境Windows 用 venv\Scripts\activate python -m venv venv source venv/bin/activate # 安装依赖有 requirements.txt 就直接装 pip install -r requirements.txt # 没有清单文件时手动装核心两个 pip install requests beautifulsoup4装完先别跑全量用python -c import requests, bs4; print(ok)验证一下导入没问题。这一步看着多余但我见过太多「跑一半报 ModuleNotFoundError」的情况都是环境没激活或者装到了全局。参数上requests版本建议 2.25 以上老版本对某些 TLS 配置的兼容性差容易在请求阶段就卡住。2.3 关键配置项逐个说明打开主脚本重点盯这几个变量它们决定了脚本能不能跑通、跑得快不快、会不会被封配置项常见命名作用调整建议目标地址BASE_URL/TARGET_URL图片列表所在页面换成你要抓的页面保存路径SAVE_DIR/OUTPUT_PATH图片落盘位置用绝对路径避免相对路径踩坑请求头HEADERS伪装浏览器身份至少带 User-Agent超时TIMEOUT单次请求等待上限设 1015 秒太短易误判失败延时DELAY/SLEEP请求间隔0.52 秒别设 0请求头里最关键的是User-Agent很多图源站点会直接拒绝没有 UA 的请求返回 403。保存路径建议写绝对路径相对路径在不同工作目录下执行时落盘位置会变找图的时候容易懵。延时参数是很多人忽略的设成 0 全速跑短时间几十上百个请求打过去轻则被限流重则 IP 被临时封后面全失败。3. 抓取与下载核心逻辑请求、解析、落盘三步走这份源码的价值不在「能下载」而在「下载得规整」。真正要理解的是它怎么把一堆散落的图片链接变成命名统一的本地文件。整个流程拆开就是三步发请求拿页面、从页面里提取图片地址、按规则保存到本地。每一步都有细节下面逐个拆。3.1 发送请求与页面获取第一步是拿到图片列表页的 HTML。核心代码通常长这样import requests HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36 } def fetch_page(url, timeout15): 请求页面返回 HTML 文本失败返回 None try: resp requests.get(url, headersHEADERS, timeouttimeout) resp.raise_for_status() # 非 2xx 状态码直接抛异常 resp.encoding resp.apparent_encoding # 防止中文乱码 return resp.text except requests.RequestException as e: print(f[请求失败] {url} - {e}) return None这段逻辑的关键点有三个。headers里带 UA 是基本操作缺了它很多站点直接返回 403。raise_for_status()让非 200 的响应立刻暴露出来而不是拿着一个错误页面去解析那样后面提取链接会得到空结果你还以为是解析写错了。apparent_encoding是根据内容自动推断编码比硬写utf-8稳遇到 GBK 编码的页面不会变乱码。参数上timeout别省网络抖动时没有超时设置脚本会一直挂着看起来像卡死。3.2 解析页面提取图片链接拿到 HTML 后要从里面把图片地址抠出来。常见做法是用 BeautifulSoup 找img标签取src属性from bs4 import BeautifulSoup from urllib.parse import urljoin def extract_image_urls(html, base_url): 从 HTML 中提取所有图片链接补全为绝对地址 soup BeautifulSoup(html, html.parser) urls [] for img in soup.find_all(img): src img.get(src) or img.get(data-src) # 兼容懒加载 if not src: continue full_url urljoin(base_url, src) # 相对路径转绝对 urls.append(full_url) return urls这里有两个容易翻车的点。一是懒加载很多现代页面图片真实地址放在>import os import time import random def download_image(url, save_dir, filename): 下载单张图片并保存返回是否成功 os.makedirs(save_dir, exist_okTrue) filepath os.path.join(save_dir, filename) try: resp requests.get(url, headersHEADERS, timeout15, streamTrue) resp.raise_for_status() with open(filepath, wb) as f: for chunk in resp.iter_content(chunk_size8192): f.write(chunk) return True except requests.RequestException as e: print(f[下载失败] {url} - {e}) return False finally: time.sleep(random.uniform(0.5, 1.5)) # 随机延时降低被封风险命名规范是这份源码区别于「随手下载」的核心。常见做法是用图片 URL 的最后一段作为文件名或者根据页面上的国家/地区名称重命名。streamTrue配合iter_content是下载大图的标准姿势避免一次性把整个响应读进内存。finally里的随机延时是血泪经验——固定间隔容易被识别出机器行为随机化之后请求节奏更像人。参数上chunk_size设 8192 字节是通用值太小写入频繁太大内存占用高一般不用改。3.4 主流程串联与批量执行把上面三步串起来就是完整的批量抓取流程def main(): html fetch_page(BASE_URL) if not html: print(首页获取失败终止) return img_urls extract_image_urls(html, BASE_URL) print(f共提取到 {len(img_urls)} 张图片链接) success 0 for idx, url in enumerate(img_urls, 1): ext os.path.splitext(url)[1] or .png filename fflag_{idx:03d}{ext} # 统一编号命名 if download_image(url, SAVE_DIR, filename): success 1 print(f完成成功 {success} / 总计 {len(img_urls)}) if __name__ __main__: main()fflag_{idx:03d}这种格式化命名保证文件名定长、可排序后期做数据集时按编号就能对应。ext从 URL 里取扩展名取不到就默认.png避免生成没有后缀的文件。整个主流程没有并发是串行下载速度不快但胜在稳定、好排查。想提速可以上线程池但那是进阶操作第一次跑建议先串行确认链路通。4. 避坑与常见问题排查这些坑我替你踩过了爬取类脚本的坑八成不在代码逻辑本身而在网络环境、目标站点策略和文件系统上。下面这几条是我拆同类包时反复遇到的按「现象 → 原因 → 解决」列出来你对照排查能省不少时间。4.1 请求返回 403 或 418现象脚本一跑就报 403 Forbidden或者 418Im a teapot一张图都下不下来。原因目标站点识别出请求不是来自真实浏览器。最常见的是没带User-Agent或者带了但用的是python-requests/2.x这种默认 UA一眼就被认出来。部分站点还会检查Referer、Accept-Language等头。解决把HEADERS补全至少包含User-Agent、Referer设成目标站点首页、Accept-Language。UA 用真实浏览器的字符串别用默认的。如果补全后还是 403说明站点有更严格的校验这时候要么放慢频率要么换图源别硬刚。4.2 下载的图片打不开或只有几 KB现象文件确实生成了但双击打不开或者大小只有 12 KB。原因下载到的不是图片本身而是错误页面或者占位图。常见于链接失效返回 404 页面、或者防盗链返回一张提示图。代码里如果没校验响应类型就会把 HTML 错误页当成图片存下来。解决在download_image里加一层校验检查resp.headers.get(Content-Type)是否以image/开头不是就跳过并记录。另外可以在保存后检查文件大小小于某个阈值比如 1 KB的删掉重试。4.3 文件名乱码或路径报错现象保存时报OSError: [Errno 22] Invalid argument或者文件名变成一堆问号。原因如果命名规则里用了页面上的国家/地区名称而这些名称里可能含有 Windows 不允许的字符\ / : * ? |或者编码不一致导致乱码。解决命名前做一次清洗把非法字符替换成下划线。更稳的做法是干脆不用中文名用编号或拼音命名显示名称单独存一份映射表。路径统一用os.path.join拼接别手写斜杠。4.4 跑到一半卡住不动现象前几十张下得好好的突然卡住既不报错也不继续。原因某个请求没有超时设置或者服务端保持连接不返回脚本一直等。也可能是触发了限流服务端故意拖慢响应。解决确保每个requests.get都带timeout参数。如果已经带了还卡把超时调短到 10 秒并在外层加一个总时长控制。限流的话把DELAY调大或者分批跑跑一批停几分钟。4.5 重复下载与断点续传现象脚本中断后重跑已经下好的图片又下一遍浪费时间还可能触发限流。原因代码没有检查本地是否已存在同名文件每次都是无条件下载。解决在download_image开头加一句判断if os.path.exists(filepath): return True跳过已存在的文件。这样重跑就相当于断点续传只补缺失的部分。注意如果图源更新了这个逻辑会导致旧图不更新按需取舍。5. 进阶技巧把这份源码改成你自己的采集器跑通默认流程只是开始这份源码真正的价值是它提供了一个可改造的骨架。下面几个改造方向是我实际用下来最能提升效率的按投入产出比排序。5.1 用线程池把串行改成并发串行下载一百张图按每张 1 秒算就是一百多秒。改成并发能压到十几秒代价是要控制好并发数别把人家站点打挂from concurrent.futures import ThreadPoolExecutor, as_completed def batch_download(img_urls, save_dir, max_workers5): 并发下载max_workers 控制同时进行的请求数 success 0 with ThreadPoolExecutor(max_workersmax_workers) as executor: futures {} for idx, url in enumerate(img_urls, 1): ext os.path.splitext(url)[1] or .png filename fflag_{idx:03d}{ext} futures[executor.submit(download_image, url, save_dir, filename)] url for future in as_completed(futures): if future.result(): success 1 return successmax_workers是关键参数设 5 是保守值对大多数站点够用又不至于太激进。设成 20、50 的基本等于在告诉对方「我是脚本」很容易被限流甚至封 IP。并发下载时time.sleep的随机延时依然要保留只是它现在发生在各个线程内部整体节奏还是被拉住了。5.2 增加重试机制与失败日志网络请求失败是常态一次失败就放弃太浪费。加个重试把失败记录单独存下来方便事后补def download_with_retry(url, save_dir, filename, retries3): 带重试的下载全部失败后写入失败日志 for attempt in range(1, retries 1): if download_image(url, save_dir, filename): return True print(f 第 {attempt} 次失败重试...) time.sleep(2 * attempt) # 退避等待越往后等越久 with open(failed.log, a, encodingutf-8) as f: f.write(url \n) return False退避等待用2 * attempt第一次失败等 2 秒第二次等 4 秒给服务端喘息时间。失败日志单独存跑完后打开看一眼如果失败集中在某几个链接多半是那几个链接本身失效了不用反复重试。5.3 图片去重与格式统一采集来的图片可能有重复同一张图不同尺寸、不同格式后期做数据集时要去重。简单做法是按文件内容的哈希值判断import hashlib def file_hash(filepath): 计算文件 MD5用于去重 h hashlib.md5() with open(filepath, rb) as f: for chunk in iter(lambda: f.read(8192), b): h.update(chunk) return h.hexdigest() def deduplicate(save_dir): 扫描目录删除内容重复的文件 seen {} removed 0 for name in os.listdir(save_dir): path os.path.join(save_dir, name) if not os.path.isfile(path): continue h file_hash(path) if h in seen: os.remove(path) removed 1 else: seen[h] name print(f去重完成删除 {removed} 个重复文件)格式统一则可以用 Pillow 批量转成 PNG 或 JPG顺便统一尺寸。这一步不是必须的但如果你要把图片喂给模型或者做展示统一格式能省掉后面很多麻烦。5.4 验证采集结果是否完整跑完之后别急着关终端花一分钟验证结果。我一般会做三件事数文件数量对不对得上预期、抽查几张图能不能正常打开、检查有没有 0 字节文件。命令行下可以快速统计# 统计文件数量和总大小 ls -l output/ | wc -l du -sh output/ # 找出小于 1KB 的可疑文件 find output/ -type f -size -1kfind那条命令能揪出下载不完整的文件这些基本就是错误页面或者中断的下载。发现之后对照failed.log补跑就行。从那以后我每次跑完采集脚本都强制走一遍「数量核对 小文件排查 随机抽检」这三步宁可多花两分钟也不想在后期用数据时才发现混进去一堆坏图。希望这份拆解帮到你拿到源码包后先按默认配置跑通再按自己的需求改。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑