公众号二维码批量导出与Logo合并:Python自动化完整方案
发布时间:2026/9/26 6:23:49来源:尧图网络
公众号运营久了最磨人的往往不是内容本身而是一堆重复性的图片体力活。就拿公众号二维码来说账号一多每次做活动海报、给门店做指引、整理矩阵宣传物料都需要把每个公众号的二维码挨个导出再把品牌Logo压到二维码中间。人工去后台一张张下载、再用PS一张张处理几十个号就能耗掉大半天还特别容易漏、容易搞混。我最近把这条流程完整自动化了一遍批量导出公众号二维码再按配置表选择性合并Logo全程只剩扫码确认登录和编辑表格两个人工动作这篇就把完整思路和实现细节写清楚给同样被这个需求折腾过的朋友一份可以直接抄的作业。这个方案适合两类人一类是手上管着多个公众号的运营或品牌同学另一类是经常帮客户做公众号物料的设计师或开发。哪怕你没写过几行Python照着代码改改路径也能跑起来如果你本身就有开发基础那这套脚本可以直接沉淀成团队内部工具后面扩展活动海报、带参二维码都很方便。1. 需求拆解为什么非批量不可1.1 这个需求背后真正要解决的问题表面上这就是两句话的事“批量导出公众号二维码”和“选择性合并Logo”但实际接触下来问题远比自己想的复杂。首先是二维码的来源问题。公众号二维码不会自动出现在你电脑里它散落在每个账号的后台需要登录之后进入设置页找到账号详情里的二维码展示区域再手动保存图片。只搞两三个账号还行账号数量一多这种重复操作的时间损耗和心理损耗都很明显。更麻烦的是每次登录切换账号后台页面的加载、二维码图片的定位、下载下来的文件命名每一步都可能出错。然后是整理问题。后台下载的图片默认文件名往往是一串无规律的数字和字符不重新命名根本对应不上具体公众号。真到做物料那天对着几十张二维码找“某某区域门店那个号”心态很容易崩。再往后才是Logo合并的难点。Logo放得太大遮住二维码的信息区域扫不出来放得太小品牌感又不够。如果每个号的Logo还不一样比如连锁体系下不同区域公司共用一个母品牌加不同后缀那手动处理的出错率更高而且出了问题根本说不清是哪一步搞错的。所以“批量导出”和“选择性合并Logo”压根不是两个独立需求它们天然是一整套流水线以“账号清单”为输入以“带Logo标记的成品二维码”为输出中间所有人工重复动作都应该尽量交给脚本来做。1.2 方案选型手动、半自动与全自动怎么选针对这个需求我实际评估过三种做法各有各的适用边界。纯手动就不多说了只适合账号数量在三个以内、且几乎不做物料更新的场景。一旦数量上来手动方案的时间成本会指数级上升而且PS里反复执行“缩小Logo、居中、导出”这种机械操作眼睛和手腕都受不了。半自动方案是我最终采用的用Python脚本把“二维码下载”和“Logo合成”这两个环节自动化但登录动作保留人工扫码确认。这样做有三个实际好处一是兼容所有公众号类型不需要额外权限二是人工扫码本身就是在确认“我有这个账号的操作权限”对账号安全更稳妥三是脚本不需要处理复杂的登录验证逻辑开发和维护成本都低很多。全自动方案在理论上是完整的程序自动跑完登录、下载、合成全流程连扫码都不用。但公众号后台有完整的安全登录机制强行模拟登录不仅实现成本高而且有触发账号风控的风险。对于正规运营场景我强烈不建议在登录环节做成完全无人值守。我自己在做技术选型时有一条原则凡是涉及账号权限的步骤保留人工确认点反而比追求“全自动”更聪明。1.3 项目涉及的技术栈与核心依赖这里把项目会用到的工具列一下方便你提前准备环境工具/库用途安装方式Python 3.8脚本运行环境官网下载安装包Selenium驱动浏览器模拟点击与页面解析pip install seleniumChromeDriverChrome浏览器的自动化驱动下载对应浏览器版本Pillow图像缩放、合成、圆角处理pip install pillowrequests下载二维码图片、调用官方接口pip install requests技术栈整体很轻量依赖包就这几个不需要额外装数据库或消息队列。Pillow负责图像处理这部分核心工作Selenium只承担“找到二维码图片元素并拿到原图地址”这一个任务requests负责把图片二进制流落盘。整个项目没有一个环节是重的后续扩展也方便。2. 批量导出公众号二维码三种途径对比与实操2.1 二维码获取途径与适用性对比要批量导出先得搞清楚二维码从哪来。我整理了三种途径并对比了它们在不同场景下的适用性获取途径清晰度批量难度适用场景公众号后台下载原图清晰度高需逐个登录账号账号数量多、需要印刷级清晰度微信App内保存截图级别分辨率偏低无法批量偶尔应急用一下微信公众平台接口原图可按需生成适合开发者批量调用活动渠道统计、带参二维码微信App内保存的方式我在早期尝试过从公众号主页进入“更多资料”再保存二维码操作步骤繁琐且分辨率只能满足手机查看一旦放进海报印刷出来就会发虚后来直接放弃了。2.2 后台图片定位与Selenium批量下载公众号后台下载二维码是官方原生提供的操作路径也是我最终选择的主力方案。具体路径就是登录公众平台后进入“设置与开发 - 公众号设置 - 账号详情”页面上会有当前账号二维码的大图展示。关键点在于怎么让脚本替我们打开页面、定位到图片并拿到高清原图地址。我用Selenium加Chrome浏览器实现核心代码如下from selenium import webdriver from selenium.webdriver.common.by import By import time, os, requests DOWNLOAD_DIR ./qr_download os.makedirs(DOWNLOAD_DIR, exist_okTrue) driver webdriver.Chrome() driver.maximize_window() driver.get(https://mp.weixin.qq.com/) input(请在浏览器中扫码登录公众号后台登录完成后回到这里按回车继续...) # 进入账号详情页页面路径以实际后台为准 driver.get(https://mp.weixin.qq.com/cgi-bin/settingpage?tsetting/indexactionindex) time.sleep(3) # 定位二维码图片元素 img_el driver.find_element(By.CSS_SELECTOR, .account-qrcode img) img_url img_el.get_attribute(src) if img_url.startswith(//): img_url https: img_url resp requests.get(img_url, headers{User-Agent: Mozilla/5.0}) with open(os.path.join(DOWNLOAD_DIR, 当前公众号二维码.png), wb) as f: f.write(resp.content)有几个细节这里必须单独拎出来讲。第一页面元素选择器会随后台改版而变化我的建议是先在浏览器开发者工具里检查一下二维码img标签实际用的class或id再替换代码里的选择器不要指望选择器永远不变。第二二维码图片的src大概率是相对路径下载前需要手动拼接https:前缀否则requests会直接报错。第三多账号切换时最稳妥的做法是扫码登录一个号下载完立即退出登录再进入下一个号重新扫码避免登录态串号带来的脏数据。有人会问为什么不直接用driver.get_screenshot_as_png()截图保存答案很简单清晰度不够。二维码的使用场景大多是印刷或海报必须是原图级清晰度。浏览器截图会受到页面缩放、浏览器窗体大小的影响放大到A4海报上边缘就会发虚。所以直接定位img标签的src并下载原图是必须的。2.3 开发者接口方式面向带参二维码的补充方案如果你的主体是服务号且开通了开发者权限还可以通过微信公众平台的官方接口生成带参数的二维码这是后台手动下载做不到的。这种方式在“批量生成不同渠道标识的二维码”场景下非常高效。流程先获取access_token再调用二维码生成接口拿到ticket最后通过ticket换取图片。核心代码长这样import requests APPID 你的AppID APPSECRET 你的AppSecret # 1. 获取access_token token_url https://api.weixin.qq.com/cgi-bin/token resp requests.get(token_url, params{ grant_type: client_credential, appid: APPID, secret: APPSECRET }).json() access_token resp[access_token] # 2. 创建临时二维码 scene batch_001 qrcode_url https://api.weixin.qq.com/cgi-bin/qrcode/create data { expire_seconds: 2592000, action_name: QR_SCENE, action_info: {scene: {scene_str: scene}} } qr_resp requests.post( qrcode_url, params{access_token: access_token}, jsondata ).json() ticket qr_resp[ticket] # 3. 通过ticket换取二维码图片 show_url https://mp.weixin.qq.com/cgi-bin/showqrcode img_resp requests.get(show_url, params{ticket: ticket}) with open(f{scene}.png, wb) as f: f.write(img_resp.content)需要注意的是接口方式生成的是带参数二维码它更适用于活动渠道统计而不是“替换公众号账号本身的二维码”。公众号账号本身的二维码最直接的来源还是后台下载。我在实际项目中会把两种方式结合账号自身的二维码走后台下载脚本活动渠道二维码走接口生成两者配合使用基本覆盖了日常所有需求。3. 选择性合并Logo的技术实现3.1 先理解容错机制否则Logo会毁掉整张码在写合成代码之前有一条原理必须搞明白二维码不是直接存图片的它靠特定的几何排布存储数据再由扫码设备解码还原。为了让二维码在破损、污损情况下依然能被识别二维码标准设计了容错等级分为L、M、Q、H四个等级分别能修复约7%、15%、25%、30%的码字。这个机制解释了Logo为什么能放在二维码正中间。二维码的信息分布并不均匀四个角的“回”字形定位图案是解码的关键中心区域相对次要再加上容错机制兜底只要Logo面积占比不超过容错阈值就依然能正常识别。结合我自己的项目经验Logo宽度控制在二维码总宽度的20%到25%之间比较稳。超过30%各种扫码App就会出现间歇性识别失败特别是光线不好的环境下扫半天弹不出来体验非常差。另一个容易被忽略的点是二维码本身的容错等级。如果下载的二维码默认容错等级只有L或M中心区域被Logo盖住后出问题的概率会显著上升。导出的二维码尽量挑选高容错等级版本再合并Logo识别容错空间会更充裕。3.2 用Pillow实现Logo合并的完整代码图像处理这层我用的是Pillow也就是PIL的延续维护版本。它的API足够简单不像OpenCV那样上手就要理解矩阵和颜色空间。Logo合成需要做四件事读取二维码、等比缩放Logo、给Logo做圆角加白色底衬、贴到二维码中心。下面这段是完整可运行的函数from PIL import Image, ImageDraw def merge_logo(qr_path, logo_path, output_path, logo_ratio0.2, corner_radius12): qr Image.open(qr_path).convert(RGBA) qr_w, qr_h qr.size logo_max_size int(min(qr_w, qr_h) * logo_ratio) logo Image.open(logo_path).convert(RGBA) logo.thumbnail((logo_max_size, logo_max_size), Image.Resampling.LANCZOS) # 圆角透明蒙版 mask Image.new(L, logo.size, 0) draw ImageDraw.Draw(mask) draw.rounded_rectangle( [0, 0, logo.size[0], logo.size[1]], radiuscorner_radius, fill255 ) # 白色底衬防止透明PNG贴上去后背景发暗 white_bg Image.new(RGBA, logo.size, (255, 255, 255, 255)) white_bg.paste(logo, (0, 0), mask) # 居中合并 pos ((qr_w - logo.size[0]) // 2, (qr_h - logo.size[1]) // 2) qr.paste(white_bg, pos, mask) qr.save(output_path, PNG) print(f已生成: {output_path})这段代码里最值得展开说明的是“白色底衬”这一步。如果直接拿透明背景的PNG Logo贴到二维码上透明区域在部分查看器或打印场景里会渲染成黑色导致Logo中央暗了一大块观感很差。先垫一张白色圆角底图再贴Logo整体效果就干净利落符合绝大多数品牌物料的白底规范。选择logo_ratio0.2的理由前面已经讲过是“可识别性”和“品牌展示感”之间折中的结果。如果你需要贴的Logo是长条形的公司标识建议等比缩放时以宽度为基准避免高度方向被压得太扁导致细节糊掉。Image.Resampling.LANCZOS是高质量缩放算法比默认的NEAREST好很多尤其从大图缩到小图时边缘更平滑这个细节在印刷场景下能感知到明显差异。3.3 “选择性合并”用配置表控制“选择性”是需求里最容易翻车的点。实际业务场景往往是这样有些账号是主品牌号必须放Logo有些账号是矩阵下的纯功能号不需要放Logo或者需要贴另一个子品牌Logo。如果把规则写成代码里的if else每次需求一变就要改代码维护成本很高。我的做法是用CSV配置表驱动整个合并流程。配置文件命名为merge_config.csv结构长这样公众号,二维码文件,是否合并,Logo文件,输出文件 品牌主号,qr_main.png,是,logo_main.png,output_main.png 区域A号,qr_a.png,是,logo_a.png,output_a.png 工具小号,qr_tool.png,否,,output_tool.png脚本读取这张表逐行判断“是否合并”字段然后走不同分支处理。运营同学后续要调整规则时只需要改表格内容完全不用碰代码。这是整个方案里性价比最高的设计也是这套工具能真正被团队长期用起来的原因。import csv from PIL import Image def batch_merge(config_pathmerge_config.csv): with open(config_path, newline, encodingutf-8-sig) as f: reader csv.DictReader(f) for row in reader: qr_file row[二维码文件] need_merge row[是否合并].strip() 是 output row[输出文件] if need_merge: merge_logo(qr_file, row[Logo文件], output) else: img Image.open(qr_file) img.save(output) print(f未合并直接复制: {output})一个常见坑必须提一下CSV文件用utf-8-sig编码读取是因为Excel另存的UTF-8 CSV会自带BOM头不加sig的话第一列名称会出现一个不可见字符导致“公众号”字段匹配失败。这个坑我第一天就踩了排查半天才发现是编码问题。4. 完整流水线从后台下载到Logo合成一次跑通4.1 目录结构与运行流程设计把两个环节串起来项目的整体目录结构是这样组织的qr_project/ ├── download_qr.py # 批量下载二维码脚本 ├── merge_logo.py # Logo合并函数库 ├── batch_merge.py # 按配置表批量合并 ├── merge_config.csv # 合并规则配置表 ├── qr_download/ # 下载的原始二维码 ├── logo_files/ # 各品牌Logo源文件 └── output/ # 最终成品存放目录运行流程分两步。第一步运行download_qr.py通过扫码登录逐个账号下载二维码到qr_download目录第二步根据实际业务情况编辑merge_config.csv然后运行batch_merge.py脚本按配置表把成品输出到output目录。这个流程保留两次人工干预一次扫码登录一次配置表编辑。这两步都不是为了“偷懒才保留”而是业务决策点本身。登录时的人为确认是账号安全边界配置表则是在确定“具体哪个号合并哪个Logo”这两步恰恰是最不能出错的地方保留人工判断反而比全自动更合理。4.2 文件命名、目录清理与运行校验批量处理中命名规范决定了后续找文件的效率。我建议所有下载的二维码统一命名为公众号全称_qr.png这样即使脱离配置表也能一眼看出图片归属。还有几个细节建议在实际项目里一并处理每次运行前清理output目录中上一次的产物避免新旧文件混淆下载完成后用os.path.exists做一次文件完整性校验避免个别二维码因为网络原因下载为空文件运行结束后生成一份简单的日志文本记录哪些文件成功、哪些失败方便复盘。import os, glob def clean_output(): for f in glob.glob(./output/*.png): os.remove(f) clean_output()这一步相当于给整条流水线加了个保险丝。批量处理一旦跑起来中间任何一个文件异常最终交付时排查成本都会指数级上升提前做校验比事后补救省事太多。5. 常见问题与排查技巧实录5.1 合并Logo后扫码失败怎么办这是这套方案上线后我收到反馈最多的类型。大部分情况下不是代码逻辑的问题而是Logo尺寸或者二维码容错等级的问题。排查顺序建议按下面几步走先检查Logo尺寸比例是否超过25%超过了就直接调低logo_ratio重新生成再检查二维码原图的容错等级如果后台下载的图片默认等级是L或M中心区域被Logo覆盖后容易出问题用微信扫不出来不代表二维码一定坏了建议用多个扫码App交叉测试排除个别扫描器兼容性问题。还有一个容易被忽略的细节Logo如果本身是深色背景且没有做白色底衬贴在二维码上会严重干扰解码。深色Logo一定要用浅色底或白底托底必要时给Logo加一圈3到5像素的白色描边识别稳定性会明显提升。5.2 批量下载时的登录态失效与页面改版问题多账号连续下载时最头疼的是登录态过期。公众号后台的登录态不是永久有效的多个账号切换时容易触发重新登录。我的处理方案是每个账号下载完主动点击后台的退出登录按钮再进入下一个账号。虽然多一次扫码操作但能明显降低风控概率。不要试图用脚本去绕过登录验证账号安全层面人工扫码永远是最稳妥的方式。页面改版是另一个完全躲不开的问题。公众号后台的结构隔一段时间就有微调遇到元素定位失败先按F12检查二维码图片元素的新class或ID替换脚本里的By.CSS_SELECTOR参数就能修复。这也是为什么我建议把选择器单独抽成变量的原因改一处全流程生效不至于到处找硬编码。5.3 中文文件名与CSV编码的系列坑Windows环境下中文路径经常引发各种编码问题Pillow读取中文路径时偶尔也会报解码错误。我的经验是项目内部统一用英文字母命名中间文件和输出文件最终交付运营同学时再考虑改成中文名或者在配置表里维护一条“中文名-英文名”的对照。这倒不是技术上不能解决而是为了少给自己找麻烦。CSV文件在Excel里编辑还容易出两种问题一种就是我前面说的BOM头问题另一种是直接存成GBK编码导致Python抛UnicodeDecodeError。处理方式很直接代码统一用encodingutf-8-sig读取同时和团队说清楚不要用Excel另存成其他编码格式。最后分享一个我自己的体会。刚开始做这套自动化的时候我总想把所有流程全部黑盒化一键点完就交付。但真正跑起来才发现越是涉及账号权限、业务决策的环节越应该保留必要的人工确认点。扫码登录、配置表编辑这些看起来“不够酷”的步骤恰恰是整个流程稳妥运行的关键。项目上线后的第一个月我用这套脚本处理了七十多个公众号的二维码导出和Logo合成需求省下的时间我没精确统计过但至少解放了一个完整的工作日。之后我又在这个框架上扩展了活动海报自动生成、带参二维码批量导出等功能基础框架一旦搭好后续的扩展真的就是加函数的事。如果你也在被这种重复劳动困扰建议先从最小的批量下载脚本开始跑通一个号再逐步放开到全部账号稳扎稳打比一步到位踏实得多。
网站建设高端定制企业官网