1. 项目概述与需求拆解
我做广告投放优化这些年,每天最烦的事不是调计划,而是拉数据。早上到公司第一件事,登录千川后台,按计划、按地域、按时段一个一个筛,再导Excel,再手工做透视表。等我把昨天一整天的数据整理清楚,两个小时过去了,账户里的预算都已经烧出一个不小的数字了。
后来我开始接触巨量千川M-API,这是巨量引擎开放平台提供的营销API接口,中文全称叫Marketing API,业内一般直接叫M-API。它能做到的事情非常简单粗暴:通过HTTP请求,直接把账户里的广告计划、广告组、广告创意、报表数据全部拉出来,结构化返回JSON,配合Python做后续处理,就能把整个“早上的数据整理工作”压缩成一段脚本+一个定时任务。这也是我这篇文章想聊的核心:用Python调巨量千川M-API,实现短视频推广计划数据的自动获取。
这篇文章适合谁看?两类人:一类是像我一样做优化投放、每天被报表折磨的人,想从重复劳动里解放出来;另一类是做广告技术开发的工程师,手里可能有客户想对接千川数据,需要一个能直接跑的参考实现。我会把从申请权限、创建应用、写签名、调接口、存数据到挂定时任务的全过程都梳理一遍,代码直接给到,细节尽量讲透。
先放一个核心逻辑图帮大家理解整个流程:本地Python脚本通过HTTP请求调用M-API接口,M-API返回广告计划数据(JSON格式),Python解析后存入本地数据库或Excel,再由系统的定时任务每天自动执行。这个过程本质就是一个“自动化报表机器人”,而M-API就是连接机器人和千川后台的数据管道。
1.1 M-API能解决什么实际问题
先说说M-API到底能干什么,这个搞清楚了,你才知道自己的需求该往哪个方向拆。巨量千川M-API覆盖的能力很多,包括账户管理、广告计划管理、数据报表、财务管理、素材管理、受众管理等等。对于绝大多数优化师来说,最常用的是两类:
第一类是报表数据接口,用来拉消耗、展现、点击、转化等核心指标,按计划维度、按时间维度、按地域维度等等都能拆。第二类是计划管理接口,用来做计划的批量创建、修改、暂停、开启。我的文章主要讲第一类,也就是数据获取,因为这是需求最刚性、收益最直接的场景。
实际上,M-API还有一个很实用的应用场景:打通内部数据系统。比如公司内部有自建的数据看板,以前数据都是人工从后台导出来再填进去,现在可以让Python脚本定时拉取M-API数据,直接写入公司数据库,看板就实时更新了。再比如做跨账户数据汇总,手上管着几十个千川账户,靠人力去后台一个一个导出数据根本不现实,用M-API批量拉取就是最合理的方案。
1.2 为什么选择Python来做这件事
选Python的原因其实很直白。第一,Python处理JSON和HTTP请求太方便了,requests库一行代码就能发一个GET请求,json库处理返回数据也是零成本。第二,Python生态里有pandas,拿到数据之后做透视、清洗、合并、导出Excel,都是几行代码的事,这对有数据分析需求的运营来说非常友好。第三,后面挂定时任务的时候,Python脚本可以被Windows任务计划程序或Linux crontab直接调度,部署成本很低。
当然,用Java、Go也能做,但如果你不是专职的后端开发,Python绝对是最省事的选择。我自己最初接触M-API的时候用的是Postman先调试接口,确认通了之后再用Python写脚本,这个流程我建议新手也照抄,能减少很多调试上的痛苦。
2. 环境准备与前置工作
在开始写代码之前,有几件事必须先做好。很多人上来就埋头写Python,结果到了调用接口那一步发现没有token、没有权限,全白干。这一节我把环境准备和开发前的所有准备工作一次讲清楚,你照着准备就行。
2.1 Python环境搭建
如果电脑上还没有Python,先去官网下载安装包,装的时候记得勾选“Add Python to PATH”这个选项。不勾选的话,后续在命令行里敲python会提示找不到命令,这是新手最容易踩的坑。装完之后打开命令行,输入python --version确认安装成功。
接下来需要安装几个第三方库。打开命令行,依次执行下面的命令:
pip install requests pandas openpyxlrequests用于发送HTTP请求,pandas用于数据处理,openpyxl用于把数据写入Excel文件。顺手把这三个都装上,后面写代码的时候就不用一次一次补了。
对于Python环境配置这块,我多说一句。很多初学者喜欢用Anaconda,觉得它全家桶方便。但如果你只是为了跑千川M-API这个脚本,其实没必要装Anaconda,原生Python加pip就够用了,而且环境更干净、启动更快。
2.2 巨量千川开放平台账号申请与权限开通
这一步是整个项目里最关键、也最容易卡住的一步。首先要有一个巨量引擎的账号,然后登录巨量千川开放平台,在平台上创建自己的应用,拿到唯一的App ID和Secret。
创建应用的时候需要注意:接入平台选择“巨量千川”,应用类型按照实际需求选择,一般选“自研应用”就可以了。提交之后等平台审核,审核时间一般是一到两个工作日。审核通过之后,在应用详情页就能看到App ID和Secret。
拿到这俩东西之后,还需要做两件事。第一件事是在“开发配置”里把回调域名或者服务器IP加入白名单,因为M-API在调用的时候会校验请求来源。第二件事是在“权限管理”里给应用申请数据报表相关的API权限,我当时申请的是“巨量千川-报表数据”这个权限。权限审核也有一个周期,建议提前申请,别等代码写完了才发现权限没开。
注意:App Secret是敏感信息,相当于你应用的钥匙,千万不要硬编码在代码里然后传到公开的代码仓库。我见过有人把Secret直接贴在GitHub上,结果被灰产扫到,账户被拿去刷API,第二天账户消耗异常,那个教训非常惨痛。
2.3 获取access_token
M-API的接口调用采用OAuth 2.0认证机制,也就是说,你需要先拿App ID和Secret去换一个access_token,然后请求具体接口的时候在Header里带上这个token。
获取access_token的接口地址是:
https://ad.oceanengine.com/open_api/oauth2/access_token/请求方式是POST,请求体里带三个字段:app_id、secret、grant_type。grant_type固定填“auth_code”。这里有个需要提前说明的地方:千川M-API有两种授权模式,一种是账号密码授权模式,一种是授权码模式。
账号密码授权模式适用于你自己的账户,可以直接用账号密码换token;授权码模式适用于第三方服务商,需要用户跳转到授权页面授权之后拿授权码。自己做数据获取的话,用账号密码授权模式就够了。不过这里我也提醒一下,账号密码授权模式在部分新规下可能受限,如果你在调用时遇到提示不支持,那就需要改用授权码模式,这个在开放平台文档里都有详细的接入说明。
3. 核心代码实现:从Token到报表数据
环境准备到位之后,终于可以进入正题了。这一节我会从获取access_token开始,一步一步把整个代码写出来。我尽量把每一段代码的用途和关键参数都讲清楚,这样你拿到手不光是能用,还能自己改。
3.1 获取access_token的代码实现
先写一个通用的函数,用来获取access_token。这段代码我用的是账号密码授权模式,如果你的应用不支持这种模式,就需要改成授权码流程,但后面的逻辑完全一样。
import requests import json import time APP_ID = "你的App ID" SECRET = "你的App Secret" def get_access_token(account_id, password): url = "https://ad.oceanengine.com/open_api/oauth2/access_token/" payload = { "app_id": APP_ID, "secret": SECRET, "grant_type": "auth_code", "auth_code": "", "account_id": account_id, "password": password } headers = {"Content-Type": "application/json"} resp = requests.post(url, json=payload, headers=headers) result = resp.json() if result.get("code") == 0: return result["data"]["access_token"] else: raise Exception(f"获取token失败: {result}")简单解释一下这段代码。requests.post就是向千川服务器发送一个POST请求,json参数会自动把Python字典转成JSON字符串。返回结果是一个标准结构,code字段为0表示成功,data.access_token就是我们要的令牌。
access_token的有效期一般是一天,但为了保险起见,建议在脚本里加上一个token缓存机制。最简单的做法是把token存到一个本地文件里,过期了再重新获取,不过大多数定时任务场景下,每天跑一次,每次重新获取token也不会有什么性能压力。
3.2 核心接口:获取广告计划列表
拿到token之后,就可以开始调真正的数据接口了。我以“获取广告计划列表”为例,因为它是最常用、也最能体现M-API价值的接口。
接口地址是:
https://ad.oceanengine.com/open_api/v1.0/qianchuan/report/ad/get/请求方式是GET,需要在Header里带Access-Token,同时还需要一堆query参数。常见的参数有:advertiser_id(广告主ID)、start_date(开始日期)、end_date(结束日期)、filtering(过滤条件)、page(页码)、page_size(每页条数)等等。
其中filtering是一个JSON字符串,可以按条件过滤计划。比如我想只看“投放中”的计划,可以用Status字段;想看特定计划ID,可以用IDs字段。这个参数非常灵活,建议好好看官方文档。
下面是一个完整的获取计划报表数据的示例代码:
import requests import json def get_ad_reports(access_token, advertiser_id, start_date, end_date, page=1, page_size=100): url = "https://ad.oceanengine.com/open_api/v1.0/qianchuan/report/ad/get/" params = { "advertiser_id": advertiser_id, "start_date": start_date, "end_date": end_date, "filtering": json.dumps({ "Status": "AD_DELIVERY_OK" }), "page": page, "page_size": page_size } headers = { "Access-Token": access_token } resp = requests.get(url, params=params, headers=headers) result = resp.json() if result.get("code") == 0: return result["data"] else: raise Exception(f"获取报表失败: {result}")注意filtering参数这里用了json.dumps,把Python字典转成JSON字符串。这是M-API的一个常见陷阱,很多人直接把字典传进去,结果提示参数格式错误。
关于分页逻辑,这里要特别说明一下。M-API的列表接口默认page_size上限是100,如果数据量超过100条,就得分页拉取。比较稳妥的办法是把所有页的数据循环拉完再合并。
3.3 分页获取与“全量拉取”的处理
实际投放中,计划数量超过100是很常见的事。所以一个健壮的数据拉取脚本,必须处理分页。下面是一个递归拉取所有页数据的封装:
def get_all_reports(access_token, advertiser_id, start_date, end_date): all_data = [] page = 1 while True: data = get_ad_reports( access_token, advertiser_id, start_date, end_date, page=page, page_size=100 ) page_data = data.get("list", []) all_data.extend(page_data) total = data.get("page_info", {}).get("total_number", 0) if len(all_data) >= total: break page += 1 time.sleep(0.5) # 注意频率控制,别把接口打挂了 return all_data这里加入了一个time.sleep(0.5),主要是为了控制请求频率。千川M-API有QPS限制,正常来说每秒几次请求问题不大,但如果你的脚本并发太高,就会触发限流或者封禁。做数据拉取的时候,宁慢勿快是基本原则。
3.4 数据整理与本地落盘
数据拿到之后是JSON格式,直接看不太直观,也不方便后续做分析。我的习惯是用pandas把数据转成表格形式,然后存成Excel文件,这样即使是非技术人员也能直接打开看。
下面这段代码会把获取到的计划数据转成DataFrame,然后保存到本地Excel:
import pandas as pd def save_reports_to_excel(all_data, file_name="千川计划数据.xlsx"): if not all_data: print("没有数据,不生成文件") return df = pd.DataFrame(all_data) df.to_excel(file_name, index=False) print(f"数据已保存到: {file_name}, 共 {len(df)} 条记录") # 调用示例 token = get_access_token("你的账号", "你的密码") reports = get_all_reports(token, "你的广告主ID", "2024-01-01", "2024-01-07") save_reports_to_excel(reports)这里需要提醒一点:M-API返回的数据字段一般是英文标识符,比如stat_cost表示消耗、show_cnt表示展现、click_cnt表示点击、convert_cnt表示转化。如果你需要中文表头,可以用pandas的rename方法手动映射一下字段名。
常见字段和中文含义对照表我整理了一下,方便大家直接参考:
| 字段名 | 中文含义 | 类型说明 |
|---|---|---|
| ad_id | 计划ID | 数值型 |
| ad_name | 计划名称 | 字符串 |
| stat_cost | 消耗金额 | 浮点型(元) |
| show_cnt | 展现次数 | 整数型 |
| click_cnt | 点击次数 | 整数型 |
| convert_cnt | 转化次数 | 整数型 |
| conversion_cost | 转化成本 | 浮点型(元) |
| ctr | 点击率 | 字符串(百分比) |
| cvr | 转化率 | 字符串(百分比) |
有了这个映射表,你就能知道接口返回的每个字段到底对应什么指标了。不过不同接口版本返回的字段会略有差异,用的时候还是以官方文档为准。
4. 定时任务配置与全流程自动化
脚本能跑通只完成了50%的工作,真正麻烦的事情是让它每天自动跑。毕竟我们做自动化的目的就是不想每天手动打开终端敲python命令。这一节我讲一下Windows和Linux两种环境下怎么挂定时任务。
4.1 Windows任务计划程序配置
如果你用的是Windows电脑,自带的“任务计划程序”就能满足需求。打开任务计划程序,点击“创建基本任务”,按向导设置:
- 名称填“千川数据自动拉取”,触发器选择“每天”,时间和你要拉的数据周期匹配,比如早上8点。
- 操作选择“启动程序”,程序或脚本填你Python解释器的路径,比如C:\Users\Administrator\AppData\Local\Programs\Python\Python310\python.exe。
- 添加参数填脚本的完整路径,比如D:\scripts\qianchuan_report.py。
这里有一个坑要提醒大家:如果你在命令行里敲python能运行,但在任务计划程序里设置同样的命令却报错,大概率是因为任务计划程序用的Python路径和命令行里不一样。解决办法是直接填Python解释器的完整路径,不要只填python。
还有一个细节是工作目录的问题。如果你的脚本里用了相对路径(比如"千川计划数据.xlsx"),建议在“起始于”一栏里填上脚本所在目录,否则生成的文件会跑到System32目录下面,让你找半天找不到。
4.2 Linux下的crontab配置
如果是部署在Linux服务器上,那就要用crontab了。先打开crontab编辑器:
crontab -e然后加上这么一行:
0 8 * * * /usr/bin/python3 /opt/scripts/qianchuan_report.py >> /opt/scripts/logs/qianchuan.log 2>&1这行的意思是每天8点执行一次脚本,并且把输出和错误日志都追加到日志文件里。这个日志习惯非常好,排查问题的时候你就知道有多重要了。我第一次部署的时候没写日志,结果某个周一脚本报错了三天我才发现。
如果是多账户拉取,只需要在脚本里加一个循环,遍历所有广告主ID,依次拉取数据。实测下来,一个账户拉一次报表数据大概是2到5秒,20个账户也就一两分钟的事,早上8点跑,完全不耽误上班用。
4.3 数据自动发送到飞书/企微
Excel文件生成之后,如果还差一个“推送到手机”的环节,这个自动化就不算完整。我个人最常用的做法是把Excel结果通过飞书机器人或者企业微信机器人推送到群聊里,每天早上打开手机就能看到前一天的数据摘要。
实现方式也很简单,就是给webhook地址发一个POST请求。飞书机器人的消息格式是这样:
import requests def send_feishu_message(webhook_url, text): payload = { "msg_type": "text", "content": {"text": text} } requests.post(webhook_url, json=payload)你可以在脚本里先把数据统计好,比如“昨日消耗XXXX元,GMV XXX元,ROI XXX”,然后整合成一段文本,通过飞书机器人推送到群聊。这样一来,整个流程就真的全自动了:数据自动拉取、自动分析、自动推送,人只需要在手机上看结果就行。
5. 常见问题与排查技巧实录
这个项目我踩过的坑不少,有些是看了好几天官方文档才搞明白的。帮大家整理一份避坑清单,按问题出现的频率排序,你遇到问题的时候可以直接对照排查。
5.1 常见错误码与解决方案速查表
| 错误码 | 错误信息 | 原因与解决方案 |
|---|---|---|
| 40001 | Invalid Token | access_token过期或无效,重新获取token即可 |
| 40002 | Token Expired | token已过期,参考上文重新获取 |
| 40003 | Invalid Signature | 请求签名错误,检查签名参数和拼接规则 |
| 40100 | Permission Denied | 应用没有对应接口权限,去开放平台申请 |
| 40301 | Advertiser Not Exist | 广告主ID填错了,或者账号没有该广告主权限 |
| 50000 | System Error | 服务端异常,稍后重试或联系平台技术支持 |
5.2 高频问题排查三板斧
先说第一个高频问题:签名错误。M-API的很多接口要求请求签名(sign),尤其是涉及账号敏感操作的接口。签名的生成规则在官方文档里写得很清楚,一般是把请求参数按字典序排列,拼接成字符串后加上salt做MD5加密。这个规则说起来简单,做起来很容易出错,我建议你在本地写一个单独的测试脚本,用一个已知参数组合去验证签名结果,确认无误后再接入主流程。
第二个高频问题是filtering参数格式不对。这个我在前面提过,filtering必须是JSON字符串,不能是Python对象。我见过太多人在论坛上问“为什么过滤条件没生效”,绝大多数都是因为没做json.dumps。
第三个高频问题是时区问题。M-API的报表数据默认按照广告主所在的时区来统计,如果你想按自己的时区拉数据,需要手动处理时间偏移。这个小细节如果不注意,很容易出现“今天拉的数据对不上”的情况。
重要提示:调用M-API时一定要控制频率。每个接口都有QPS限制,正常情况下每秒1-2次请求是安全的。如果只是拉报表数据,完全没必要并发,老老实实一条一条拉就行。我见过有人图快用多线程拉数据,结果整个账号的API权限被停了一天,严重影响业务,得不偿失。
5.3 关于数据一致性的一点思考
最后分享一个我在实际使用中的体会。M-API拉出来的数据和千川后台看到的数据,在某些情况下可能会有细微的差异,尤其是当天实时数据。这是因为后台报表和API接口的数据计算口径存在微小的时效性差异,一般在T+1之后会完全对齐。
所以我的建议是:当天的数据仅供参考,做决策尽量用前一天的数据。如果你的业务对数据准确性要求极高,可以在脚本里强制等到第二天凌晨再拉前一天的数据,这样拿到的一定是最终数据。
另外,如果你管着多个账户,我建议拉数据的时候统一用同一个时间基准。我之前就踩过这个坑,早上8点拉A账户的数据,中午12点拉B账户的数据,结果两张表的数据口径不一致,做汇总分析的时候对不上账。后来我把所有账户统一在每天早上8点拉取,这个问题就彻底解决了。
6. 玩法扩展:从一个脚本到一套数据中台
脚本跑通、定时任务挂好之后,这个项目其实还能往外延伸很多。我把自己做过的几个扩展方向列出来,给大家做个参考。
数据落地这一步,我没用Excel,而是写了一个简单的MySQL表结构,把每天的报表数据直接写入数据库。有了数据库之后,后续的事情就好办了:你可以用Metabase或者Superset这种开源工具直接做可视化看板,也可以给运营同学开一个查询入口。Excel文件作为备份当然可以,但它处理不了历史数据累积的问题——当你的数据量到几十万条的时候,Excel打开都费劲,更别说做分析了。
6.1 多账户汇总与统一报表
如果你手上管着多个千川账户,一键汇总的需求肯定绕不开。在脚本里加一个账户列表,循环拉取每个账户的数据,最后统一合并。需要注意的是,不同账户的广告主ID不同,拉数据的时候要用各自的权限去请求。如果你是服务商角色,需要先通过授权拿到客户的广告主访问权限。
汇总数据的时候,我建议保留一个advertiser_id字段,这样后续做跨账户分析或者细分筛选都很方便。用pandas做汇总的时候,groupby一下消耗、展现、点击这些指标,就能得到账户维度的整体报表。我这边曾经同时管着30多个账户,以前每月月初汇总报表要花一整个下午,现在一条命令30秒搞定,这就是自动化的价值。
6.2 异常消耗预警推送
数据自动化之后,还能顺手做一个预警功能。比如昨天消耗超过一定阈值,或者ROI跌破预警线,就让飞书机器人自动推送一条告警消息到群里。这个逻辑写起来不复杂,就是在拉取数据之后加一个判断,触发条件就调用webhook推送。
我自己的实现是:每天上午9点先拉前一天数据,计算账户整体ROI,如果低于设定阈值,飞书机器人就会在群里@我,提醒赶紧排查计划。这个功能上线之后,至少帮我避免了两次大额消耗事故,投入产出比极高。
6.3 对接内部投放管理系统
如果你所在的公司有内部的投放管理系统,M-API还可以作为一个数据采集层,将千川数据接入到这个系统里。比如有一个内部平台是给管理层看投放日报的,以前是运营手工整理Excel再发邮件,现在可以让Python脚本拉取M-API数据后直接写入内部系统的数据库,管理层打开系统就能看到最新数据。
这个方案的核心逻辑是解耦:M-API负责对接千川,内部系统负责展示,Python脚本只做中间的搬运工。这样做的好处是,即便千川的接口升级换代,也只需要改Python脚本,不影响内部系统的稳定性。
我个人在实际操作中的体会是,M-API能做的事情远比官方文档里写得要丰富。文档只是给了你一堆接口,但怎么组合使用、怎么跟业务深度绑定,这些都需要自己去摸索。我先跑通了数据拉取这个最基础、最刚需的场景,后面自然就能举一反三,覆盖到更多业务需求。
还有一个小技巧分享给大家:脚本写完之后,建议在代码里加一个完整的注释头,写明接口文档的版本、请求时间、依赖库版本等信息。因为千川API更新频率不低,过几个月回来看代码,如果没有注释,你会发现根本想不起来当时用的什么参数结构。这个习惯成本极低,但后患无穷少。