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_tokenM-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, jsonpayload, headersheaders) 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, page1, page_size100): 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, paramsparams, headersheaders) 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, pagepage, page_size100 ) 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然后保存到本地Excelimport 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, indexFalse) 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 21这行的意思是每天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, jsonpayload)你可以在脚本里先把数据统计好比如“昨日消耗XXXX元GMV XXX元ROI XXX”然后整合成一段文本通过飞书机器人推送到群聊。这样一来整个流程就真的全自动了数据自动拉取、自动分析、自动推送人只需要在手机上看结果就行。5. 常见问题与排查技巧实录这个项目我踩过的坑不少有些是看了好几天官方文档才搞明白的。帮大家整理一份避坑清单按问题出现的频率排序你遇到问题的时候可以直接对照排查。5.1 常见错误码与解决方案速查表错误码错误信息原因与解决方案40001Invalid Tokenaccess_token过期或无效重新获取token即可40002Token Expiredtoken已过期参考上文重新获取40003Invalid Signature请求签名错误检查签名参数和拼接规则40100Permission Denied应用没有对应接口权限去开放平台申请40301Advertiser Not Exist广告主ID填错了或者账号没有该广告主权限50000System 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接口的数据计算口径存在微小的时效性差异一般在T1之后会完全对齐。所以我的建议是当天的数据仅供参考做决策尽量用前一天的数据。如果你的业务对数据准确性要求极高可以在脚本里强制等到第二天凌晨再拉前一天的数据这样拿到的一定是最终数据。另外如果你管着多个账户我建议拉数据的时候统一用同一个时间基准。我之前就踩过这个坑早上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更新频率不低过几个月回来看代码如果没有注释你会发现根本想不起来当时用的什么参数结构。这个习惯成本极低但后患无穷少。