今天繼續來測試 Telegram Bot API 用法, 本篇旨在探討傳送影片到 Telegram 的方法.
本系列之前的文章參考 :
我的 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')
參考 :
Telegram 雖然支援常見的 mp4/mov/avi/mkv/webm 等影片格式, 但其中以 H.264 編碼的 mp4 支援度最佳, 傳送結果最穩定, mov 格式則要視編碼與音訊格式部分支援, 至於 avi/mkv/webm 格式則不保證能順利傳送, 所以基本上還是以傳送 mp4 影片為主 (H.264 + AAC 格式).
8. 利用 HTTP 的 POST 方法傳送影片 :
首先匯入 requests 用來負責處理 HTTP 請求與回應 :
>>> import requests
Telegram Bot API 傳送影片的 HTTP 網址格式如下 :
https://api.telegram.org/bot{token}/sendVideo
定義一個嵌入 Telegram Bot 權杖的 API 網址變數 url :
>>> url=f'https://api.telegram.org/bot{token}/sendVideo'
其中嵌入變數 token 為 Telegram Bot 的權杖.
(1). 傳送網路影片 :
首先測試傳送一個網路上的 mp4 影片, 例如 samplelib.com 提供的範例影片 :
參考 :
注意, 必須是直接放在網路上, 網址是以 .mp4 結束的網址才行, Youtube 影片無法直接使用 (要先下載用本機檔案方式傳送), 因為它的連結是一個網頁網址, mp4 影片是嵌在該網頁中, Telegram 無法從網頁網址取出 mp4 網址 (因為有防爬蟲與版權保護).
接下來製作影片的 data 字典, 必須包含 chat_id (聊天室識別碼) 與 video (影片網址) 這兩個鍵, 但 caption (標題) 鍵與 parse_mode 鍵則是可有可無 :
>>> data={
'chat_id': chat_id,
'video': 'https://samplelib.com/lib/preview/mp4/sample-5s.mp4',
'caption': '範例影片'
}
>>> data
{'chat_id': '7742981072', 'video': 'https://samplelib.com/lib/preview/mp4/sample-5s.mp4', 'caption': '範例影片'}
最後呼叫 requests.post() 並將此 data 字典傳給 data 參數即可 :
>>> r=requests.post(url, data=data)
檢視傳回值裡面有關於此影片的解析度與編碼格式等資訊 :
>>> r.json()
{'ok': True, 'result': {'message_id': 154, 'from': {'id': 7938146214, 'is_bot': True, 'first_name': 'twstock', 'username': 'twstock168_bot'}, 'chat': {'id': <聊天室ID>, 'first_name': '<我的名字>', 'username': '<我的username>', 'type': 'private'}, 'date': 1744424810, 'video': {'duration': 6, 'width': 1920, 'height': 1080, 'file_name': 'sample-5s.mp4', 'mime_type': 'video/mp4', 'thumbnail': {'file_id': 'AAMCBAADGQMAA5pn-c9qwM3evHoXsPcf3ovsgwFAzAACpgcAAu6tHVKvU2k_MzPKIwEAB20AAzYE', 'file_unique_id': 'AQADpgcAAu6tHVJy', 'file_size': 29129, 'width': 320, 'height': 180}, 'thumb': {'file_id': 'AAMCBAADGQMAA5pn-c9qwM3evHoXsPcf3ovsgwFAzAACpgcAAu6tHVKvU2k_MzPKIwEAB20AAzYE', 'file_unique_id': 'AQADpgcAAu6tHVJy', 'file_size': 29129, 'width': 320, 'height': 180}, 'file_id': 'BAACAgQAAxkDAAOaZ_nPasDN3rx6F7D3H96L7IMBQMwAAqYHAALurR1Sr1NpPzMzyiM2BA', 'file_unique_id': 'AgADpgcAAu6tHVI', 'file_size': 2848208}, 'caption': '範例影片'}}
檢視 Telegram App 果然收到此影片 :
以上測試之完整程式碼如下 :
# telegram_send_web_video.py
import requests
def telegram_web_video(token, chat_id, video_url, caption=None, parse_mode='Markdown'):
url=f'https://api.telegram.org/bot{token}/sendVideo'
data={
'chat_id': chat_id,
'video': video_url,
'caption': caption,
'parse_mode': parse_mode
}
try:
with requests.post(url, data=data) 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 requests.exceptions.RequestException as e:
print(f'Request error: {e}')
return False
if __name__ == '__main__':
token='YOUR TOKEN'
chat_id='YOUR CHAT ID'
video_url='URL OF PHOTO'
caption='THE CAPTION'
telegram_web_video(token, chat_id, video_url, caption)
如果要傳送多個網路影片, 跟傳送多張圖片一樣, API 要改用 sendMediaGroup, 每個影片要與標題先打包成媒體字典放進串列中, 然後將其轉成 JSON 格式字串放進 data 字典的 media 鍵, 再把 data 字典傳給 requests.post() 的 data 參數, API 網址如下 :
https://api.telegram.org/bot{token}/sendMediaGroup
我們直接修改 "Python 學習筆記 : 用 Telegram Bot 取代 LINE Notify (三)" 中的 telegram_web_images() 函式成為如下的 telegram_web_videos() :
# telegram_web_videos.py
import requests
def telegram_web_videos(token, chat_id, media_list, caption_list):
url=f'https://api.telegram.org/bot{token}/sendMediaGroup'
media=[{
'type': 'video',
'media': media,
'caption': caption,
'parse_mode': 'Markdown'
}
for media, caption in zip(media_list, caption_list)
]
data={
'chat_id': chat_id,
'media': str(media).replace("'", '"')
}
try:
with requests.post(url, data=data) as r:
r.raise_for_status() # 若 status_code != 2xx 會拋出例外
result=r.json()
if result.get('ok'):
print('Message sent successfully.')
return True
else:
print(f'Telegram API Error: {result}')
return False
except requests.exceptions.RequestException as e:
print(f'Request error: {e}')
return False
if __name__ == '__main__':
token='YOUR TOKEN'
chat_id='YOUR CHAT ID'
video_urls=['https://yaohuang1966.github.io/media/cat.mp4',
'https://yaohuang1966.github.io/media/remind.mp4']
captions=['小喵三兄弟', '明天記得上班']
telegram_web_videos(token, chat_id, video_urls, caption)
這裡我準備了兩個放在 GitHub 上的 mp4 影片來測試 :
>>> def telegram_web_videos(token, chat_id, media_list, caption_list):
url=f'https://api.telegram.org/bot{token}/sendMediaGroup'
media=[{
'type': 'video',
'media': media,
'caption': caption,
'parse_mode': 'Markdown'
}
for media, caption in zip(media_list, caption_list)
]
data={
'chat_id': chat_id,
'media': str(media).replace("'", '"')
}
try:
with requests.post(url, data=data) as r:
r.raise_for_status() # 若 status_code != 2xx 會拋出例外
result=r.json()
if result.get('ok'):
print('Message sent successfully.')
return True
else:
print(f'Telegram API Error: {result}')
return False
except requests.exceptions.RequestException as e:
print(f'Request error: {e}')
return False
然後準備兩支影片網址與標題串列 :
>>> video_urls=['https://yaohuang1966.github.io/media/cat.mp4',
'https://yaohuang1966.github.io/media/remind.mp4']
>>> captions=['小喵三兄弟', '明天記得上班']
呼叫 telegram_web_videos() 傳送這兩張影片 (token, chat_id 已在前面用 dotenv 載入) :
>>> telegram_web_videos(token, chat_id, video_urls, caption)
Message sent successfully.
True
檢查 Telegram App 果然收到這兩個影片 :
(2). 傳送本機影片 :
傳送本機上的影片與傳送本機圖片的方法相同 (只是 API 不同, 傳送圖片是 sendPhoto, 傳送影片是 sendVideo), 都是將標題 caption 留在 data 參數中, 將影片檔另外以 files 參數傳送. 影片檔要用 open() 以 rb 模式開啟, 然後將檔案參考設為 files 參數字典中 files 鍵之值, 於呼叫 requests.post() 時把 data 與 files 傳進去即可.
參考 "Python 學習筆記 : 用 Telegram Bot 取代 LINE Notify (三)" 中的 telegram_local_image() 函式, 將其修改為如下的 telegram_local_video() :
# telegram_send_local_video.py
import requests
def telegram_local_video(token, chat_id, video_path, caption=None, parse_mode='Markdown'):
url=f'https://api.telegram.org/bot{token}/sendVideo'
data={
'chat_id': chat_id,
'caption': caption,
'parse_mode': parse_mode
}
try:
with open(video_path, 'rb') as f:
files={'video': 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 requests.exceptions.RequestException as e:
print(f'Request error: {e}')
return False
if __name__ == '__main__':
token='YOUR TOKEN'
chat_id='YOUR CHAT ID'
video_path='VIDEO FILE PATH'
caption='THE CAPTION'
telegram_local_video(token, chat_id, video_path, caption)
此例 data 字典中僅攜帶聊天室 ID (chat_id) 與影片標題 (caption), 影片檔案參考則是放在 files 字典的 files 鍵裡面, 整個架構與傳送本機圖片一樣, 只是 API 改為 sendVideo 而已.
>>> def telegram_local_video(token, chat_id, video_path, caption=None, parse_mode='Markdown'):
url=f'https://api.telegram.org/bot{token}/sendVideo'
data={
'chat_id': chat_id,
'caption': caption,
'parse_mode': parse_mode
}
try:
with open(video_path, 'rb') as f:
files={'video': 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 requests.exceptions.RequestException as e:
print(f'Request error: {e}')
return False
我將上面 GitHub 中的貓咪影片下載到本機工作目錄下的 cat.mp4, 測試如下 :
>>> video_path='cat.mp4'
>>> caption='小喵三兄弟'
>>> telegram_local_video(token, chat_id, video_path, caption)
Message sent successfully.
True
檢視 Telegram App 果然收到此影片 :
傳送多個媒體不論是網路或本機都是使用 sendMediaGroup API, 網址格式如下 :
https://api.telegram.org/bot{token}/sendMediaGroup
傳送本機影片的程式架構與傳送多個本機圖片一樣, 也是使用 open() 逐一開啟影片檔, 然後將這些檔案參考與其標題打包成 multipart 媒體字典串列後傳給 requests.post() 的 files 參數送出. 下面直接拿 "Python 學習筆記 : 用 Telegram Bot 取代 LINE Notify (三)" 這篇中用來傳送本機多個圖片檔的 telegram_local_image() 函式來修改為如下的 telegram_local_video() :
# telegram_send_local_video.py
import requests
def telegram_local_videos(token, chat_id, media_list, caption_list):
url=f'https://api.telegram.org/bot{token}/sendMediaGroup'
files={} # 儲存檔案參考的字典
media=[] # 儲存 media 字典串列
for i, video_path in enumerate(media_list): # 將檔案
key=f'media{i+1}' # 製作 files 字典的鍵 'media#'
f=open(video_path, 'rb') # 開啟檔案
files[key]=f # 將檔案參考存入 files 字典
item={ # media 字典的項目
'type': 'video',
'media': f'attach://{key}'
}
if i < len(caption_list): # 若有對應的 caption,則加入
item['caption']=caption_list[i] # 加入 caption 鍵
media.append(item) # 將媒體字典加入 media 串列
data={ # 製作 data 參數值
'chat_id': chat_id,
'media': str(media).replace("'", '"') # JSON 字串格式
}
multipart={ # 製作 multipart 參數值
k: (f.name, f, 'video/mp4') for k, f in files.items()
}
try:
with requests.post(url, data=data, files=multipart) as r:
r.raise_for_status() # 若 status_code != 2xx 會拋出例外
result=r.json()
if result.get('ok'):
print('Message sent successfully.')
return True
else:
print(f'Telegram API Error: {result}')
return False
except requests.exceptions.RequestException as e:
print(f'Request error: {e}')
return False
finally: # 關閉檔案避免資源泄漏
for f in files.values():
f.close()
if __name__ == '__main__':
token='YOUR TOKEN'
chat_id='YOUR CHAT ID'
video_paths=['cat.mp4', 'remind.mp4']
caption=['小喵三兄弟', '記得明天要上班']
telegram_local_videos(token, chat_id, video_paths, caption)
其中黃底色部分就是修改之處, 可見只是將 media 字典的 type 鍵之值改為 video, 而 multipart 字典的媒體格式改為 video/mp4 如此而已.
我將上面 GitHub 中的貓咪與唐伯虎點秋香影片下載到本機工作目錄下的 cat.mp4 與 remind.mp4, 測試如下 :
>>> def telegram_local_videos(token, chat_id, media_list, caption_list):
url=f'https://api.telegram.org/bot{token}/sendMediaGroup'
files={} # 儲存檔案參考的字典
media=[] # 儲存 media 字典串列
for i, video_path in enumerate(media_list):
key=f'media{i+1}' # 製作 files 字典的鍵 'media#'
f=open(video_path, 'rb') # 開啟檔案
files[key]=f # 將檔案參考存入 files 字典
item={ # media 字典的項目
'type': 'video',
'media': f'attach://{key}'
}
if i < len(caption_list): # 若有對應的 caption 則加入
item['caption']=caption_list[i] # 加入 caption 鍵
media.append(item) # 將媒體字典加入 media 串列
data={ # 製作 data 參數值
'chat_id': chat_id,
'media': str(media).replace("'", '"') # JSON 字串格式
}
multipart={ # 製作 multipart 參數值
k: (f.name, f, 'video/mp4') for k, f in files.items()
}
try:
with requests.post(url, data=data, files=multipart) as r:
r.raise_for_status() # 若 status_code != 2xx 會拋出例外
result=r.json()
if result.get('ok'):
print('Message sent successfully.')
return True
else:
print(f'Telegram API Error: {result}')
return False
except requests.exceptions.RequestException as e:
print(f'Request error: {e}')
return False
finally: # 關閉檔案避免資源泄漏
for f in files.values():
f.close()
測試結果 :
>>> video_paths=['cat.mp4', 'remind.mp4']
>>> captions=['小喵三兄弟', '記得明天要上班']
>>> telegram_local_videos(token, chat_id, video_paths, captions)
Message sent successfully.
True
查看 API 果然收到這兩個影片 :
沒有留言 :
張貼留言