本篇紀錄如何用 Telegram Bot API 透過 HTTP 傳送一般檔案.
本系列之前的文章參考 :
我將 Telegram Bot API 權杖與聊天室識別碼都存放在環境變數檔 .env 裡面, 利用 dotenv 套件載入後再用 os 模組讀取出來放在 token 與 chat_id 變數裡 :
>>> from dotenv import load_dotenv
>>> load_dotenv()
True
>>> import os
>>> token=os.environ.get('TELEGRAM_TOKEN')
>>> chat_id=os.environ.get('TELEGRAM_ID')
# load_secrets_py
from dotenv import load_dotenv
import os
load_dotenv()
token=os.environ.get('TELEGRAM_TOKEN')
chat_id=os.environ.get('TELEGRAM_ID')
參考 :
12. 利用 HTTP API 傳送一般檔案 :
Telegram Bot API 傳送一般檔案的 API 是 sendDocument, 使用 Bot 物件的話則是呼叫其 send_document() 方法. 與之前傳送多媒體 (圖片, 影片, 音訊) 可用 sendMediaGroup 類別打包後一次傳送不同的是, sendDoucumetn 或 send_document() 一次只能傳送一個文件, 如果要傳送多個文件可先壓縮成 zip 檔或使用迴圈傳送.
其次, 傳送網路檔案因為 Telegram 要去網站抓取檔案, 這時主機可能會檢查來源 IP, User-Agent 與 TLS 握手細節等原因導致下載失敗 (收到 403 或 TLS 錯誤), 所以以下測試以傳送本機為主.
(1). 使用 HTTP API 傳送檔案 :
匯入 requests 模組來處理 HTTP 請求與回應 :
>>> import requests
Telegram 傳送檔案的 HTTP API 網址格式如下 :
https://api.telegram.org/bot{TOKEN}/sendDocument
製作請求網址 :
>>> url=f'https://api.telegram.org/bot{token}/sendDocument'
製作要傳給 data 參數的字典, 必須包含 chat_id 鍵, 或可選用的 caption 與 parse_mode 鍵 :
>>> data={'chat_id': chat_id,
'caption': '*出國要帶的東西*',
'parse_mode': 'Markdown'}
然後用 open() 開啟要傳送的檔案, 我準備了一個 WORD 檔案 travellers.docx (注意, 不可以用中文檔名, 會被強制斷線), 將檔案參考傳給 files 字典的 document 鍵, 然後在呼叫 requests.post() 時將 files 字典傳給 files 參數, 這樣 requests 就會用 multipart/form-data 方式傳送檔案 :
>>> with open(file_path, 'rb') as f:
files={'document': f}
r=requests.post(url, data=data, files=files)
檢視傳回值 :
>>> r.json()
{'ok': True, 'result': {'message_id': 294, 'from': {'id': 7938146214, 'is_bot': True, 'first_name': 'twstock', 'username': 'twstock168_bot'}, 'chat': {'id': <聊天室ID>, 'first_name': '<我的名字>', 'username': '<我的 username>', 'type': 'private'}, 'date': 1744790747, 'document': {'file_name': 'travellers.docx', 'mime_type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'file_id': 'BQACAgUAAxkDAAIBJmf_ZNtPGDpz2YNbvWBJUz92Y35pAALZFgACTYwAAVQb3M1fKs1GWzYE', 'file_unique_id': 'AgAD2RYAAk2MAAFU', 'file_size': 17276}, 'caption': '出國要帶的東西', 'caption_entities': [{'offset': 0, 'length': 7, 'type': 'bold'}]}}
查看 Telegram App 有收到此 docx 檔案 :
以上測試的完整程式碼如下 :
# telegram_send_document.py
import requests
def telegram_document(token, chat_id, file_path, caption=None, parse_mode='Markdown'):
data={
'chat_id': chat_id,
'caption': caption,
'parse_mode': parse_mode
}
try:
with open(file_path, 'rb') as f:
files={'document': f}
with requests.post(url, data=data, files=files) as r:
r.raise_for_status()
result=r.json()
if result.get('ok'):
print('Message sent successfully.')
return True
else:
print(f'Telegram API Error: {result}')
return False
except Exception as e:
print(f'Request error: {e}')
return False
if __name__ == '__main__':
token='YOUR TOKEN'
chat_id='YOUR CHAT ID'
file_path='FILE PATH'
caption='THE CAPTION'
telegram_document(token, chat_id, file_path, caption)
(2). 使用 Bot 物件傳送檔案 :
上面程式可以改用 Bot 物件以非同步方式傳送, 程式碼如下 :
# telegram_send_document_bot.py
import asyncio
from telegram import Bot
from telegram.error import TelegramError
async def telegram_document(token, chat_id, file_path, caption=None, parse_mode='Markdown'):
bot=Bot(token=token)
try:
with open(file_path, 'rb') as f:
msg=await bot.send_document(
chat_id=chat_id,
document=f,
caption=caption,
parse_mode=parse_mode
)
print('Message sent successfully.')
return True
except TelegramError as e:
print(f'Telegram API Error: {e}')
return False
except Exception as e:
print(f'Request error: {e}')
return False
if __name__ == '__main__':
token='YOUR TOKEN'
chat_id='YOUR CHAT ID'
file_path='FILE PATH'
caption='THE CAPTION'
asyncio.run(telegram_document(token, chat_id, file_path, caption))
>>> async def telegram_document(token, chat_id, file_path, caption=None, parse_mode='Markdown'):
bot=Bot(token=token)
try:
with open(file_path, 'rb') as f:
msg=await bot.send_document(
chat_id=chat_id,
document=f,
caption=caption,
parse_mode=parse_mode
)
print('Message sent successfully.')
return True
except TelegramError as e:
print(f'Telegram API Error: {e}')
return False
except Exception as e:
print(f'Request error: {e}')
return False
我將之前測試圖片時的 cat1.jpg, cat2.jpg, 與 cat3.jpg 壓縮為 cats.zip : 測試如下 :
>>> file_path='cats.zip'
>>> caption='*可愛的三小貓*'
>>> asyncio.run(telegram_document(token, chat_id, file_path, caption))
Message sent successfully.
True
檢查 App 果然有收到該 zip 檔 :
沒有留言 :
張貼留言