钉钉审批附件无法直接用requests下载,必须通过官方SDK调用OapiProcessinstanceGetRequest获取含签名的download_url,该地址已内置短期有效鉴权,可直连下载。

钉钉审批文件无法直接用 requests 下载,因为需要登录态和接口鉴权
钉钉开放平台不提供「导出审批附件」的公开 API,所有审批相关操作(包括获取附件 URL)都依赖 dingtalk.api 或官方 SDK 的内部鉴权流程。你看到的审批详情页里那些 PDF/Excel 链接,点开会跳转到带临时 token 的地址(如 https://oapi.dingtalk.com/...?access_token=xxx&expires=120),这个 token 有效期极短,且绑定设备、IP 和 session,不能简单复用。
常见错误现象:403 Forbidden 或 400 Invalid access token;用浏览器开发者工具复制下来的链接,在脚本里 requests.get() 直接请求会失败。
- 必须通过钉钉官方 Python SDK(
dingtalk-sdk)调用OapiProcessinstanceGetRequest获取审批实例详情 - 从返回的
form_component_values中解析出附件字段(类型为file),再提取download_url字段(注意:不是原始 URL,是 SDK 解析后提供的可直下地址) - 该
download_url已内置短期有效签名,无需额外加 header 或 token
用 dingtalk-sdk 获取审批实例并提取附件下载地址
前提是你已申请企业自建应用,拿到 AppKey、AppSecret,并有对应审批模板的权限。SDK 不支持直接按群 ID 查审批,得先知道审批实例 ID(process_instance_id)——通常来自审批回调、或管理员后台导出的 CSV 记录。
示例逻辑:
立即学习“Python免费学习笔记(深入)”;
from dingtalk.api import OapiProcessinstanceGetRequest
from top.api import DefaultTopClient
<p>client = DefaultTopClient(
server_url="<a href="https://www.php.cn/link/ac281a4f6613b8639870ae23016bbaeb">https://www.php.cn/link/ac281a4f6613b8639870ae23016bbaeb</a>",
appkey="your_appkey",
appsecret="your_appsecret"
)</p><p>req = OapiProcessinstanceGetRequest()
req.process_instance_id = "PROC-xxxxxx" # 必须真实存在且你有权限
resp = req.getResponse(client)</p><h1>检查 resp.get("body") 是否含 form_component_values</h1><p>for field in resp.get("body", {}).get("form_component_values", []):
if field.get("name") == "附件" and field.get("value"):
files = field["value"] # 是 list,每个元素含 name + download_url
for f in files:
print(f["name"], f["download_url"]) # 这个 download_url 可直接 requests.get</p>下载时要注意 Content-Disposition 和文件名编码
钉钉返回的附件响应头中,Content-Disposition 常含中文文件名,比如 attachment; filename*=UTF-8''%E9%99%84%E4%BB%B6.pdf。Python requests 默认不解析该字段,容易保存成 download.pdf 这类无意义名字。
- 用
response.headers.get("Content-Disposition")提取原始值 - 借助
email.utils解码filename*字段:email.utils.collapse_rfc2231_value() - 若解析失败(比如字段是
filename="abc.pdf"格式),回退用正则提取双引号内内容 - Windows 下注意路径非法字符(
/ : * ? " < > |),建议用re.sub(r'[\/*?:"<>|]', "_", filename)清洗
没有 process_instance_id 怎么办?只能靠人工或日志补全
钉钉不提供「按时间范围批量查审批实例」的开放接口(OapiProcessinstanceListids 最多只返回 ID 列表,且需指定发起人、流程 ID、时间范围三者,权限要求高)。如果你没开启审批回调,又没存历史 ID,脚本就卡在第一步。
可行但受限的补救方式:
- 让管理员在钉钉管理后台 → 工作台 → 审批 → 导出近 30 天记录(CSV),从中提取
process_instance_id字段 - 若使用了审批回调(
https://your-domain.com/callback),确保服务端已持久化收到的process_instance_id -
OapiProcessinstanceListids接口可试,但必须传process_definition_id(审批模板 ID),且调用方需是该模板的管理员
绕过 ID 直接“爬群消息”不可行:钉钉 PC 客户端协议未开放,网页版无审批附件的 DOM 节点暴露,自动化点击也不稳定——这不是技术瓶颈,是平台设计上就不允许。



















