1956张Bing壁纸迁移记:一次批量上传Piwigo的踩坑实录

前言

最近帮朋友把一个Bing壁纸仓库(niumoo/bing-wallpaper)的1956张4K壁纸批量导入到Piwigo相册系统里。本以为就是个"写个脚本循环上传"的简单事儿,结果踩了一路的坑,从半夜搞到天亮。记录一下这些坑和解决方法,给后来人参考。

项目概况

  • 图片来源:GitHub上的 niumoo/bing-wallpaper 仓库,收录了2021年至今的每日Bing壁纸
  • 目标系统:Piwigo 16.4.0(Docker运行),modus主题
  • 图片数量:1956张,按年月分类(2021-02 ~ 2026-06,共65个月)
  • 每张大小:4K分辨率(3840x2160),但Bing的JPEG压缩很厉害,平均只有~580KB
  • 总容量:约4.3GB

技术方案

架构

Bing服务器在加拿大的OVH,Piwigo跑在Docker容器里,Nginx反向代理+Cloudflare CDN。上传脚本跑在宿主机上,通过Piwigo的Web Service API(ws.php)进行上传。

初始脚本

第一版Python脚本的逻辑很简单:

  1. 解析每个月的README.md,提取日期和下载链接
  2. 调用 pwg.categories.add 创建年月分类
  3. 下载4K图片
  4. 调用 pwg.images.addSimple 上传并指定分类

看着没啥问题,跑起来才发现坑有多深。

踩坑全记录

坑1:PHP-FPM 进程爆满

跑起来没几分钟脚本就挂了。一看错误日志:

WARNING: [pool www] seems busy, spawning 8 children...

Piwigo容器默认的 pm.max_children = 32,上传请求太多太快,PHP-FPM worker 全部被占满,新的请求只能排队等。某次请求超时后API返回空响应,脚本JSON解析直接崩溃。

解决:增大PHP-FPM进程数,给每个请求留足喘息时间。

  • max_children 32 → 50
  • start_servers 2 → 5
  • 上传间隔从0.5秒加到3秒
  • API调用加重试机制(失败自动重试3次)

坑2:分类重复创建

脚本重启后,发现2023-08出现了两个。排查发现,脚本只在启动时调用一次 pwg.categories.getList 获取已有分类列表。当脚本崩溃重启后,API返回的可能是过期的缓存数据,新分类没出现在返回结果里,于是又创建了一个。

解决:改从MySQL直接查分类表,不走API缓存。

# 糟糕:通过API查
r = api("pwg.categories.getList")
# 靠谱:直接查数据库
r = mysql_query("SELECT id, name FROM piwigo_categories")

坑3:上传成功但分类没关联上

最诡异的坑——API返回 {"stat":"ok","image_id":1234} 说上传成功,但图片的 category_id 是NULL,没归属到任何分类。访问图片页面正常,就是在相册里找不到。

反复测试发现,同样的API参数手动curl上传就没问题,脚本跑就有问题。最后定位到是Cookie过期——长时间运行后会话失效,API虽然返回了成功,但实际没执行完整操作。

解决:上传后直接用SQL补一刀,确保分类关联。

INSERT IGNORE INTO piwigo_image_category(image_id,category_id) VALUES(1234, 56);

坑4:新增相册在Web页面上不显示

上传完2023-09后,左侧菜单栏能看到12个月,但主内容区只显示9个。排查了1个小时,发现三个原因叠加:

原因A:分页限制
Piwigo配置 nb_categories_page = 9,一页只显示9个子分类。超过的就分页到下一页了。

原因B:缺少代表图
Piwigo主视图用 representative_picture_id 显示每个相册的封面缩略图。如果该字段为NULL,该相册就不会在主视图渲染。新增的月份这个字段全是空的。

原因C:缓存过时
Piwigo的 piwigo_user_cache_categories 表缓存了分类数据。快速创建分类后缓存没更新,导致新分类虽然数据库里有,但系统不认——直接跳到用户信息页面。

解决三连

  • nb_categories_page 设成20
  • 上传第一张图时自动设置 representative_picture_id
  • 每次上传后清理对应分类的缓存

坑5:curl下载挂起

并行下载3张图片时,某次对Bing CDN的请求卡住不动了,整个脚本被阻塞。ThreadPoolExecutoras_completed 在等所有线程完成,一个挂起全部等待。

解决:给curl加下载超时。

curl --max-time 20 -sL ...

最终成果

经过一夜的折腾,最终成果:

指标数据
图片总数1,956 张
时间跨度2021-02 ~ 2026-06
占用空间4.3 GB
分类数量65 个月分类 + 6 个年份分类
最终存储/gallery/upload/

最终脚本要点

  1. 3路并行下载 — ThreadPoolExecutor同时下载3张,大幅提速
  2. 单路上传 — 一次只传一张,避免压垮PHP-FPM
  3. SQL直写分类 — 不信任API的分类参数,上传后自己写 image_category
  4. 自动设代表图 — 每个分类第一张图自动设为封面
  5. 自动清缓存 — 上传后删掉 piwigo_user_cache_categories 对应记录
  6. curl超时--max-time 20 防止下载挂死
  7. Cookie自动重登 — 检测到认证失败自动重新登录

总结

这次迁移最大的教训是:不要过度信任API的返回结果。API说成功不代表真的成功了,最好通过数据库验证一下。对于批量操作,适当放慢节奏、加一些冗余校验,反而比一味追求速度更能稳定完成。

另外Piwigo的缓存机制是个暗坑——数据写入数据库后,并不代表前端能立即看到。如果你也遇到"数据有但页面上看不到"的问题,优先检查 piwigo_user_cache* 表。

Last modification:June 10th, 2026 at 01:53 pm
如果觉得我的文章对你有用,请随意赞赏