Jun.

記事は繁体字中国語で書かれています。

AI BLOG
2026-09-15プロジェクト振り返り

PlurkPost 代購發文工具複盤

PlurkPost 代購發文工具複盤 封面

一家代購店在噗浪,也就是台灣常用的微網誌上開團,每一團都要把日本官網的商品資料照固定格式手抄成一整串貼文。

這個內部工具讓人貼上商品網址就排好整串貼文,已上線給店裡少數幾個人共用。這篇隨進度更新。

貼文格式照舊貼文反推,排版交給模板

每一團的貼文結構都一樣,所以我把發成功的舊貼文讀回來當標準答案,排版做成固定模板,填不出來的欄位留下醒目的空格。

噗浪每則上限 360 字,但舊貼文有幾則超過還是發得出去,代表網址另有固定算法。拿這些貼文回推,每個網址最多算 38 字;官方沒寫這條,哪天被退回再往下修。

note技術細節:模板欄位與字數常數

兩篇實際貼文透過 Plurk API 取 content_raw 整理成 docs/POST-FORMATS.md:主文放主圖與截止日,回文依序是注意事項、運費、商品樓;自訂表情為 [花] 這類方括號名稱,連結格式是 URL (顯示文字),qualifier 為 :。 模板定義在 data/canned-texts.jsontemplate.fields,罐頭文以 {{欄位}} 引用;auto 自動帶入,required 空白時輸出 ⟨欄位名⟩ 佔位符,whenwhenEquals 控制條件欄位。 商品樓自動排版,超過 10 張圖或 360 字就換樓,模仿實際貼文「單圖商品併樓」的做法。 字數常數 PLURK_LINK_LEN = 38,受「純文字 50 字+8 個圖片網址」那樓限制:50 + 8 × 38 = 354 ≤ 360。 舊值 45 只算圖片網址、一般網址算原長,會把宣傳連結樓誤判超限。

會造成損失的錯在送出前擋下,其他只提醒

代購最怕收單截止打錯:寫成昨天,或晚於官方停止受理,客人下了單卻買不到。這類錯和沒填的空格在送出前一律擋下;匯率不在常見範圍、商品名還是日文,只跳提醒。

note技術細節:發布前檢查

擋下:內文仍有 ⟨…⟩、收單截止早於今天、收單截止晚於官方受注締切(取自商品詳細頁的 orderDeadline)、單樓超過 360 字或 10 張圖。 提醒:距官方締切不到 2 天、匯率不在 0.15~0.35、通販境內運為 0、 商品行含日文假名。

測試帳號只能發私人貼文,這條鎖在伺服器

工具同時接著測試帳號和正式帳號。測試帳號發的文一律只有自己看得到,這條寫在伺服器端,畫面上選了公開也照樣改掉。

噗浪的隱私欄位填 0 代表「所有朋友可見」,「只有我」要填自己的帳號編號。這個差別只有把發出去的文讀回來才看得到,所以驗收一律從平台讀回貼文的實際設定。

note技術細節:本人限定的正確寫法

PLURK_ACCOUNT=testapplyPrivacyPolicy() 忽略前端設定,固定送 limited_to=[owner_id]/api/publish-all/api/post-plurk 都套用。 owner_idUsers/me 取得並依 token 快取;取不到就中止發布回 500,不退回 [0]。 Plurk 的 [0](API 讀回 |0|)是所有朋友可見,網頁前端的「只有我」送的是 [自己的 user_id];修正後讀回 |owner_id|。 前端「本人限定」仍送 [0],由伺服器轉換。

只存幾組金鑰,不值得多養一個資料庫

工具唯一要長期保存的,是登入噗浪用的幾組金鑰。為幾個字串多接一個資料庫,就多一個服務要顧,免費方案閒置太久還會被暫停。所以金鑰直接放進主機的環境設定,整套架在不綁卡的免費方案上,主機設在離日本商店近的東京。

note技術細節:Vercel Hobby 部署

考慮過 Railway(需月費)、Vercel + Supabase(免費專案閒置 7 天暫停)、Firebase(Functions 要 Blaze 方案綁卡),最後採 Vercel Hobby,token 放環境變數。 Express 改 module.exports = app,直接執行才 listenapi/index.js 為入口,vercel.jsonregions: ["hnd1"]maxDuration: 300。 函式沒有可寫的檔案系統:OAuth request token 改放 10 分鐘 httpOnly cookie;/callback 在正式站不寫檔,改顯示 token 請管理者貼進環境變數後重新部署。 密碼登入在 lib/auth.js,HMAC 簽章 cookie,/api/*/auth/* 無 cookie 回 401;/api/proxy-image 限白名單網域,避免變成開放代理。 東京節點實測:各站爬蟲本機與正式站結果一致,沒有一站擋海外 IP。

商店隨時改版,所以壞掉要能一鍵回報

工具靠爬蟲,也就是自動去商店網頁抄商品資料的小程式,每家店各一支,對方一改版就壞。所以擷取失敗時畫面會出現「回報」按鈕,按下就記進共用的 Google 試算表。

回報要有人按才記,因為網路一時不穩也會失敗,自動記錄只會灌出假警報。累積的回報能匯出成給 AI 讀的待辦清單,每筆附上對應的爬蟲,一次修完。

flowchart LR
  A[商店網站改版] --> B[擷取失敗]
  B --> C[有人按下回報]
  C --> D[記進共用試算表]
  D --> E[匯出待辦清單]
  E --> F[交給 AI 修對應的爬蟲]
note技術細節:爬蟲註冊表與維護看板

每支爬蟲 export { name, homepage?, match(url), fetch(url), fetchDetail?(url) }scrapers/index.js 依網址比對挑選;專用站必須排在通用的 shopify.js 之前。 回傳格式寫成契約記在 CLAUDE.md:單品 fetch() 回扁平 { title, images:string[] }fetchDetail()images[{ key, url }];格式不合會在前端破圖或報 data.images is not iterable。 看板存 Google Sheets:lib/sheets.js 以服務帳號 JWT 呼叫 REST,簽章用 Node 內建 crypto,不裝 googleapis;寫入一律 valueInputOption=RAW,防止 = 開頭的輸入被當成公式。 本機測試走同介面的 lib/sheets-memory.js;看板 API 失敗回 502/503,不影響發文。 匯出為純文字,每筆附「比對:scrapers/xxx.js」,只命中通用 Shopify 時標「通用」,比對不到寫「無(網域)」。

發文已上線,訂單管理還沒動工

下一步是讓 AI 把日文商品名翻成中文,目前每件都手動改。排版仍交給模板,AI 產出的格式每次可能不一樣。

規劃中的後半段還沒開始:自動登記開團、讀留言整理訂單、自動回覆客人。正式帳號的專屬表情符號尚未驗證,最新一批爬蟲修正也還沒有正式站驗收紀錄。

note技術細節:待辦

MVP-2(計畫中):POST /api/translate 批次翻譯,Gemini structured output 強制回傳 [{ id, zh }];譯名品質靠系統提示、data/glossary.json 詞彙表與翻譯快取三層,SDK 版本與模型名實作時再查證。 ROADMAP MVP-3~5:發文成功寫入 Sheets 開團紀錄、輪詢 Responses/get 由 AI 解析喊單、responseAdd 自動回覆;看板的 lib/sheets.js 會直接沿用。 改善項:/api/publish-all 目前一次跑完,改為前端逐步呼叫(上傳圖 → 主文 → 各回文),失敗可從斷點續發。 Hobby 排程每日只能跑 1 次,MVP-4 的留言輪詢要另找做法。

相關

AI BLOG に戻る