name: adhome-whitelist-v3 description: 消費醫療加白V3。當用戶提到「加白」「加白第N行」「ADHome」「adhome」「白名單」「機構准入」「消費醫療加白」時觸發。支援企微文件+騰訊文件雙源讀取,自動下載附件(優先docx,禁止靜默降級PDF),智慧填表提交,分類級聯選擇器修復,訊號檔案確認機制,審批狀態追蹤,企微Webhook通知。 dependencies: [] allowed-tools: disable: false
自動完成 ADHome(adhome.woa.com)廣告賬戶加白(機構准入評估)申請的全流程。經過 10+ 次實戰迭代最佳化,具備訊號檔案確認機制確保安全提交。
核心能力: - 雙源文件讀取:企微文件(Playwright)+ 騰訊文件(MCP 匯出 xlsx) - 智慧附件下載:優先 docx 匯出(企微文件選單匯出 / 騰訊文件 Chrome profile 登入匯出),下載失敗時提醒使用者而非靜默降級 - 自動填寫 ADHome 表單(Playwright 瀏覽器自動化) - 分類級聯選擇器精確匹配(三列獨立選擇,葉子節點 radio) - 訊號檔案機制:填表→截圖→使用者按鈕確認→提交(防誤操作) - ADHome Cookie 自動重新整理(iOA 驗證)+ 每次登入後必須儲存 Cookie - 企微 Webhook 通知(兩層:指令碼層+Agent層)+ 審批狀態定時追蹤
重要:嚴格按此流程執行,不要新增額外步驟。
使用者: "加白第N行" + 文件連結
│
┌────┴────┐
│ 前置檢查 │
└────┬────┘
│
0️⃣ Webhook 配置檢查(首次觸發)
├─ user_config.json 存在? → YES → 讀取 webhook
└─ NO → 引導使用者配置 → 儲存
│
① 識別文件型別並讀取第N行資料
├─ doc.weixin.qq.com → Playwright + 企微Cookie
└─ docs.qq.com → MCP export_file 匯出 xlsx + openpyxl
⚠️ 必須先讀表頭確認列對映
│
② 定位/下載素材檔案(⚠️ 附件格式優先順序:docx > 圖片 > PDF)
├─ 本地搜尋 ~/Desktop/加白/
├─ 企微文件 → Playwright 選單匯出 docx
├─ 騰訊文件 → Chrome profile 登入態 + 選單匯出 docx
├─ ⚠️ 下載失敗/只能PDF?→ 暫停,提醒使用者檢查許可權和登入態
│ ├─ 🛑 使用者選停止 → 關閉瀏覽器,終止當前行
│ └─ 🔄 使用者選繼續 → 關閉瀏覽器,修復後重新下載,成功後繼續
└─ 禁止靜默降級為 PDF(除非使用者明確允許)
│
③ 構建 Config → 後臺執行填表指令碼(auto_submit: false 必須!)
→ 指令碼填完表 → 截圖 → 寫訊號檔案 → 輪詢等待
│
④ 對話方塊確認
→ 展示填寫內容彙總表格 + 表單截圖
→ ✅ 提交 / ❌ 撤回
│
⑤ 驗證 + 企微通知(兩層)
使用者: "加白第6行和第7行"
│
① 一次 Playwright/MCP 例項讀取所有行資料
│
② 批次下載附件(MCP 可並行匯出)
│
③ 逐行序列:
├─ 構建 config → 後臺填表 → 等待訊號
├─ 展示確認按鈕 → 使用者確認
├─ 提交 → 驗證
└─ 下一行...
│
④ 一條企微通知彙總所有行結果
| 項 | 說明 |
|---|---|
| 配置檔案 | {SKILL_DIR}/scripts/user_config.json |
| 格式 | {"notify_webhook": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"} |
| 首次引導 | 檢測不到 webhook → 提示使用者提供企微群機器人 Webhook 地址 → 寫入持久化 |
| 後續執行 | 自動讀取,無需重複配置 |
| ⚠️ 規則 | 不同使用者有不同 webhook,嚴禁硬編碼 |
| URL 域名 | 文件型別 | 讀取方式 |
|---|---|---|
doc.weixin.qq.com |
企微文件 | Playwright + 企微 Cookie |
docs.qq.com |
騰訊文件 | MCP 匯出 xlsx + openpyxl |
~/.wecom-doc-cookies.json,格式 { "cookies": [...] }const cookies = Array.isArray(raw) ? raw : raw.cookies || []input.bar-label | Formula bar:.formula-input.formula-bar-content .ql-editor 已失效# 1. 匯出 xlsx
mcporter call tencent-docs manage.export_file --args '{"file_id":"DSWhDdm5zY1hkeUxq"}'
# 2. 輪詢進度(5s)
mcporter call tencent-docs manage.export_progress --args '{"task_id":"xxx"}'
# 3. curl 下載 xlsx → openpyxl 解析
⚠️ smartsheet API 不支援普通 sheet,只支援智慧表格 ⚠️ 企微 Cookie 訪問 docs.qq.com 時部分列顯示"此單元格已開啟填寫內容隱藏"
不同文件的列結構可能不同: - 標準格式:A→S 直接對應 19 個欄位 - 擴充套件格式:前 3 列為日期/代理/提報人(A-C),實際資料從 D 列開始,擴充套件到 V 列
必須先讀表頭(第 1 行)確認列對映!
| 列 | 欄位 |
|---|---|
| A | 選擇行業 |
| B | 主體名稱 |
| C | 賬戶ID(多個用換行分隔) |
| D | 廣告主產業身份 |
| E | 廣告主資本背景 |
| F | 資質資訊附件 |
| G | 品牌名+產品名 |
| H | 產品連結方式 |
| I | 產品連結 |
| J | 外層素材 |
| K | 素材落地頁方式 |
| L | 素材落地頁連結 |
| M | 投放鏈路 |
| N | 分類 |
| O | 投放機構名稱 |
| P | 競媒投放消耗 |
| Q | 消耗預算 |
| R | 保證金豁免 |
| S | 備註 |
| 列 | 欄位 |
|---|---|
| A | 提報時間 |
| B | 提報代理 |
| C | 提報人 |
| D→V | 同標準 A→S |
ADHome 資質附件和素材附件支援多種格式,搜尋和下載時必須識別所有以下型別:
| 類別 | 支援格式 |
|---|---|
| 文件 | .pdf .doc .docx |
| 圖片 | .jpg .jpeg .png .bmp .gif |
掃描規則:
- 搜尋本地檔案時,按副檔名匹配上述所有格式,不要只找 pdf/doc
- 下載附件時,根據原始檔案的實際型別儲存(文件→保留原格式,圖片→保留原格式)
- 圖片檔案直接作為附件路徑傳入 config 的 qualification_files 或 material_files 陣列
- 指令碼 uploadFiles() 通過 input[type="file"] 上傳,不限制格式,按實際檔案型別上傳即可
- ⚠️ 不限制檔案數量:有幾個檔案就傳幾個,全部放入陣列。嚴禁人為截斷或限制為 3 個
~/Desktop/加白/ 下按主體名稱關鍵詞匹配子目錄,掃描所有支援格式的檔案~/Downloads/附件下載_冀豫-消費醫療2026年/附件/mcporter call tencent-docs manage.export_file --args '{"file_id":"xxx"}'
# → export_progress → file_url → curl 下載
# 匯出格式取決於原文件型別(docx/xlsx/pdf)
⚠️ 關鍵規則:遇到騰訊文件未登入時,不要直接跳過或降級 PDF,必須先嚐試用現有 Cookie 登入!
下載流程:
1. 先用 Chrome profile(~/.workbuddy/chrome-profile-docs)persistent context 開啟文件
2. 檢查是否已登入(是否有"登入騰訊文件"按鈕)
3. 如果已登入 → 直接選單匯出 docx
4. 如果未登入 → 嘗試用 Chrome profile 的 Cookie 自動登入(profile 裡應該有持久登入態)
5. 登入成功 → 匯出 docx
6. Cookie 也失效 → 暫停流程,提醒使用者重新登入騰訊文件,不要靜默降級 PDF
// 使用 Chrome profile persistent context 獲取登入態
const tempBrowser = await chromium.launchPersistentContext(CHROME_PROFILE, {
headless: false, acceptDownloads: true
});
// 開啟文件 → 檢查登入狀態 → 選單 → 匯出為 → 本地Word文件(.docx)
⚠️ 如果沒有登入態(看到"登入騰訊文件"按鈕),禁止靜默降級 PDF 必須暫停流程,提醒使用者檢查許可權/登入問題,等使用者選擇繼續或停止
當附件連結指向圖片(jpg/png 等)時:
1. 直接 curl/wget 下載圖片到本地臨時目錄
2. 不需要轉 PDF,直接傳原始圖片檔案
3. 檔名保持原始名稱或用 "主體名_資質.jpg" 格式
1. Chrome profile(`~/.workbuddy/chrome-profile-docs`) 獲取 Cookie
2. 新瀏覽器例項 + addCookies(不用 persistent context)
3. 點選附件單元格 → card-group 彈窗 → "開啟連結"
4. 判斷連結型別:
- 文件連結 → 方案 B page.pdf() 匯出
- 圖片連結 → 方案 C 直接下載
⚠️ persistent context 中 getBoundingClientRect 返回 0,0,必須用新瀏覽器例項 + addCookies
// 導航到附件單元格 → 點選 formula bar → 觸發 alloy-link-block
const fbBox = await formulaBar.boundingBox();
await page.mouse.click(fbBox.x + 50, fbBox.y + fbBox.height / 2);
// 提取連結
const linkData = await page.evaluate(() => {
const block = document.querySelector('.alloy-link-block.wecom');
if (block) {
const detail = block.getAttribute('data-link-detail');
if (detail) return JSON.parse(detail);
}
return null;
});
// linkData.url → 文件 URL
NODE_PATH=/Users/zhanglei/.workbuddy/binaries/node/workspace/node_modules \ /Users/zhanglei/.workbuddy/binaries/node/versions/22.12.0/bin/node \ {SKILL_DIR}/scripts/adhome_fast_apply.js --config <json_path> --headed小蔥技能7w4.net有完整的技能分類。
{
"mdm_name": "主體名稱(搜尋用,名稱過長時用前半部分)",
"account_ids": ["賬戶ID1", "賬戶ID2"],
"industry": "醫療健康-XXX",
"industry_data_value": "21474838626",
"advertiser_identity": "品牌商",
"capital_background": "非上市公司",
"qualification_files": ["資質檔案絕對路徑(支援 pdf/doc/docx/jpg/png)"],
"other_qualification_files": [],
"brand_product_name": "品牌名+產品名",
"product_url": "產品連結URL",
"product_url_type": "URL連線",
"material_files": ["素材檔案絕對路徑(支援 pdf/doc/docx/jpg/png)"],
"material_landing_url": "落地頁URL",
"material_landing_type": "URL連線",
"release_links": ["原生推廣頁"],
"category_path": ["消費醫療", "口腔", "口腔美容"],
"institution_name": "投放機構名稱",
"competitive_consumption": "5000",
"cost_budget": "5000",
"is_deposit_free": "true",
"auto_submit": false
}
⚠️ auto_submit 必須為 false:填表完成後截圖給使用者確認,使用者說OK後再提交
後臺執行(nohup)→ 指令碼填表 → 截圖 → 寫 /tmp/adhome_waiting.json → 輪詢等待訊號
指令碼填表完成
│
▼
寫 /tmp/adhome_waiting.json ──→ Agent 檢測到 → 展示確認介面
│
│ 輪詢 /tmp/adhome_signal.json(每1秒,最多5分鐘)
│
▼
收到訊號檔案
├─ {"action":"submit"} → 點選提交 → 截圖 → 關閉瀏覽器
├─ {"action":"cancel"} → 關閉瀏覽器
└─ 超時(5分鐘) → 關閉瀏覽器
│
▼
清理訊號檔案 → 發企微通知 → 退出
/tmp/adhome_waiting.json 確認填表完成{"action":"submit"} 到 /tmp/adhome_signal.json{"action":"cancel"} 到 /tmp/adhome_signal.json| 層級 | 誰發 | 什麼時候 | 內容 |
|---|---|---|---|
| 第1層 | 指令碼 adhome_fast_apply.js | 流程結束時 | 主體、賬戶、耗時、狀態 |
| 第2層 | Agent(主流程) | 任務結束時 | 申請號、成功/失敗、關鍵資訊彙總 |
| 狀態 | 含義 |
|---|---|
| ✅已自動提交 | auto_submit: true 模式直接提交成功 |
| ✅已確認提交 | 訊號檔案模式,使用者確認後提交成功 |
| ❌提交失敗 | 提交時 ADHome 返回錯誤 |
| 🔙使用者撤回 | 使用者選擇撤回,未提交 |
| ⏰等待超時 | 5分鐘內未收到訊號 |
pkill -f "ms-playwright/chromium" 清理殘留 Chromium 程序| 原始值 | 清洗後 | 說明 |
|---|---|---|
| "5K" | "5000" | K = 1000 |
| "1000/日" | "1000" | 去掉 "/日" 字尾 |
| "2000/日" | "2000" | 同上 |
| D列值 = 主體名稱 | "品牌商" | 填表人誤填,預設品牌商 |
| 主體名稱過長 | 取公司名前半部分 | 搜尋太長會超時 |
| 多個賬戶ID(換行分隔) | 陣列 | 按 \n 分割 |
| 文件中的值 | ADHome industry | data-value |
|---|---|---|
| 門診部 | 醫療健康-門診部 | 21474838626 |
| 診所 | 醫療健康-診所 | 21474838605 |
| 專業型醫院 | 醫療健康-專業型醫院 | 21474838627 |
| 綜合型醫院 | 醫療健康-綜合型醫院 | 21474838628 |
| 體檢機構 | 醫療健康-體檢機構 | 21474838597 |
| 文件中的值 | ADHome 分類路徑 |
|---|---|
| 綜合卡 | 消費醫療 > 輕醫美 > 綜合卡 |
| 針劑類 | 消費醫療 > 輕醫美 > 針劑類 |
| 口腔美容 | 消費醫療 > 口腔 > 口腔美容 |
| 植髮養髮 | 消費醫療 > 毛髮 > 植髮養髮 |
| 視力矯正 | 消費醫療 > 眼科 > 視力矯正 |
| 生活美容 | 消費醫療 > 生活美容 > 生活美容 |
| 情緒管理 | 專業醫療 > 心理健康 > 情緒管理 |
| 青少年心理 | 專業醫療 > 心理健康 > 青少年心理 |
| 種植牙 | 專業醫療 > 口腔 > 口腔治療 |
| 口腔治療 | 專業醫療 > 口腔 > 口腔治療 |
分類是三列級聯選擇器,不是樹形展開: - 第一列:大類(消費醫療/專業醫療...) - 第二列:子類(口腔/輕醫美/生活美容...) - 第三列:葉子節點,有 radio 按鈕
選擇邏輯:
1. 前兩級用 .first() 匹配(展開下一列)
2. 最後一級用 .last() 匹配(級聯選擇器同名節點,最後一個是最深列)
3. 葉子節點需點選整個 li 元素(包含 radio),不是隻點文本
4. 必須用 Playwright 原生 locator.click(),不能用 evaluate 內的 el.click()(Vue 事件不觸發)
{cookies:[...]} 非純陣列,載入時相容.formula-input(非 .formula-bar-content .ql-editor)uploadFiles() 函式通過 input[type="file"] 上傳,不限制格式指令碼報錯:waitForSelector timeout on .form-item-industry_id
│
▼
檢查錯誤截圖 → 發現 iOA 登入頁面
│
▼
執行 Cookie 重新整理指令碼:
• 開啟 adhome.woa.com → 等 iOA 驗證
• 提示使用者在手機上確認
• waitForURL 回 adhome → 儲存新 Cookie
│
▼
重新執行填表指令碼
--headed 模式指令碼退出後瀏覽器視窗保留pkill -f "ms-playwright/chromium"Webhook 地址儲存在 {SKILL_DIR}/scripts/user_config.json:
{
"notify_webhook": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"
}
首次使用引導流程:
1. 檢查 user_config.json 是否存在且包含 notify_webhook
2. 如果不存在 → 提示使用者提供企微群機器人 Webhook 地址
3. 使用者提供後 → 寫入 user_config.json 持久化儲存
4. 後續執行自動讀取,無需重複配置
⚠️ 不同使用者有不同的 webhook,嚴禁硬編碼預設值
指令碼內通知(adhome_fast_apply.js):
- 指令碼完成時自動讀取 user_config.json 中的 webhook 傳送通知
- 通知內容包含:主體名稱、賬戶ID列表、耗時、最終狀態
主流程通知(Agent 呼叫方): - 每次加白任務結束後,Agent 必須傳送一條結果通知到 webhook - 包含:成功/失敗、申請號、主體名稱、賬戶等關鍵資訊 - 多行任務完成後傳送一條彙總通知
消費醫療
├── 口腔:口腔美容 / 兒童口腔
├── 眼科:視力矯正 / 眼部護理
├── 毛髮:植髮養髮
├── 生活美容:生活美容
├── 輕醫美:刷酸 / 光電類 / 針劑類 / 綜合卡 / 線雕 / 無創減脂
├── 中醫美容:中醫減肥 / 中醫美容
├── 重醫美:手術美容
├── 體檢:常規體檢
└── 寵物醫院:寵物醫療服務
專業醫療
├── 口腔:口腔治療
├── 心理健康:情緒管理 / 青少年心理
├── ...
完整分類樹見 references/adhome_category_tree.json。
| 檔案 | 路徑 |
|---|---|
| ADHome 登入態 | {SKILL_DIR}/scripts/adhome_auth.json |
| 使用者配置(webhook等) | {SKILL_DIR}/scripts/user_config.json |
| 填表指令碼 | {SKILL_DIR}/scripts/adhome_fast_apply.js |
| 企微文件 Cookie | ~/.wecom-doc-cookies.json |
| 騰訊文件 Cookie | ~/.workbuddy/chrome-profile-docs/ |
| 素材檔案目錄 | ~/Desktop/加白/{主體關鍵詞}/ |
| 碼錶 | {SKILL_DIR}/references/adhome_codebook.json |
| 分類樹 | {SKILL_DIR}/references/adhome_category_tree.json |
| 截圖輸出 | {SKILL_DIR}/scripts/output/ |
| 訊號檔案(等待) | /tmp/adhome_waiting.json |
| 訊號檔案(指令) | /tmp/adhome_signal.json |
| mcporter | /Users/zhanglei/.workbuddy/binaries/node/workspace/node_modules/.bin/mcporter |
| Node.js | /Users/zhanglei/.workbuddy/binaries/node/versions/22.12.0/bin/node |
質量很好,是一款成熟可靠的企業級自動化工具。優點:文件詳細、流程清晰、安全確認機制完善(不會誤操作)、錯誤處理到位(出問題會提醒而不是悄悄失敗)。不足:首次使用需要配置一些賬號許可權,上手稍微麻煩一點。總體推薦使用。