make_metadata.py:为每个图库平台生成精确CSV表头

因Adobe Stock表头错误导致240个文件被拒后,作者开发了精确生成各平台CSV表头的脚本。
文章讲述了一次因CSV表头不精确而导致240个文件被图库平台秒拒的教训,并由此引出Python脚本make_metadata.py。该脚本将Adobe Stock、Vecteezy、Dreamstime三个平台的表头硬编码,确保列数与列名逐一匹配解析器要求,并支持通过JSON文件提供真实标题和关键词。作者强调关键词必须与图像实际内容一致,否则会引发更隐蔽的部分拒绝。配套的upload_tracker.py用标准库账本记录上传状态,防止重复发布导致账户被标记。整个流程在1 vCPU、2GB RAM的低资源服务器上运行,脚本设计以简单可靠为原则,避免电子表格带来的格式破坏。
make_metadata.py:为每个图库平台生成精确CSV表头
一次失败的Adobe Stock CSV上传经历,催生了一个专注于CSV表头精确性的Python脚本。作者用240个文件被秒拒的教训告诉我们:在自动化上传流程中,表头错误比内容问题更致命。

表头为什么是关键
每个图库平台的CSV格式各不相同,且互不兼容。Adobe Stock要求5列,Vecteezy要4列,Dreamstime则需要15列。如果你向Dreamstime提交一个5列文件,或给Adobe多加了它不认识的列,上传解析器会直接报错,整批文件全部退回。
作者强调,核对表头时不能只依赖文档,因为文档可能滞后,但上传解析器不会。make_metadata.py将三个平台的表头硬编码在脚本中,没有模板文件可编辑,也没有配置项可误设。运行python make_metadata.py ./my-assets --platform adobe --out metadata.csv --ext .jpg后,第一行写出的就是Adobe所需的5列表头,字符逐一匹配。
CSV(Comma-Separated Values)是一种以纯文本存储表格数据的格式,用分隔符(通常是逗号)划分列,换行划分行。它的“标准”非常宽松:没有强制的引号规则、编码声明或表头校验机制,各平台的解析器往往按自己的实现严格解析。因此同一份CSV在不同平台可能表现完全不同——多余的列、顺序错位、BOM头或CRLF换行都可能触发拒绝。图库平台通常会在上传时先做一次结构校验,列数与列名不匹配即批处理失败,这就是文章强调“表头逐一匹配”的技术根源。
行数据如何填充
表头只是第一步,每一行还需要标题、关键词和分类。默认行为是将文件名转化为标题——比如geometric-fox-pattern-04.jpg会变成"Geometric Fox Pattern 04"。这能通过解析器,但无法赢得搜索排名。
脚本因此支持--titles titles.json参数,允许为每个文件提供真实的标题和关键词。作者的工作流是:先无标题运行脚本生成正确结构,再提交前填写JSON。替换默认标题只需几分钟,而替换被拒批次则要耗费一个下午。
作者特别强调一条自定规则:关键词必须来自实际图像内容,而非提示词。审核人员会检查关键词与可见内容是否匹配,不匹配是导致部分拒绝的隐蔽原因之一,而部分拒绝比全部拒绝更麻烦,因为你可能注意不到哪些文件失败了。
重复上传的陷阱与解决方案
修复表头问题后,作者重新运行了批次,一天后因小修改再次运行,结果造成重复发布。这是导致账户被标记的最快方式,也是所有脚本化上传者容易犯的错误。
upload_tracker.py是一个仅使用标准库的账本工具。上传前检查待处理项目,上传后记录完成状态。由于"done"是按文件、按账本记录,而非依赖记忆,重新运行不会导致重复发布。它和make_metadata.py一样无需安装任何第三方包。整个流程中只有两个脚本需要第三方包:用于封面渲染的Pillow和用于PDF生成的reportlab。
约束条件如何塑造脚本设计
整个流程运行在1 vCPU、2 GB RAM、无GPU的服务器上。作者认为这更多是一种纪律而非限制:一次只运行一个进程,不在单核上并行图像任务;资产之间调用gc.collect();用resource.getrusage测量峰值RSS而非平均值,因为峰值才是导致2GB内存耗尽的原因;按需分辨率渲染,用60 dpi而非300 dpi检查预览,是内存能否容纳的关键。
make_metadata.py因为只做文本处理,轻松适应这些约束。处理240个文件的CSV构建只需几秒,内存占用极低。元数据步骤从不是瓶颈,图像生成才是,因此作者刻意让元数据步骤保持简单可靠。
RSS(Resident Set Size)指进程当前驻留在物理内存中的部分,resource.getrusage 返回的 ru_maxrss 是进程生命周期内的峰值常驻内存,单位在Linux上为KB。相对于平均内存,峰值更能反映OOM(内存不足)风险:一个瞬时峰值就可能触发内核OOM Killer。Python的垃圾回收分为引用计数和分代回收,gc.collect() 强制执行一次完整回收,适合在释放大对象(如高分辨率图像数组)后主动调用,避免峰值叠加;但频繁调用会增加CPU开销,因此在低配环境中要权衡使用。
为什么不用电子表格
作者最初尝试手动CSV路线,但电子表格应用会以可预测的方式失败:静默重新格式化、添加不必要的引号、破坏编码。而直接写文件的脚本每次产生相同的字节。当平台拒绝批次时,可以肯定问题在内容而非工具。
这个脚本是流程工具包四个脚本之一,还包括跟踪器、md2pdf.py和pack_product.py。它们共同打包了39个产品、约856 MB输出,总计约19,000行流程代码,背后有300多页研究支撑,全部在同一台1 vCPU/2GB RAM机器上验证。
对于需要打包图库艺术或模板的创作者,如果CSV步骤正在消耗你的时间,make_metadata.py提供了一种简单可靠的自动化方式,避免重复作者曾犯过的错误。
相关推荐

LLM应用越改越糟?三步构建有效评估体系
LLM应用迭代时如何判断变好还是变坏?本文基于Reddit开发者讨论,详解构建测试集、自动化回归评估、LLM-as-judge评分与结构化追踪智能体行为,建立从生产反馈到评估追踪的持续闭环。

瑞典政府封杀ChatGPT与Claude:AI工具治理的转折点
瑞典政府宣布禁止在员工电脑上使用ChatGPT和Claude,出于信息安全考虑。本文分析禁令细节、数据主权焦虑及对AI行业的影响。

苹果复活初代iPod:Apple Music隐藏彩蛋深度体验
苹果在Apple Music的404页面埋藏了初代iPod虚拟彩蛋,预置2000年代早期歌曲,引发社交传播。本文解析彩蛋位置、发现过程与怀旧营销背后的产品逻辑。