google-ads-report
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGoogle Ads Report
Google Ads 报告
Pull campaign, keyword, and conversion data from the Google Ads API.
从Google Ads API拉取广告系列、关键词和转化数据。
Prerequisites
前置条件
Requires:
- and
GOOGLE_CLIENT_ID(OAuth)GOOGLE_CLIENT_SECRET - (apply at https://ads.google.com/home/tools/manager-accounts/)
GOOGLE_ADS_DEVELOPER_TOKEN - (the account ID, format:
GOOGLE_ADS_CUSTOMER_ID, passed without dashes)XXX-XXX-XXXX - (if using a manager account, the manager account ID)
GOOGLE_ADS_LOGIN_CUSTOMER_ID
Set in , , or .
.env.env.local~/.claude/.env.global需要:
- 和
GOOGLE_CLIENT_ID(OAuth 认证)GOOGLE_CLIENT_SECRET - (申请地址:https://ads.google.com/home/tools/manager-accounts/)
GOOGLE_ADS_DEVELOPER_TOKEN - (账户ID,格式:
GOOGLE_ADS_CUSTOMER_ID,传入时需去掉连字符)XXX-XXX-XXXX - (若使用经理账户,填写经理账户ID)
GOOGLE_ADS_LOGIN_CUSTOMER_ID
请在 、 或 文件中配置以上参数。
.env.env.local~/.claude/.env.globalGetting an Access Token
获取访问令牌
bash
undefinedbash
undefinedSame OAuth flow as other Google APIs
Same OAuth flow as other Google APIs
Scope needed: https://www.googleapis.com/auth/adwords
Scope needed: https://www.googleapis.com/auth/adwords
Exchange code for tokens
Exchange code for tokens
curl -s -X POST "https://oauth2.googleapis.com/token"
-d "code={AUTH_CODE}"
-d "client_id=${GOOGLE_CLIENT_ID}"
-d "client_secret=${GOOGLE_CLIENT_SECRET}"
-d "redirect_uri=urn:ietf:wg:oauth:2.0:oob"
-d "grant_type=authorization_code"
-d "code={AUTH_CODE}"
-d "client_id=${GOOGLE_CLIENT_ID}"
-d "client_secret=${GOOGLE_CLIENT_SECRET}"
-d "redirect_uri=urn:ietf:wg:oauth:2.0:oob"
-d "grant_type=authorization_code"
---curl -s -X POST "https://oauth2.googleapis.com/token"
-d "code={AUTH_CODE}"
-d "client_id=${GOOGLE_CLIENT_ID}"
-d "client_secret=${GOOGLE_CLIENT_SECRET}"
-d "redirect_uri=urn:ietf:wg:oauth:2.0:oob"
-d "grant_type=authorization_code"
-d "code={AUTH_CODE}"
-d "client_id=${GOOGLE_CLIENT_ID}"
-d "client_secret=${GOOGLE_CLIENT_SECRET}"
-d "redirect_uri=urn:ietf:wg:oauth:2.0:oob"
-d "grant_type=authorization_code"
---API Base
API 基础信息
Google Ads API uses GAQL (Google Ads Query Language) via REST.
POST https://googleads.googleapis.com/v17/customers/{CUSTOMER_ID}/googleAds:searchStreamHeaders:
Authorization: Bearer {ACCESS_TOKEN}
developer-token: {DEVELOPER_TOKEN}
login-customer-id: {LOGIN_CUSTOMER_ID} # Only if using manager account
Content-Type: application/jsonGoogle Ads API 通过REST接口使用GAQL(Google Ads查询语言)。
POST https://googleads.googleapis.com/v17/customers/{CUSTOMER_ID}/googleAds:searchStream请求头:
Authorization: Bearer {ACCESS_TOKEN}
developer-token: {DEVELOPER_TOKEN}
login-customer-id: {LOGIN_CUSTOMER_ID} # Only if using manager account
Content-Type: application/json1. Campaign Performance Report
1. 广告系列绩效报告
Overview of all campaigns with key metrics.
bash
curl -s -X POST \
"https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
-H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
-H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT campaign.name, campaign.status, metrics.impressions, metrics.clicks, metrics.ctr, metrics.average_cpc, metrics.cost_micros, metrics.conversions, metrics.cost_per_conversion, metrics.conversions_value FROM campaign WHERE segments.date DURING LAST_30_DAYS AND campaign.status != REMOVED ORDER BY metrics.cost_micros DESC"
}'所有广告系列的关键指标概览。
bash
curl -s -X POST \
"https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
-H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
-H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT campaign.name, campaign.status, metrics.impressions, metrics.clicks, metrics.ctr, metrics.average_cpc, metrics.cost_micros, metrics.conversions, metrics.cost_per_conversion, metrics.conversions_value FROM campaign WHERE segments.date DURING LAST_30_DAYS AND campaign.status != REMOVED ORDER BY metrics.cost_micros DESC"
}'Parsing Campaign Data
解析广告系列数据
bash
curl -s -X POST "..." | python3 -c "
import json, sys
data = json.load(sys.stdin)
print(f\"{'Campaign':<35} {'Status':<10} {'Impr':>8} {'Clicks':>7} {'CTR':>7} {'Avg CPC':>8} {'Cost':>10} {'Conv':>6} {'CPA':>8}\")
print('-' * 110)
for batch in data:
for row in batch.get('results', []):
c = row.get('campaign', {})
m = row.get('metrics', {})
cost = int(m.get('costMicros', 0)) / 1_000_000
cpc = int(m.get('averageCpc', 0)) / 1_000_000
cpa = float(m.get('costPerConversion', 0)) / 1_000_000 if m.get('costPerConversion') else 0
print(f\"{c.get('name',''):<35} {c.get('status',''):<10} {int(m.get('impressions',0)):>8} {int(m.get('clicks',0)):>7} {float(m.get('ctr',0))*100:>6.2f}% \${cpc:>7.2f} \${cost:>9.2f} {float(m.get('conversions',0)):>6.1f} \${cpa:>7.2f}\")
"bash
curl -s -X POST "..." | python3 -c "
import json, sys
data = json.load(sys.stdin)
print(f\"{'Campaign':<35} {'Status':<10} {'Impr':>8} {'Clicks':>7} {'CTR':>7} {'Avg CPC':>8} {'Cost':>10} {'Conv':>6} {'CPA':>8}\")
print('-' * 110)
for batch in data:
for row in batch.get('results', []):
c = row.get('campaign', {})
m = row.get('metrics', {})
cost = int(m.get('costMicros', 0)) / 1_000_000
cpc = int(m.get('averageCpc', 0)) / 1_000_000
cpa = float(m.get('costPerConversion', 0)) / 1_000_000 if m.get('costPerConversion') else 0
print(f\"{c.get('name',''):<35} {c.get('status',''):<10} {int(m.get('impressions',0)):>8} {int(m.get('clicks',0)):>7} {float(m.get('ctr',0))*100:>6.2f}% \${cpc:>7.2f} \${cost:>9.2f} {float(m.get('conversions',0)):>6.1f} \${cpa:>7.2f}\")
"Important: Cost Micros
重要提示:成本微单位
All cost values in Google Ads API are in micros (1/1,000,000 of the currency unit). Divide by 1,000,000 to get the actual amount.
Google Ads API中的所有成本值均以微单位表示(即货币单位的1/1,000,000)。需除以1,000,000得到实际金额。
2. Keyword Performance Report
2. 关键词绩效报告
See how individual keywords perform.
bash
curl -s -X POST \
"https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
-H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
-H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT ad_group_criterion.keyword.text, ad_group_criterion.keyword.match_type, ad_group_criterion.quality_info.quality_score, metrics.impressions, metrics.clicks, metrics.ctr, metrics.average_cpc, metrics.cost_micros, metrics.conversions, metrics.conversions_value FROM keyword_view WHERE segments.date DURING LAST_30_DAYS AND ad_group_criterion.status != REMOVED ORDER BY metrics.cost_micros DESC LIMIT 50"
}'查看单个关键词的表现。
bash
curl -s -X POST \
"https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
-H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
-H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT ad_group_criterion.keyword.text, ad_group_criterion.keyword.match_type, ad_group_criterion.quality_info.quality_score, metrics.impressions, metrics.clicks, metrics.ctr, metrics.average_cpc, metrics.cost_micros, metrics.conversions, metrics.conversions_value FROM keyword_view WHERE segments.date DURING LAST_30_DAYS AND ad_group_criterion.status != REMOVED ORDER BY metrics.cost_micros DESC LIMIT 50"
}'Quality Score Breakdown
质量得分细分
bash
curl -s -X POST \
"https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
-H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
-H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT ad_group_criterion.keyword.text, ad_group_criterion.quality_info.quality_score, ad_group_criterion.quality_info.creative_quality_score, ad_group_criterion.quality_info.post_click_quality_score, ad_group_criterion.quality_info.search_predicted_ctr, metrics.impressions, metrics.average_cpc FROM keyword_view WHERE ad_group_criterion.quality_info.quality_score IS NOT NULL AND segments.date DURING LAST_30_DAYS ORDER BY ad_group_criterion.quality_info.quality_score ASC LIMIT 50"
}'Quality Score Components:
- quality_score: Overall score (1-10)
- creative_quality_score: Ad relevance (BELOW_AVERAGE, AVERAGE, ABOVE_AVERAGE)
- post_click_quality_score: Landing page experience
- search_predicted_ctr: Expected click-through rate
bash
curl -s -X POST \
"https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
-H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
-H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT ad_group_criterion.keyword.text, ad_group_criterion.quality_info.quality_score, ad_group_criterion.quality_info.creative_quality_score, ad_group_criterion.quality_info.post_click_quality_score, ad_group_criterion.quality_info.search_predicted_ctr, metrics.impressions, metrics.average_cpc FROM keyword_view WHERE ad_group_criterion.quality_info.quality_score IS NOT NULL AND segments.date DURING LAST_30_DAYS ORDER BY ad_group_criterion.quality_info.quality_score ASC LIMIT 50"
}'质量得分组成部分:
- quality_score: 整体得分(1-10)
- creative_quality_score: 广告相关性(BELOW_AVERAGE, AVERAGE, ABOVE_AVERAGE)
- post_click_quality_score: 着陆页体验
- search_predicted_ctr: 预估点击率
3. Ad Group Performance
3. 广告组绩效报告
bash
curl -s -X POST \
"https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
-H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
-H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT campaign.name, ad_group.name, ad_group.status, metrics.impressions, metrics.clicks, metrics.ctr, metrics.average_cpc, metrics.cost_micros, metrics.conversions FROM ad_group WHERE segments.date DURING LAST_30_DAYS AND ad_group.status != REMOVED ORDER BY metrics.cost_micros DESC LIMIT 50"
}'bash
curl -s -X POST \
"https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
-H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
-H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT campaign.name, ad_group.name, ad_group.status, metrics.impressions, metrics.clicks, metrics.ctr, metrics.average_cpc, metrics.cost_micros, metrics.conversions FROM ad_group WHERE segments.date DURING LAST_30_DAYS AND ad_group.status != REMOVED ORDER BY metrics.cost_micros DESC LIMIT 50"
}'4. Search Terms Report
4. 搜索词报告
See what users actually searched for (vs. your keywords).
bash
curl -s -X POST \
"https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
-H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
-H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT search_term_view.search_term, segments.keyword.info.text, segments.keyword.info.match_type, metrics.impressions, metrics.clicks, metrics.ctr, metrics.cost_micros, metrics.conversions FROM search_term_view WHERE segments.date DURING LAST_30_DAYS ORDER BY metrics.impressions DESC LIMIT 100"
}'Use this to:
- Find new keyword opportunities (high-converting search terms)
- Identify negative keyword candidates (irrelevant terms with spend)
- Discover match type issues (broad match pulling in junk traffic)
查看用户实际搜索的内容(与您设置的关键词对比)。
bash
curl -s -X POST \
"https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
-H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
-H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT search_term_view.search_term, segments.keyword.info.text, segments.keyword.info.match_type, metrics.impressions, metrics.clicks, metrics.ctr, metrics.cost_micros, metrics.conversions FROM search_term_view WHERE segments.date DURING LAST_30_DAYS ORDER BY metrics.impressions DESC LIMIT 100"
}'该报告可用于:
- 发现新的关键词机会(高转化搜索词)
- 识别否定关键词候选(有支出但不相关的搜索词)
- 发现匹配类型问题(广泛匹配带来无效流量)
5. Conversion Tracking
5. 转化追踪报告
bash
curl -s -X POST \
"https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
-H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
-H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT campaign.name, metrics.conversions, metrics.conversions_value, metrics.cost_micros, metrics.conversions_from_interactions_rate, metrics.value_per_conversion FROM campaign WHERE segments.date DURING LAST_30_DAYS AND campaign.status = ENABLED ORDER BY metrics.conversions DESC"
}'bash
curl -s -X POST \
"https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
-H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
-H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT campaign.name, metrics.conversions, metrics.conversions_value, metrics.cost_micros, metrics.conversions_from_interactions_rate, metrics.value_per_conversion FROM campaign WHERE segments.date DURING LAST_30_DAYS AND campaign.status = ENABLED ORDER BY metrics.conversions DESC"
}'ROAS Calculation
ROAS 计算
bash
undefinedbash
undefinedROAS = conversions_value / (cost_micros / 1_000_000)
ROAS = conversions_value / (cost_micros / 1_000_000)
curl -s -X POST "..." | python3 -c "
import json, sys
data = json.load(sys.stdin)
print(f"{'Campaign':<35} {'Cost':>10} {'Conv Value':>12} {'ROAS':>8}")
for batch in data:
for row in batch.get('results', []):
c = row['campaign']['name']
m = row['metrics']
cost = int(m.get('costMicros', 0)) / 1_000_000
value = float(m.get('conversionsValue', 0))
roas = value / cost if cost > 0 else 0
print(f"{c:<35} ${cost:>9.2f} ${value:>11.2f} {roas:>7.2f}x")
"
---curl -s -X POST "..." | python3 -c "
import json, sys
data = json.load(sys.stdin)
print(f"{'Campaign':<35} {'Cost':>10} {'Conv Value':>12} {'ROAS':>8}")
for batch in data:
for row in batch.get('results', []):
c = row['campaign']['name']
m = row['metrics']
cost = int(m.get('costMicros', 0)) / 1_000_000
value = float(m.get('conversionsValue', 0))
roas = value / cost if cost > 0 else 0
print(f"{c:<35} ${cost:>9.2f} ${value:>11.2f} {roas:>7.2f}x")
"
---6. Daily Spend Trend
6. 每日支出趋势报告
bash
curl -s -X POST \
"https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
-H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
-H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT segments.date, metrics.impressions, metrics.clicks, metrics.cost_micros, metrics.conversions FROM customer WHERE segments.date DURING LAST_30_DAYS ORDER BY segments.date DESC"
}'bash
curl -s -X POST \
"https://googleads.googleapis.com/v17/customers/${GOOGLE_ADS_CUSTOMER_ID}:searchStream" \
-H "Authorization: Bearer ${GADS_ACCESS_TOKEN}" \
-H "developer-token: ${GOOGLE_ADS_DEVELOPER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT segments.date, metrics.impressions, metrics.clicks, metrics.cost_micros, metrics.conversions FROM customer WHERE segments.date DURING LAST_30_DAYS ORDER BY segments.date DESC"
}'GAQL Date Ranges
GAQL 日期范围
Use these built-in date ranges in GAQL:
- ,
TODAYYESTERDAY - ,
LAST_7_DAYS,LAST_14_DAYSLAST_30_DAYS - ,
THIS_MONTHLAST_MONTH - ,
THIS_QUARTERLAST_QUARTER - Custom:
segments.date BETWEEN '2024-01-01' AND '2024-03-31'
可在GAQL中使用以下内置日期范围:
- ,
TODAYYESTERDAY - ,
LAST_7_DAYS,LAST_14_DAYSLAST_30_DAYS - ,
THIS_MONTHLAST_MONTH - ,
THIS_QUARTERLAST_QUARTER - 自定义范围:
segments.date BETWEEN '2024-01-01' AND '2024-03-31'
Workflow: Monthly Google Ads Report
工作流:月度Google Ads报告
When asked for a full ads report:
- Account Overview: Total spend, impressions, clicks, conversions, ROAS
- Campaign Performance: All active campaigns ranked by spend
- Top Keywords: Top 20 keywords by spend with quality scores
- Search Terms: Top search terms and negative keyword candidates
- Quality Score Distribution: How many keywords at each QS level
- Conversion Analysis: Conversions and ROAS by campaign
- Daily Trend: Spend and conversion trend over the period
当需要生成完整广告报告时:
- 账户概览: 总支出、展示量、点击量、转化量、ROAS
- 广告系列绩效: 所有活跃广告系列按支出排序
- 核心关键词: 按支出排名前20的关键词及质量得分
- 搜索词分析: 核心搜索词及否定关键词候选
- 质量得分分布: 各质量得分等级的关键词数量
- 转化分析: 各广告系列的转化量及ROAS
- 每日趋势: 周期内的支出和转化趋势
Report Format
报告格式
undefinedundefinedGoogle Ads Report: {Account Name}
Google Ads Report: {Account Name}
Period: {date range}
Period: {date range}
Account Summary
Account Summary
| Metric | Value | vs Previous |
|---|---|---|
| Total Spend | $X | +Y% |
| Impressions | X | +Y% |
| Clicks | X | +Y% |
| CTR | X% | +Y pp |
| Avg CPC | $X | +Y% |
| Conversions | X | +Y% |
| ROAS | Xx | +Y% |
| Metric | Value | vs Previous |
|---|---|---|
| Total Spend | $X | +Y% |
| Impressions | X | +Y% |
| Clicks | X | +Y% |
| CTR | X% | +Y pp |
| Avg CPC | $X | +Y% |
| Conversions | X | +Y% |
| ROAS | Xx | +Y% |
Campaign Performance
Campaign Performance
| Campaign | Spend | Clicks | Conv | CPA | ROAS |
|---|---|---|---|---|---|
| ... | ... | ... | ... | ... | ... |
| Campaign | Spend | Clicks | Conv | CPA | ROAS |
|---|---|---|---|---|---|
| ... | ... | ... | ... | ... | ... |
Top Keywords (by spend)
Top Keywords (by spend)
| Keyword | Match | QS | Spend | Clicks | Conv | CPC |
|---|---|---|---|---|---|---|
| ... | ... | ... | ... | ... | ... | ... |
| Keyword | Match | QS | Spend | Clicks | Conv | CPC |
|---|---|---|---|---|---|---|
| ... | ... | ... | ... | ... | ... | ... |
Recommendations
Recommendations
- Pause: Keywords with high spend and zero conversions
- Increase Bids: Keywords with high conversion rate but limited budget
- Negative Keywords: Search terms wasting budget
- Quality Score Fixes: Keywords with QS < 5 and actions to improve
- Budget Reallocation: Shift budget from low-ROAS to high-ROAS campaigns
---- Pause: Keywords with high spend and zero conversions
- Increase Bids: Keywords with high conversion rate but limited budget
- Negative Keywords: Search terms wasting budget
- Quality Score Fixes: Keywords with QS < 5 and actions to improve
- Budget Reallocation: Shift budget from low-ROAS to high-ROAS campaigns
---Error Handling
错误处理
| Error | Cause |
|---|---|
| Invalid or expired access token |
| Developer token issue or account access |
| GAQL syntax error |
| API quota exceeded |
| 错误类型 | 原因 |
|---|---|
| 访问令牌无效或已过期 |
| 开发者令牌问题或账户权限不足 |
| GAQL语法错误 |
| API配额已用尽 |
Common GAQL Mistakes
常见GAQL错误
- Missing (required for most metric queries)
WHERE segments.date DURING ... - Using status filter incorrectly
REMOVED - Forgetting to handle division by 1,000,000
costMicros - Requesting incompatible resource + segment combinations
- 缺少(大多数指标查询必填)
WHERE segments.date DURING ... - 错误使用状态过滤器
REMOVED - 忘记将除以1,000,000
costMicros - 请求了不兼容的资源和细分维度组合
Tips
小贴士
- Always filter out REMOVED campaigns/ad groups/keywords
- Use instead of
searchStreamfor large result sets (no pagination needed)search - Cache results when building multi-section reports
- Quality Score of 0 means "not enough data" -- treat as null
- 始终过滤掉已移除(REMOVED)的广告系列/广告组/关键词
- 对于大量结果集,使用而非
searchStream(无需分页)search - 生成多部分报告时缓存结果
- 质量得分为0表示“数据不足”,需视为空值处理