流程

  • 开通百度推广账号:大客户找代理,小客户直接开户;
  • 在营销中心设置相关信息(比如公司信息、推广站点信息等内容);
  • 创建自己的推广站点,并部署自己的追踪代码(追踪访客来源和轨迹);
  • 创建百度推广账号结构(计划、单元、关键词、创意),并进行发布;
  • 申请开通百度商业开发者中心权限,并获取权限代码(普通权限和账户管家权限可以直接通过E秘自助开通)。
  • 百度营销首页:
    https://www2.baidu.com
  • 百度商业开发者中心:
    http://dev2.baidu.com
  • 搜索推广API文档:
    http://dev2.baidu.com/newdev2/dist/index.html#/content/?pageType=1&productlineId=3&nodeId=399&pageId=293&url=

API调用方式

百度推广API提供对账户管理、推广管理、推广辅助、报告查看等功能,调用时只要请求不同服务所对应的URL,传入指定参数即可实现目的。所以这个服务可以集成到任何形式的应用里,比如桌面应用、WEB服务等等。

基础的推广流程介绍

百度搜索结果页中,有一定数量的广告位置,搜索推广即是以这些广告位作为标的,以竞价的形式进行广告投放。一旦竞价成功,则会展现获胜者的广告内容(竞价者以关键词匹配的形式参与进来),获得展现后,如果访客点击广告结果,则会产生一个向广告主计费的点击,本次竞价的成本即为本次点击所消耗的广告费用。

到此为止,即是百度推广在搜索推广中所进行的全部活动:提供广告平台,由广告主参与竞价,优胜者展现广告,至于访客点不点这个广告,就看广告的相关度以及广告主的广告创意撰写得如何了。

接下来,访客会被广告位中的链接带入广告主的着陆页,开始进入转化阶段。这一阶段就是纯粹的八仙过海各显神通,广告主的最终目的就是让网页访客进行转化,使出浑身解数让普通访客变成自己的真正客户。

因为每一条广告都必带广告链接,所以可以在链接上添加自定义的参数(或预定义通配符),对不同广告进行标记,结合访客转化数据,就可以对广告绩效进行综合考评。

广告标记

所谓的广告标记,是URL中的一个/套自定义参数,比如为每条广告、每个关键词都设置一个唯一id。此外,百度还提供了通配符参数,展示广告的时候,广告链接会将通配符参数替换为实际内容,比如在URL中加入{adposition}和{pagenum}两个通配参数,最终展示的时候,该占位将被替换成实际的广告排名和广告所在的搜索结果页码。

2019年4月起,百度对URL插入通配符参数功能进行了升级,新增{userid},{planid},{unitid},{keyword}4个通配符。

支持的通配符,以及通配符使用详情可以参考该文档:

http://dev2.baidu.com/newdev2/dist/index.html#/content/?pageType=1&productlineId=3&nodeId=133&pageId=39

通过以上步骤,就获取到了来源数据,再结合访客在本站点的活动轨迹、转化情况,就可以了解不同广告的表现,并根据推广效果对广告内容进行优化。

推广API分类

百度推广API分为以下几类:

基础广告管理

  • AccountService:账户模块,用于查询/更新账户所有属性,包括:账户余额、预算、地域、注册域名等
  • CampaignService:计划模块,用于计划层级物料管理—新增/删除/修改/查询计划,属性包括:计划名称、计划预算、计划状态、计划地域、否定关键词、计划投放设备等
  • AdgroupService:单元模块,用于单元层级物料管理,新增/删除/修改/查询单元,属性包括:单元名称、单元出价、单元否定关键词、单元计算机/移动出价比例、图片素材配图开关等
  • KeywordService:关键词模块,用于关键词层级物料管理,新增/删除/修改/查询关键词,属性包括:关键词出价、访问url、小程序url、匹配方式、关键词状态、关键词标签、关键词指导价等
  • CreativeService:创意模块,用于创意层级物料管理,新增/删除/修改/查询创意,属性包括:创意标题、创意描述、访问url、显示url、小程序url、创意状态、创意标签、创意设备偏好等

数据报告

  • ReportService:数据报告服务,支持实时报告和异步报告两种类型、包括:账户、计划、单元、创意等层级的报告类型
  • LiveReportService:实时数据报告服务,支持账户/计划/关键词实时数据

样式管理

  • NewCreativeService:高级样式模块,用于高级样式属性管理
  • LeadAdsService:线索通模块,用于线索通自定义表单-线索追踪的线索内容
  • ImageSegmentService:图片素材管理服务,用于实现图片上传、图片自动裁剪、素材撰写描述/更新、素材删除等
  • AdgroupImageSegmentBindService:图片素材绑定服务,用于单元查询、绑定/解绑定图片素材信息

人群管理

  • CrowdService:人群模块,用于新增/删除/修改/查询人群信息,包括:人群名称、年龄、性别、兴趣等
  • CrowdBindService:人群管理模块,用于绑定/解绑/查询/删除人群信息,包括,计划层级/创意层级绑定,人群绑定出价系数等

辅助功能

  • ToolkitService:历史操作记录查询,用于查询账户中物料操作后的记录,包括账户、计划、单元、关键词、创意等层级
  • BulkService:整账户下载,用于获取账户/计划的完整物料信息,包括:账户、计划、单元、创意各层级物料内容
  • KRService:关键词规划师,用于根据种子词扩展关键词、关键词预估
  • SearchService:综合查询服务,用于查询账户内关键词搜索、物料标签搜索、关键词/创意筛选状态和质量度
  • TabService:物料标签服务,用于查询关键词/创意层级的标签名称、标签颜色、标签id等

访问推广API

访问推广API本质上就是一个简单的HTTP POST过程,将对应内容,以JSON格式附在请求里,发送给指定的API接口,即完成了一次接口调用。每个账户在统计周期内,接口调用配额有上限(每周清零配额计数,重新开始统计)。

请求内容要求为JSON格式,包含header对象和body对象:header对象为认证信息,body部分为接口名以及接口参数。比如通过API获取账户基础信息,就可以构造一个如下格式的JSON字符串向https://api.baidu.com/json/sms/service/AccountService/getAccountInfo发送POST请求:


{
    "header": {
        "username": "用户账户的用户名",
        "password": "用户账户的密码",
        "token": "用户账户的API权限代码"
    },
    "body": {
      "getAccountInfoRequest": { "type": "1" }
    }
}

以上请求内容的header部分是普通账号的格式,如果是账户管家用户,需要使用账户管家的用户、密码、权限代码,并用target参数指定需要访问的被管理账户。


    "header": {
        "username": "账户管家账户的用户名",
        "password": "账户管家账户的密码",
        "target": "被管理账户的用户名",
        "token": "账户管家账户的API权限代码"
    }

响应格式也是JSON结果,格式如下


{
    "header":{
        "status":0,         //0:成功,1:部分失败,2:全部失败,3:系统错误
        "desc":"success",   //描述
        "rquota":49018033   //剩余的请求配额(现可忽略)
        "quota": 2,         //本次请求发送的数据条数
        "failures":[        //错误信息
            {
                 "code":800,
                 "message":"系统内部错误",
                 "position":"_sys",
            },
        ],        
        "oprs": 2 //成功操作数据条数
        "oprtime":1 //操作时间描述
    },
    "body":{
        //业务字段,请参考各接口的说明
    }
}

其它接口也是使用同样的流程进行调用,区别在于不同接口使用各自对应的API地址,以及不同的参数列表。

报告接口

报告接口有两类,同步报告和异步报告。同步报告的响应更快,数据更小,所以请求发出后,程序可以直接阻塞并等待后台返回报告数据;异步报告因为耗时更高,阻塞状态会影响程序正常运行,所以在发出报告请求以后,推广后台会直接返回调用结果,并开始准备报告,此时可以通过不间断地访问专门的报告状态查询接口(getReportState)查看本次reportID对应任务的进展,一旦发现报告生成完毕,调用getReportFileUrl接口获取生成的报告文件URL以后,就可以使用http下载的形式获取报告文件了。

因为百度的文档已经写得非常完善,再多罗嗦下去就显得非常多余。本文的目的主要是为了让不了解的人可以抛开令新手眼花缭乱的手册去了解如何上手,一旦了解了整个流程,后面就可以根据自己的需求选择相应的方式去实现,或者反过来,根据API的功能去设计自己的产品。

DEMO

DEMO演示了如何获取百度推广账号7天账号数据报告、和基本账号信息,可在此基础上进行扩充,将它变成自己的产品。

因为Request和Response的基本结构都一样,所以为专门写了对应的基类,供各个接口继承,除了Request、Response请求本身,在请求和响应的body部分,每个接口也有自己的数据格式(不同的参数,也即不同的数据实体)封装于内,所以也需要为此实体专门准备对应的请求数据类和响应数据类。


BaiduHelper:获取基础账户信息、7天账号实时报告


    public enum BaiduUserStat
    {
        开户金未到 = 1,
        正常生效 = 2,
        余额为零 = 3,
        未通过审核 = 4,
        审核中 = 6,
        被禁用 = 7,
        预算不足 = 11
    }
    public enum BaiduUserLevel
    {
        三星 = 1,
        二星 = 2,
        一星 = 3,
        未生效 = 4
    }
    public static class BaiduHelper
    {
        public static string UserName { get; set; }
        public static string Password { get; set; }
        public static string Token { get; set; }
        public static string CallPost(string url, object content)
        {
            using WebClient client = new WebClient();
            client.Headers["Content-Type"] = "application/json;charset=utf8";
            string res =
                Encoding.UTF8.GetString(
                    client.UploadData(url, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(content))));            
            return res;
        }
        public static AccountInfoResult GetAccount()
        {
            string res =
                CallPost("https://api.baidu.com/json/sms/service/AccountService/getAccountInfo",
                new BaiduRequest()
                {
                    body = new getAccountInfoRequest()
                });
            return JsonConvert.DeserializeObject<AccountInfoResult>(res);
        }
        public static RealTimeInfoResult Get7DaysReport()
        {
            string res =
                CallPost("https://api.baidu.com/json/sms/service/ReportService/getRealTimeData",
                new BaiduRequest()
                {
                    body = new RealTimeRequest()
                });
            return JsonConvert.DeserializeObject<RealTimeInfoResult>(res);
        }
        public static string GeneralInfo()
        {
            using DBHelper helper = new DBHelper();
            string id = DateTime.Now.ToString("yyyy-MM-dd");
            var report =
                 helper.FetchFirst(
                     "SELECT `report` FROM `baidu_reports` WHERE `id`=@id",
                     new Dictionary<string, object> { { "id", id } },
                     out _);
            if (report is null)
            {
                AccountInfoType acc = GetAccount().body.data[0];
                report =
                    $"【百度推广日报 \t{DateTime.Now:MM-dd HH:mm}】\n" +
                    $"状态:{acc.userLevel},{acc.userStat}\n" +
                    $"充值:¥{acc.payment}\n" +
                    $"余额:¥{acc.balance + acc.pcBalance + acc.mobileBalacne}\n" +
                    $"消费:¥{acc.cost}\n" +
                    $"预算:¥{acc.budget}/天\n\n" +
                    $"七天报告:\n日期 \t展现,点击,消费\n";
                List<RealTimeInfoType> days = Get7DaysReport().body.data;
                report += string.Join("\n", days.Select(d => d.date + " \t" + string.Join(", \t", d.kpis)));
                helper.Query(
                    $"INSERT INTO `baidu_reports` (`id`, `report`) VALUES (@id, @report)",
                    new Dictionary<string, object> {
                        { "id", id }, { "report", report }
                    }, out _);
            }
            return $"{report}";
        }
    }

BaiduRequest基类:所有类型的请求均继承该类(因为格式一样,只有body参数不一样)


    public class BaiduRequest
    {
        public BaiduRequestHeader header { get; set; } =
            new BaiduRequestHeader()
            {
                username = BaiduHelper.UserName,
                password = BaiduHelper.Password,
                token = BaiduHelper.Token
            };
        public BaiduRequestBody body { get; set; }
    }
    public class BaiduRequestHeader
    {
        public string username { get; set; }
        public string password { get; set; }
        public string token { get; set; }
    }
    public class BaiduRequestBody { }

BaiduResponse基类:所有接口的Response都继承该类(格式一样,只有body参数不一样)


    public class BaiduResponse
    {
        public BaiduResponseResult data { get; set; }
        public int status { get; set; }
        public List<string> errors { get; set; }
    }
    public class BaiduResponseResult { public BaiduResponseResultHeader header { get; set; } }
    public class BaiduResponseResultHeader
    {
        public int oprs { get; set; }
        public int oprtime { get; set; }
        public long rquota { get; set; }
        public List<string> failures { get; set; }
        public int succ { get; set; }
        public long quota { get; set; }
        public string desc { get; set; }
        public int status { get; set; }
    }

账户信息接口的相关类:请求、响应、以及账户信息类


    public class getAccountInfoRequest : BaiduRequestBody
    {
        public List<string> accountFields { get; set; } =
            new List<string> { "balance", "pcBalance", "mobileBalance", "budget", "payment", "userStat", "cost", "userLevel" };
    }

    public class AccountInfoResult : BaiduResponseResult { public AccountInfoResultBody body { get; set; } }
    public class AccountInfoResultHeader
    {
        public int oprs { get; set; }
        public int oprtime { get; set; }
        public long rquota { get; set; }
        public List<string> failures { get; set; }
        public int succ { get; set; }
        public long quota { get; set; }
        public string desc { get; set; }
        public int status { get; set; }
    }
    public class AccountInfoResultBody { public List<AccountInfoType> data { get; set; } }
    public class AccountInfoType
    {
        public string userId { get; set; }
        public decimal balance { get; set; }
        public decimal pcBalance { get; set; }
        public decimal mobileBalacne { get; set; }
        public decimal cost { get; set; }
        public decimal payment { get; set; }
        public decimal budget { get; set; }
        public BaiduUserStat userStat { get; set; }
        public BaiduUserLevel userLevel { get; set; }
    }

同步报告接口的相关类:请求、响应、以及报告类


    public class RealTimeRequest : BaiduRequestBody { public RealTimeRequestType realTimeRequestType = new RealTimeRequestType(); }
    public class RealTimeRequestType
    {
        public List<string> performanceData { get; set; } = new List<string> { "impression", "click", "cost" };
        public string startDate { get; set; } = DateTime.Now.AddDays(-7).ToString("yyyy-MM-dd");
        public string endDate { get; set; } = DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd");
        public int reportType { get; set; } = 2;//账户
    }
    public class RealTimeInfoType
    {
        public long id { get; set; }
        public List<string> name { get; set; }
        public string date { get; set; }
        public List<string> kpis { get; set; }
    }
    public class RealTimeInfoResult : BaiduResponseResult { public RealTimeInfoResultBody body { get; set; } }

    public class RealTimeInfoResultBody { public List<RealTimeInfoType> data { get; set; } }