Telegram API调用遇Bad Request错误,内嵌链接发送失败求解决
解决Telegram API发送内嵌链接时的Bad Request错误
问题根源分析
你遇到的Bad Request: can't parse inline keyboard Markup Json object错误,主要由以下代码问题导致:
1. 链接变量引用错误
代码中把链接变量link_写成了字符串字面量"link_",这会导致Telegram API收到无效URL,同时破坏JSON结构的合法性。
2. Reply Markup未序列化为JSON字符串
Telegram API要求reply_markup参数必须是JSON格式的字符串,直接传递Python字典会导致API无法正确解析。
3. 循环内键盘结构重复累加
在循环中每次都往inline_keyboard列表添加按钮,导致后续消息的键盘包含之前所有新闻的按钮,不符合单条消息对应单个按钮的预期。
4. 代码缩进错误
try块的缩进不正确,会引发语法错误,导致代码逻辑异常。
5. MarkdownV2特殊字符未转义
使用parse_mode: MarkdownV2时,caption中的特殊字符(如_、*、[等)需要转义,否则会触发格式错误。
修复后的完整代码
import requests from bs4 import BeautifulSoup import json NEWS_URL = "https://www.iflscience.com/latest" TELEGRAM_API_URL = f"https://api.telegram.org/bot{TELEGRAM_TOKEN}/" CHAT_ID = "你的聊天ID" # 替换为实际聊天ID headers = {} # 补充你的请求头 def scrape_science_news(): response = requests.get(url=NEWS_URL, headers=headers) if response.status_code == 200: soup = BeautifulSoup(response.content, "html.parser") news_items = [] card_list = soup.find_all("div", attrs={"class": "card list-card"}) for card in card_list[:3]: card_tbn = card.find("div", attrs={"class": "card-thumbnail"}) card_img = card_tbn.picture.source.next_element.attrs["srcset"] card_content_h = card.find("div", attrs={"class": "card-content--header"}) card_header = card_content_h.a.span.string card_content_b = card.find("div", attrs={"class": "card-content--body"}) card_title = card_content_b.a.h3.string card_link_h = card_content_b.a.attrs["href"] news_items.append({ "card_img": card_img, "card_header": card_header, "card_title": card_title, "card_link": card_link_h }) return news_items def escape_markdown_v2(text): """转义MarkdownV2的特殊字符""" special_chars = r'\_*[]()~`>#+-=|{}.!' return ''.join(f'\\{c}' if c in special_chars else c for c in text) def send_news_to_telegram(news_items): for item in news_items: img_ = item["card_img"] header_ = item["card_header"] title_ = item["card_title"] link_ = item["card_link"] # 每条消息单独创建键盘,避免累加 inline_keyboard = [ [{"text": title_, "url": link_}] ] inline_keyboard_markup = json.dumps({"inline_keyboard": inline_keyboard}) # 转义caption中的特殊字符 message = f"{escape_markdown_v2(header_)}\n\n" try: news = { "photo": img_, "caption": message, "parse_mode": "MarkdownV2", "reply_markup": inline_keyboard_markup, "disable_web_page_preview": True, "chat_id": CHAT_ID } response = requests.post(TELEGRAM_API_URL + "sendPhoto", data=news) if response.status_code == 200: with open("islog.txt", 'a') as file: file.write(f"{title_}\n") else: print(response.text) except UnicodeError: pass def main(): news_items = scrape_science_news() send_news_to_telegram(news_items) if __name__ == "__main__": main()
关键修复说明
- 修正链接变量:将
"url": "link_"改为"url": link_,正确引用实际链接。 - 序列化Reply Markup:使用
json.dumps()将键盘字典转换为JSON字符串,符合API要求。 - 独立构建键盘:在循环内为每条消息单独创建
inline_keyboard列表,避免按钮累加。 - 修复缩进错误:调整
try块的缩进,确保代码语法正确。 - 添加MarkdownV2转义:新增
escape_markdown_v2函数,转义caption中的特殊字符,避免格式错误。
内容的提问来源于stack exchange,提问作者Bolarin Samuel
相关产品推荐
相关产品推荐

