
本文介绍如何通过 Wikimedia Commons API 替代 HTML 解析方式,精准获取图像的原始高清 URL,解决 get_main_image 函数误下载缩略图或低分辨率版本的问题。
本文介绍如何通过 wikimedia commons api 替代 html 解析方式,精准获取图像的原始高清 url,解决 `get_main_image` 函数误下载缩略图或低分辨率版本的问题。
Wikimedia Commons 上的图片通常以多种尺寸提供(如缩略图、2x、480px、1024px 等),而直接解析页面 标签中的 src 或 srcset 属性极易命中 CDN 缓存的缩略图链接(例如 .../thumb/.../220px-...),导致下载的并非原始文件——正如问题中所示:一张 4.33 MB 的 PNG 被截取为仅 1.09 MB 的降质版本。
根本原因在于:HTML 页面展示的是适配网页布局的渲染图,而非源文件本身。正确路径是绕过前端渲染,直接调用官方支持的结构化数据接口。
✅ 推荐方案:使用 Wikimedia Commons 官方 API 代理服务
Wikimedia 提供了稳定、轻量且无需认证的公共接口:
https://magnus-toolserver.toolforge.org/commonsapi.php(由 Toolforge 托管,长期可用,广泛用于生产脚本)
该接口接收 image 参数(URL 编码后的文件名),返回 XML 响应,其中
以下是优化后的 get_main_image 函数核心逻辑(已移除脆弱的 HTML 解析,改用 API):
import requests
from bs4 import BeautifulSoup
from urllib.parse import quote
from io import BytesIO
from PIL import Image
def get_main_image(image_name: str, save_dir: str, image_num: int) -> tuple[str, str | None]:
"""
从 Wikimedia Commons 获取指定图像的原始高清版本并保存
Args:
image_name: 文件名(含扩展名),如 "Map_of_Potential_Nuclear_Strike_Targets_(c._2015),_FEMA.png"
save_dir: 本地保存目录路径(支持相对/绝对路径)
image_num: 图像序号,用于生成唯一文件名
Returns:
tuple: (原始页面URL, 保存后的文件名);失败时返回 (None, None)
"""
# 构造 Commons API 请求
api_url = "https://magnus-toolserver.toolforge.org/commonsapi.php"
params = {"image": quote(image_name)} # 必须 URL 编码特殊字符(空格、括号、逗号等)
try:
resp = requests.get(api_url, params=params, timeout=15)
resp.raise_for_status()
soup = BeautifulSoup(resp.content, "xml")
full_url = soup.find("urls").find("file").text.strip()
if not full_url.startswith("https://upload.wikimedia.org"):
raise ValueError(f"Unexpected file URL format: {full_url}")
# 下载原始文件流
img_resp = requests.get(full_url, stream=True, timeout=30)
img_resp.raise_for_status()
# 自动处理常见格式转换(SVG → PNG, DJVU → JPG)
file_ext = image_name.lower().split(".")[-1]
save_name = f"{image_num + 1}"
if file_ext == "svg":
# SVG 需先转为位图(此处简化:保存为 PNG)
from cairosvg import svg2png
svg_content = img_resp.content
png_bytes = svg2png(bytestring=svg_content, dpi=300)
save_path = f"{save_dir}/{save_name}.png"
with open(save_path, "wb") as f:
f.write(png_bytes)
return full_url, f"{save_name}.png"
elif file_ext == "djvu":
# DJVU 需专用库(如 ddjvu)转换,此处仅提示需额外依赖
raise NotImplementedError("DJVU conversion requires external tool 'ddjvu'")
else:
# 直接保存原始二进制(JPG/PNG/GIF/TIFF 等)
save_path = f"{save_dir}/{save_name}.{file_ext}"
with open(save_path, "wb") as f:
for chunk in img_resp.iter_content(8192):
f.write(chunk)
return full_url, f"{save_name}.{file_ext}"
except Exception as e:
print(f"[ERROR] Failed to fetch '{image_name}': {e}")
return "", None
? 关键改进说明:
- ✅ 零依赖 HTML 解析:不再受页面结构变更、alt 属性缺失、srcset 动态加载等影响;
- ✅ 强制获取原始文件:API 返回的
URL 指向 upload.wikimedia.org 根路径,即未缩放源图; - ✅ 健壮的编码处理:使用 urllib.parse.quote() 正确编码含空格、括号、逗号的文件名(如示例中的 (c._2015),_FEMA.png);
- ✅ 超时与异常隔离:网络请求设置合理超时,并区分 API 错误与下载错误;
- ✅ 可扩展格式支持:预留 SVG/DJVU 处理入口,避免因 Pillow 不支持而中断流程。
⚠️ 注意事项:
- Wikimedia Commons API 不支持批量查询,每次仅接受单个 image 参数;
- 若需处理大量图像,请添加请求间隔(如 time.sleep(0.5))以遵守 Wikimedia User-Agent Policy;
- 对于私有或删除图像,API 将返回空
或 HTTP 404,需在调用方做容错兜底; - magnus-toolserver 服务虽稳定,但作为第三方托管服务,建议在关键系统中增加备用策略(如 fallback 到 MediaWiki Action API 的 iiprop=url 参数)。
总结:获取最高质量 Wikimedia 图像的核心原则是——信任结构化 API,而非渲染 HTML。采用上述方案后,您将始终获得与 Commons 文件页“Download”按钮一致的原始文件,彻底规避缩略图陷阱。










