glowup-review-pipeline
驅動 Glow Up 美妝評論網站的完整資料管線——從 Threads/Google/小紅書抓評論,到用 Claude Code 本身當 LLM 做語言理解標記、Python 做加權計算,產出可重現的評分 CSV。務必在使用者提到「更新評分」「抓新資料」「跑評分」「幫我評分」「新增了XX小紅書/Threads/Google資料」「這個品項評分」或提到 route_reviews.py/score_
SKILL.md.claude/skills/glowup-review-pipeline/SKILL.md
GitHubGlow Up 評論管線
這是一個多步驟、有明確順序的資料管線技能。不要跳步驟——每一步都是因為踩過真實的坑 才加進來的(詳見「已知地雷」),跳過會導致資料錯置或分數被誤覆蓋。
先讀這兩份專案文件,它們是權威來源,本檔不重複內容
../../../CLAUDE.md——專案現況、資料夾結構、API Key 清單、 「已知問題/待辦」。開始任何工作前先讀,尤其是文件開頭的「目前資料狀態」區塊(了解現在 有多少品項已評分)。../../../SKILL_商品評比.md——完整評分方法論:LLM 怎麼標記每則評論(商品身份比對、業配偵測三層篩查、情緒強度七級、可信度三級)、Python 怎麼把標記轉成分數(加權平均、共識度修正、雙軌加權、兩極化偵測)。評分相關的所有規則 細節都在這份文件,不要自己發明新的判斷邏輯。
⚠️ 這份方法論文件描述的是「理想設計」,
score_reviews.py目前的實作大部分已對齊 (共識度修正、雙軌高頻加權、負評可信度保護規則都已補齊),但情緒換算分與可信度權重的 「數值」是刻意重新校準過的(程式碼裡有註解說明),跟文件裡 Step 3.4/4.1 表格寫的原始 數字不同——這是有意的調整,不是 bug,兩邊數值不必強求一致。真的要確認實際數值以score_reviews.py檔案開頭的SENTIMENT_SCORE/CREDIBILITY_WEIGHT常數為準。
六步驟總覽
Step 1 在 csv/Items.csv 把要更新的品項 "Update This Time" 欄填 "yes"
Step 2 跑爬蟲:Threads + Google 自動化;小紅書半手工(存 HTML → parse_xhs.py 匯入)
Step 2.5 圖上心得補救:檢查有沒有「心得寫在圖片裡」的貼文(見下方章節,每次有新資料都要查)
Step 3 clean_data.py 清洗廣告
Step 4 多品項拆分與歸位路由:route_reviews.py(LLM兩段式)或 route_xhs_programmatic.py(小紅書單品牌資料夾捷徑)
Step 5 審核 csv/候選新品.csv,決定要不要收編新品項
Step 6 評分:score_reviews.py(LLM兩段式,Claude Code 自己扮演標記者)
以下逐步展開;每一步該跑哪個指令、輸出去哪裡,CLAUDE.md 的「工作流程」章節有完整指令
區塊可以直接照抄,這裡只講「為什麼」跟容易出錯的地方。
Step 1-2:標記待更新品項、抓資料
scrape_threads.py/test_google.py 是全自動的,.env 裡的 key 沒過期就能直接跑。
小紅書是半手工:使用者存 HTML 到 小紅書美妝貼文/{子分類}/{品牌資料夾}/,然後跑
parse_xhs.py {子分類...}(或 --all)匯入。這一步是冪等的(依 URL 去重),重跑不會
重複匯入,所以可以放心多跑幾次確認有沒有新檔案進來。
注意檢查:新增的小紅書資料夾有沒有不小心巢狀放錯位置(例如把「眼霜」子分類的資料夾整個 搬進「面膜」資料夾底下)——如果真的看到某個資料夾底下有跟資料夾名稱完全對不上的品牌 子資料夾,先確認過再匯入,不要讓錯置的資料污染到不相關的子分類。
Step 2.5:圖上心得補救(每次有新資料都要檢查一次,不是一次性)
背景:有些貼文的心得是寫在圖片裡而不是貼文本文(小紅書長圖文、Threads 截圖轉發都 發生過),爬蟲/parse_xhs.py 抓不到圖片裡的文字,該則評論看起來內容很短甚至空白,但圖片 裡才是真正的心得,直接漏掉等於少了一部分真實聲音。這是每次有新資料就該檢查的標準動作, 不是只在遇到特定子分類時才做一次的例外處理。
小紅書(前提:貼文是用瀏覽器「完整網頁」存檔,該篇旁邊會多一個 {檔名}_files/
資料夾):
python3 extract_xhs_images.py 子分類A 子分類B(或--all)→ 掃有_files/的貼文, 濾掉頭像/icon,把內容大圖轉成 png,產出llm_io/xhs_image_manifest.json- 由你(Claude Code)逐張 Read manifest 內的 png,把圖上文字抄出來,寫成
llm_io/xhs_image_texts.json(格式:{url: 圖片內文}) python3 merge_xhs_image_text.py→ 把圖片內文接回三份 reviews json 的content欄位(冪等、可重跑,標記image_review: true)- 之後 Step 6 評分時,這些補回的內文才會真正被讀到。
Threads:目前沒有對應的自動抽取工具(Threads 沒有「完整網頁存檔含原圖資料夾」這個
管道)。若發現某則 Threads 評論內容異常短/空白但明顯附了截圖,手動打開原始連結把圖片裡
的文字抄進該筆記錄的 content 欄位,格式比照 merge_xhs_image_text.py 的
【圖片內文】 marker 寫法。這是已知的工具缺口——如果之後這類 Threads 貼文量大到需要
自動化,可以參考小紅書那套三段式流程另外做一版。
Step 3:清洗
python3 clean_data.py——過濾業配/廣告,輸出 cleaned_reviews.json。沒有需要注意的坑。
Step 4:多品項拆分與歸位路由
一篇貼文常常同時講多款商品,需要先拆分再歸位到正確的品項,評分才不會把 A 商品的評論 混進 B 商品。兩條路徑,依情況選:
route_reviews.py(LLM 兩段式,處理多品項/不確定的情況):--prepare --subcat 子分類A,子分類B產出llm_io/route_requests.json→ 由你讀取、 逐則拆分並比對商品目錄、寫出llm_io/route_responses.json→--compute產出routed_reviews.json+csv/候選新品.csv。目錄裡有對應的品項才會被歸位,目錄外的 新品只會被暫存到候選新品清單,不會自動收編、不會被評分——這是刻意設計,避免亂長品項。- ⚠️
route_reviews.py只處理小紅書貼文(設計如此,Threads/Google 一律原樣通過不拆分)。 如果加了新的子分類,記得檢查route_reviews.py裡的FOLDER_TO_SUBCAT對照表有沒有 登記這個子分類的小紅書資料夾名稱——沒登記會直接找不到任何待拆分貼文(0則),這個坑 已經真的踩過一次(面膜/面霜當時漏登記)。
- ⚠️
route_xhs_programmatic.py(程式化捷徑,免 LLM,只適用單一品牌資料夾):小紅書 貼文如果已經放在「單一品牌」的子資料夾(不是「多品項XXX評比」這種混合資料夾),品牌 名稱明確,不需要 LLM 拆分,直接依資料夾開頭品牌名比對Items.csv補上item_id更快。 用法:python3 route_xhs_programmatic.py 子分類A 子分類B。跟route_reviews.py是 互補關係,不是取代——多品項/評比類資料夾這支腳本會自動跳過,交給route_reviews.py處理。
score_reviews.py 找不到 routed_reviews.json 時會自動退回舊的 cleaned_reviews.json
- keyword 比對,向後相容,但比對會比較粗(見「已知地雷」的雜訊問題)。
Step 5:審核候選新品
打開 csv/候選新品.csv,人工確認哪些是真的要收錄的新品項,手動補進 Items.csv,再重跑
Step 4 讓新加入的品項也能被歸位。這一步沒有自動化,是刻意要有人把關。
Step 6:評分
--prepare --subcat 子分類A,子分類B 產出 llm_io/score_requests.json → 由你(Claude Code)
逐則標記(見下方「標記時的角色」)、寫出 llm_io/score_responses.json → --compute 算分。
標記時的角色:你就是 SKILL_商品評比.md 裡說的「LLM」,負責純語言理解——商品身份
比對(是不是同一個商品/系列/規格)、業配偵測、子款識別(sub_variant)、情緒強度標記、
可信度判斷。不要自己心算分數——加權平均、共識度修正、兩極化偵測全部是 Python
(score_reviews.py)做的計算,你只需要老老實實輸出結構化標記,讓分數可重現。
已知地雷(每一條都真實發生過,不是理論風險)
score_reviews.py --compute沒有--subcat參數,永遠重算全部 430 個品項。 若score_responses.json只包含本輪新標記的子分類,其餘沒被標記到的品項的product_key不在檔案裡,程式碼會直接跳過(保留 CSV 裡的舊分數),理論上不會被清空 ——但這個保護是後來加的修正,每次跑完--compute還是要親自比對新舊csv/AI_Scores.csv的Subcategories欄位去重清單有沒有無故消失,發現不對馬上停手排查,不要接著跑build_scores_data.py(會把錯誤傳播到前台)。這是實際發生過一次的資料遺失事故 (2026-07-21,靠 Time Machine 復原),養成每次跑完就 diff 一下子分類清單的習慣。 建議先cp csv/AI_Scores.csv csv/AI_Scores.csv.bak_<說明>再跑--compute。Python 版本:
route_reviews.py、score_reviews.py必須用/usr/bin/python3(3.9), PATH 上預設的 anaconda Python 3.6 不支援anthropicSDK。爬蟲/清洗腳本用哪個都可以。關鍵字比對(keyword-fallback)雜訊很多:
score_reviews.py對沒有item_id的評論 會用品牌+商品名的字串比對來抓可能相關的評論(主要是 Threads/Google 資料,因為只有小紅書 會被路由),這個比對很寬鬆,容易抓到同品牌但完全不相關的貼文(例如「M.A.C」品牌關鍵字 比對到「MacBook」的討論串)。這正是 Step 6 標記時product_match: mismatch存在的原因 ——標記時要真的讀內容判斷是不是同一個商品,不要因為它出現在候選清單裡就預設相關。小紅書資料夾容易巢狀放錯:見 Step 2 的提醒。
前台「真實網友心得」卡片目前 100% 來自小紅書,不是因為資料真的只有小紅書 (原始語料 Threads 反而佔多數),而是
build_scores_data.py的pick_testimonials()只從有item_id的評論裡選,而只有小紅書會被路由。如果要讓心得卡片的來源比例更真實, 需要調整pick_testimonials()也從已標記product_match: match的 Threads/Google 評論裡選,而不是只看有沒有item_id。route_reviews.py --compute曾經會整批洗掉「其他子分類」先前的路由結果(已修好, 但務必知道這個坑)。舊版compute()每次都只帶著「本輪--subcat」的llm_io/route_responses.json,本輪沒標記到的 rid 一律直接退回未路由的cleaned_reviews.json原始記錄(不含item_id),等於把之前任何一輪(不管是route_reviews.py的 LLM 路由,還是route_xhs_programmatic.py的程式化路由)已經 標好的item_id全部蓋掉。2026-07-28 資料遺失事故:跑完面膜/面霜的--compute後,routed_reviews.json裡粉底液(含植村秀)等所有其他子分類的item_id全部消失, 導致前台「真實網友心得」卡片全部顯示「尚無足夠社群心得資料」,連帶讓依賴pick_testimonials()的build_scores_data.py重建scores-data.json時,把手動補寫的reviewSummary(網友評價匯總)欄位也一併洗掉(build_scores_data.py本身也有份,見下)。 已修正:compute()現在會先讀舊的routed_reviews.json,本輪沒有標記到的 rid 改成 沿用舊檔裡「已路由」的版本(保留item_id),只有從未被任何一輪處理過的 rid 才退回原樣 通過,不會再互相覆蓋。但事故當下刪除評論路由備份不可逆:清理專案雜物時如果看到routed_reviews.backup_*.json這類檔案,即使看起來像過期產物,也不要因為「只留最新 一份」的原則就刪光——每一份都是不同時間點某輪路由的快照,是這個舊 bug 的唯一救命索。 建議至少保留最近 2-3 份、或每次route_reviews.py --compute前也養成cp routed_reviews.json routed_reviews.json.bak_<說明>的習慣。build_scores_data.py每次都是從csv/AI_Scores.csv+routed_reviews.json重新 算出scores-data.json,不會保留任何「額外手動補寫、不是從 CSV 算出來」的欄位—— 例如「網友評價匯總」用的reviewSummary欄位。舊版直接用data.setdefault(key, {...})建立全新模板,從來沒讀過舊檔,重建一次就把reviewSummary洗掉一次(就是上面地雷6 事故的第二個成因)。已修正:現在main()開頭會先讀舊的scores-data.json,把每個 品項的reviewSummary(如果有)原樣帶進新模板,之後才用 CSV 算分數覆蓋其餘欄位。 之後如果還要加其他「非 CSV 算出來」的手動欄位,記得比照這個做法補進保留邏輯, 不要假設重建腳本會自動保留。
完成評分後
python3 build_scores_data.py 重新產生前台用的 scores-data.json。這一步之前如果懷疑
AI_Scores.csv 有問題(見地雷1),先不要跑這步,把錯誤範圍確認清楚再繼續,避免把錯誤
傳播到前台。