Sly Bye

刪除一個 Telegram 機器人後,https://t.me/your_deleted_bot 仍然會回傳 HTTP 200
以及看起來完全正常的頁面。所有我所知道的連結檢查器 — CI 動作、 目錄腳本、監控 cron 工作 — 都會永久將它回報為正常。

如果您維護任何列出 Telegram 機器人的列表,您的列表中已經有部分是 已失效的,而您的檢查卻告訴您一切正常。

重現步驟

選擇一個從未存在過的使用者名稱:

curl -s -o /dev/null -w "%{http_code}\n" https://t.me/nonexistent_test_bot_77712
# 200

Enter fullscreen mode Exit fullscreen mode

200 狀態碼。沒有重新導向、沒有 404、也沒有軟性 404 標記可以讓狀態檢查 捕捉到。

真相所在

狀態碼在此處毫無用處,但 Open Graph 標題則不然。我測試了四個 使用者名稱 — 兩個活躍的機器人,兩個不存在的:

URL og:title
t.me/BookClassBot (活躍) BookClass
t.me/instanavy_bot (活躍) StoryViewer - anonymous instagram story viewer tool
t.me/nonexistent_test_bot_77712 Telegram: Contact @nonexistent_test_bot_77712
t.me/zzz_definitely_not_a_real_bot_9182 Telegram – a new era of messaging

活躍的機器人會將自己的顯示名稱放入 og:title。已失效的則會取得兩種 Telegram 預留位置之一:Telegram: Contact @<username>,或者 — 如果使用者名稱甚至 在語法上無效 — 則是通用的 Telegram – a new era of messaging

這就是全部的訊號。

curl -s https://t.me/some_bot | grep -o '<meta property="og:title" content="[^"]*"'

Enter fullscreen mode Exit fullscreen mode

檢查方式

僅使用標準函式庫,無需相依套件:

import re
import urllib.request

UA = "Mozilla/5.0 (compatible; linkcheck/1.0)"

DEAD_EXACT = {"Telegram – a new era of messaging", "Telegram"}
DEAD_PREFIX = "Telegram: Contact @"


def telegram_bot_exists(url: str) -> bool:
    """True if the bot behind a t.me URL still exists.

    HTTP status is not usable here: Telegram serves 200 with a placeholder page
    for usernames that were deleted or never existed. The Open Graph title is
    what actually differs.
    """
    req = urllib.request.Request(url, headers={"User-Agent": UA})
    with urllib.request.urlopen(req, timeout=20) as resp:
        html = resp.read(200_000).decode("utf-8", "replace")

    m = re.search(r'<meta\s+property="og:title"\s+content="([^"]*)"', html)
    title = m.group(1).strip() if m else ""

    if not title:
        return False
    return title not in DEAD_EXACT and not title.startswith(DEAD_PREFIX)

Enter fullscreen mode Exit fullscreen mode

請注意 Telegram – a new era of messaging 中的破折號。它是 U+2013,而不是連字號。 我因為這個浪費了幾分鐘時間。

它能應對各種 URL 變體

Mini App 會以多種形式被連結,而此檢查適用於所有形式 — 標題仍然會解析為應用程式的真實名稱:

t.me/DefyTONBot/app                            -> "DefyTON"
t.me/arena_defense_bot/arena_defense           -> "ARENA DEFENSE"
t.me/lexicon_snap_bot?startapp=cat_awesome     -> "LexiCon"
t.me/playful_mind_bot/play?startapp=cat_awesome_tma -> "Playful Mind"

Enter fullscreen mode Exit fullscreen mode

因此您可以將檢查指向任何人提交的任何 URL,而無需先將其標準化為 純使用者名稱。

為什麼要費心

因為目錄會在無聲中腐壞,而無聲的腐壞正是毀掉它們的原因。

一個所有項目都回傳 200 的機器人列表看起來像是被維護過的。每個項目都是 綠色的。與此同時,其中一部分會導向 Telegram 頁面,上面什麼也沒說,而唯一 發現這件事的人是點擊連結的讀者 — 一次,然後就再也不相信這個列表。

我在建立 Telegram Mini App 目錄時遇到了這個問題。每個項目都通過了 傳統的連結檢查。只有在加入標題檢查後,我才能說這些機器人確實存在。它現在每週在 CI 中執行,並標記任何已悄然 消失的項目。

值得一提的注意事項

  • 這取決於 Telegram 的標記,而這不是 API 合約。如果他們更改預留位置 字串,檢查就會過時。將這些字串明顯地固定在某處,並偶爾針對已知失效的使用者名稱進行測試。
  • 存在但已損壞、被封鎖或無回應的機器人仍然會通過檢查。這只告訴您 使用者名稱可以解析 — 僅此而已。
  • 請有禮貌地抓取。這是每個項目一次請求,依排程進行,而不是爬取。

通用原則

可重複使用的教訓與 Telegram 無關。重點在於 HTTP 200 意味著伺服器 有回應,而不是該項目存在。許多平台會提供裝飾過的 「這裡沒有東西」頁面,而不是 404 — 這對人類來說更好,但對所有指向它們的 自動化檢查來說更糟。

每當您在別人的平台上檢查資源時,要問的問題是:這個主機對於 確定不存在的項目會回傳什麼?先找出答案,然後再撰寫檢查。假設您從未驗證過的 404 是監控器連續數月回報綠色的原因。


這個案例出處的目錄位於 這裡 — 檢查程式位於 scripts/check.py,屬於公共領域,請自行取用。我也建立了 StoriesFly,這就是上面 Instagram 風格測試 使用者名稱的來源。