iT邦幫忙

2026 iThome 鐵人賽

DAY 28
0
AI 自動化

用 LINE Bot 和 Agent Skill 自動化整理筆記與 IG 發文系列 第 28 篇

Day 28|發布、取回 permalink、清理圖床

  • 分享至 

  • xImage
  •  

昨天把帳號和 token 都處理好了,今天終於輪到真的發文。這篇講 publish_ig.py 從頭到尾做了什麼,發完之後記錄怎麼留,最後是圖床上那些圖要怎麼清掉。

發布前的最後一眼

腳本一開始先檢查三件事:deck.json 有沒有 uploaded 網址、張數是不是 2 到 10 張、caption 加 hashtag 有沒有超過 2200 字元。這幾個 Day 25 講過,不重複。

接著它把要發的東西整段印出來:帳號、張數、字元數、完整文案,再提醒一次發布後無法編輯。然後等我打 PUBLISH。印帳號那行會先找 config 裡的 brand.handle,找不到才印 IG_USER_ID,所以 handle 有填的話,我看到的是 @帳號名稱,比一串數字好確認。

文案長這樣組:caption 後面空一行,再接 hashtag 用空格串起來。這就是之後送給 API 的 caption 全文。

三段式發布

輪播沒有「一次丟十張圖」的端點,要分三段做。

第一段:每張圖建一個 child container。 對 /{user_id}/media 發 POST,帶 image_url 跟 is_carousel_item=true。這裡不帶 caption,文件寫了帶了也會被忽略,caption 要等到第二段才給。

alt_text 是在這一段帶的。腳本會去 deck.json 的每張 slide 找 alt_text 欄位,有填就一起送,沒填就跳過。ig-api.md 說這個對無障礙有幫助、值得填。我要老實講一件事:SKILL.md 裡 deck.json 的範例 schema 並沒有列 alt_text,是腳本和 ig-api.md 有提到。所以現在是「有填會用,沒填也不會報錯」的狀態。

第二段:建 carousel 母 container。 一樣是 /{user_id}/media,這次帶 media_type=CAROUSEL、children(把剛剛拿到的 child id 用逗號串起來,順序就是輪播順序)、caption(上面那段全文)。

第三段:發布。 對 /{user_id}/media_publish 發 POST,帶 creation_id,值是母 container 的 id。這個地方文件在排查表裡特別記了一筆:如果誤把某個 child id 當 creation_id 送出去,會得到 Invalid parameter。要用的是母的。

回傳的 id 就是貼文的 media id。

container 不是建完就能用

每個 container 建完不能馬上往下,要等狀態變成 FINISHED。腳本裡的 wait_ready 每 2 秒查一次 status_code:

r = api_get(base, cid, {"fields": "status_code,status", "access_token": token})
code = r.get("status_code")
if code == "FINISHED":
    return
if code == "ERROR":
    die(f"container {cid} 處理失敗:{r.get('status')}\n"
        f"  多半是圖抓不到或格式不對,見 references/ig-api.md 排查表。")

最多等 120 秒,超過就終止並說「圖床可能太慢或圖太大」。child 每建一個就等一個,母 container 建完也等一次,全部 FINISHED 才會進到發布。

Day 26 說過,網址在上傳那一步已經驗證過了,所以這裡要是看到 ERROR,我會先懷疑圖太大或格式不對。排查表寫的建議是確認圖小於 8MB,並用 curl 看圖片網址的回應時間。

取回 permalink,寫回 deck.json

發布成功之後,腳本再對 media id 打一個 GET,只要 permalink 這個欄位:

link = api_get(base, media_id, {"fields": "permalink", "access_token": token})

然後把 media_id、permalink 和發布時間寫進 deck.json 的 published 欄位:

deck["published"] = {"media_id": media_id, "permalink": permalink,
                     "at": time.strftime("%Y-%m-%dT%H:%M:%S%z")}

這樣資料夾裡就留了一份這篇貼文的紀錄,要找連結不用回 IG 翻。SKILL.md 第 7 步也寫了,deck.json、preview.html、cards/ 都留在 ig-post-<日期>/,下次做同主題的續篇可以拿來複用。腳本最後把 media_id 和 permalink 印出來,我只要把這個連結回報給自己就收工了。

照程式碼讀,有一個縫

這段是我讀 publish_ig.py 時注意到的,實際上沒有碰過。

api_get 和 api_post 遇到 HTTP 錯誤都是直接 die()。假設 media_publish 成功了,貼文已經在 IG 上,但接下來取 permalink 剛好失敗,腳本會在那一步結束,published 不會寫進 deck.json。貼文在,紀錄沒有。

另外,腳本沒有「從中斷的地方繼續」的機制。中途失敗(例如第 6 張圖的 container 出錯),重跑就是從第一段全部重建。文件說 container 建了 24 小時沒發布就會過期,所以前面建好的不會留下來變成垃圾。

第一點的補救不難:permalink 失敗的話,去 IG 上看一眼貼文有沒有出來,有的話手動補紀錄就好。第二點也不太痛,發文額度是每 24 小時滾動 100 篇,輪播算一篇,重跑幾次不會碰到上限,ig_setup_check.py 可以查剩幾篇。

清理圖床

發完之後,圖床上的 PNG 已經沒用了。ig-api.md 跟腳本的提示都寫,IG 會留自己的副本,清掉不影響貼文。SKILL.md 的做法是發完後問我要不要清,不會自己動手。

指令是:

python3 scripts/upload_images.py --deck deck.json --cleanup

GitHub 這條路的做法,是列出 repo 裡 path 底下的檔案,把檔名以前綴開頭的每個都刪掉,最後印出刪了幾個。前綴就是 Day 26 講的那個 日期-專案slug。如果用 scp,是 ssh 過去執行 rm -f 前綴-*.png。local 這個模式不支援 --cleanup,腳本會要我自己刪。

這邊我讀程式碼時發現一個要留意的地方:前綴裡的日期是用 date.today() 算的,也就是「執行腳本當天」。所以如果是今天上傳、今天發、今天清,前綴會對上;要是隔天才跑 --cleanup,算出來的前綴日期不一樣,會找不到檔案,印出刪了 0 個。所以要清就發完當下清。真的隔天才想到,就得自己去 repo 刪。

刪檔在 GitHub 上是新增一個 commit,所以檔案在 git 歷史裡還找得到。這點 Day 26 提過,因為圖本來就是公開的,我沒有另外處理。

小結

發布是三段式:每張圖建 child container、把它們串成母 container 並帶上 caption、最後 media_publish。每一段之間要等狀態變成 FINISHED。發完用 media id 取回 permalink,連同 media id 和時間寫回 deck.json。最後問自己要不要清圖床,要清就當天清,因為前綴吃的是當天日期。

這條線走完,從教材到貼文就是通的。明天是倒數第二篇:同一套骨架換內容,拿它跟另一個 skill ig-carousel-publisher 對照,看這套規範怎麼複用。


上一篇
Day 27|IG API:帳號類型、token 取得與續期
下一篇
Day 29|同一骨架換內容:對照 ig-carousel-publisher,看規範如何複用
系列文
用 LINE Bot 和 Agent Skill 自動化整理筆記與 IG 發文 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言