程序化广告优化与反欺诈
RTB 买量只是起点——真正的挑战在于如何优化出价策略、过滤无效流量、以及在碎片化的媒体环境中找到高价值展示机会。
程序化投放优化全景
graph TB
A[投放策略] --> B[出价优化]
A --> C[库存筛选]
A --> D[频次控制]
A --> E[反欺诈]
B --> B1[动态 CPM]
B --> B2[目标 CPA]
B --> B3[ROAS 出价]
C --> C1[白名单]
C --> C2[黑名单]
C --> C3[PMPs]
E --> E1[Bot 检测]
E --> E2[异常点击]
E --> E3[展示欺诈]
style A fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
style E fill:#ffcdd2,stroke:#e53935,stroke-width:2px
出价优化器
from dataclasses import dataclass
from enum import Enum
class BidStrategy(Enum):
FIXED_CPM = "fixed_cpm"
TARGET_CPA = "target_cpa"
TARGET_ROAS = "target_roas"
MAXIMIZE_CLICKS = "maximize_clicks"
@dataclass
class BidRequest:
placement_id: str
floor_price: float # 底价 CPM
predicted_ctr: float # 预估 CTR
predicted_cvr: float # 预估转化率
user_segment: str # 用户分群
@dataclass
class BidResponse:
bid_price: float
should_bid: bool
strategy_used: str
reason: str = ""
class ProgrammaticBidder:
"""程序化出价器"""
def __init__(self, target_cpa: float = 50.0, daily_budget: float = 5000.0):
self.target_cpa = target_cpa
self.daily_budget = daily_budget
self.spent_today = 0.0
@property
def budget_remaining(self) -> float:
return self.daily_budget - self.spent_today
def calculate_bid(
self, request: BidRequest, strategy: BidStrategy
) -> BidResponse:
"""根据策略计算出价"""
# 预算耗尽不出价
if self.budget_remaining <= 0:
return BidResponse(0, False, strategy.value, "预算耗尽")
if strategy == BidStrategy.TARGET_CPA:
return self._bid_target_cpa(request)
elif strategy == BidStrategy.TARGET_ROAS:
return self._bid_target_roas(request)
elif strategy == BidStrategy.MAXIMIZE_CLICKS:
return self._bid_maximize_clicks(request)
else:
return BidResponse(
request.floor_price * 1.1, True,
strategy.value, "固定加价 10%"
)
def _bid_target_cpa(self, req: BidRequest) -> BidResponse:
"""目标 CPA 出价:根据预估转化率反推"""
if req.predicted_ctr <= 0 or req.predicted_cvr <= 0:
return BidResponse(0, False, "target_cpa", "预估值为零")
# CPM = target_CPA × CTR × CVR × 1000
bid_cpm = self.target_cpa * req.predicted_ctr * req.predicted_cvr * 1000
should_bid = bid_cpm >= req.floor_price
return BidResponse(
round(bid_cpm, 2), should_bid, "target_cpa",
f"CPA反推CPM={bid_cpm:.2f}, 底价={req.floor_price}"
)
def _bid_target_roas(self, req: BidRequest) -> BidResponse:
"""目标 ROAS 出价"""
avg_order_value = 200.0 # 平均订单金额
target_roas = 3.0
max_cpa = avg_order_value / target_roas
bid_cpm = max_cpa * req.predicted_ctr * req.predicted_cvr * 1000
should_bid = bid_cpm >= req.floor_price
return BidResponse(
round(bid_cpm, 2), should_bid, "target_roas",
f"ROAS={target_roas}, 最高CPA={max_cpa:.0f}"
)
def _bid_maximize_clicks(self, req: BidRequest) -> BidResponse:
"""最大化点击模式——用完预算为止"""
# 简化:底价上浮 20%
bid = req.floor_price * 1.2
bid = min(bid, self.budget_remaining)
return BidResponse(
round(bid, 2), True, "maximize_clicks",
"底价+20%, 剩余预算优先"
)
# 使用示例
bidder = ProgrammaticBidder(target_cpa=40.0, daily_budget=8000.0)
req = BidRequest(
placement_id="site_001",
floor_price=5.0,
predicted_ctr=0.012,
predicted_cvr=0.03,
user_segment="高价值用户",
)
response = bidder.calculate_bid(req, BidStrategy.TARGET_CPA)
print(f"出价: {response.bid_price} CPM | 竞价: {response.should_bid} | {response.reason}")
广告欺诈检测
from dataclasses import dataclass
@dataclass
class ClickEvent:
ip: str
user_agent: str
timestamp: float
placement_id: str
is_visible: bool = True
class FraudDetector:
"""基础广告欺诈检测"""
# 已知 Bot User-Agent 关键词
BOT_SIGNATURES = [
"bot", "crawler", "spider", "headless",
"phantomjs", "selenium"
]
def __init__(self, click_threshold: int = 10, window_sec: float = 60.0):
self.click_threshold = click_threshold
self.window_sec = window_sec
self.ip_clicks: dict[str, list[float]] = {}
def is_bot(self, event: ClickEvent) -> bool:
ua_lower = event.user_agent.lower()
return any(sig in ua_lower for sig in self.BOT_SIGNATURES)
def is_click_flood(self, event: ClickEvent) -> bool:
"""同一 IP 短时间内点击过多"""
now = event.timestamp
clicks = self.ip_clicks.get(event.ip, [])
# 过滤窗口外的旧记录
recent = [t for t in clicks if now - t < self.window_sec]
recent.append(now)
self.ip_clicks[event.ip] = recent
return len(recent) > self.click_threshold
def check(self, event: ClickEvent) -> dict:
flags = []
if self.is_bot(event):
flags.append("BOT_UA")
if self.is_click_flood(event):
flags.append("CLICK_FLOOD")
if not event.is_visible:
flags.append("INVISIBLE_AD")
return {
"ip": event.ip,
"is_fraud": len(flags) > 0,
"flags": flags,
}
广告欺诈类型对比
| 类型 | 手法 | 占比 | 检测方式 | 损失程度 |
|---|---|---|---|---|
| Bot 点击 | 自动化脚本点击 | ~35% | UA/行为分析 | 高 |
| 点击农场 | 真人低成本点击 | ~20% | 地理/设备异常 | 中 |
| 展示注入 | 1x1 像素广告 | ~15% | 可见性检测 | 中 |
| 归因劫持 | SDK 伪造安装 | ~15% | 时间戳异常 | 高 |
| 域名欺骗 | 冒充优质媒体 | ~15% | ads.txt 验证 | 高 |
本章小结
- 出价反推——从 target CPA 和预估 CTR×CVR 反算合理 CPM
- 四种出价策略——固定CPM、目标CPA、目标ROAS、最大化点击
- Bot 三重检测——UA 签名 + 点击频率 + 展示可见性
- ads.txt 必须启用——防止域名欺骗,验证授权卖家
- 每日预算兜底——任何策略都要检查剩余预算
下一章:平台内广告实战