You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Telegram API的telegram.error.BadRequest网页内容类型错误?

问题

我在PythonAnywhere服务器部署了一个Telegram天气机器人,支持返回2小时、24小时、4天三种天气预报。机器人调用新加坡政府天气API获取数据,整理为pandas DataFrame后保存为PNG图片,计划通过update.message.reply_photo(response)将图片发送给用户,其中response是PythonAnywhere上图片的HTTPS链接。本地运行时使用本地文件路径可正常工作,但在PythonAnywhere使用URL时出现telegram.error.BadRequest: Wrong type of the web page content错误,我怀疑是图片需要登录PythonAnywhere才能访问,请求协助解决该问题。

我的脚本:

import requests
import pandas as pd
import json
from typing import Final
from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes
import df2img

BOT_TOKEN: Final = <purposely_masked_out>
BOT_USERNAME: Final = <purposely_masked_out>

async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text('Hi! You can check the SG weather by typing \'2 hours\', \'24 hours\' or \'4 days\'')

def handle_response(text: str) -> str:
    # 2 hours weather data extraction
    if '2 hours' in text:
        two_r = requests.get('https://api.data.gov.sg/v1/environment/2-hour-weather-forecast').json()
        two_df = pd.DataFrame(columns=['area', 'forecast'])

        for i in range(len(two_r['items'][0]['forecasts'])):
            two_df.loc[i] = [(two_r['items'][0]['forecasts'][i]['area']),
                             (two_r['items'][0]['forecasts'][i]['forecast'])]

        fig = df2img.plot_dataframe(two_df)
        df2img.save_dataframe(fig=fig, filename='SG 2 hour weather.png')
        return 'https://www.pythonanywhere.com/user/<purposely_masked_out>/files/home/<purposely_masked_out>/SG 2 hour weather.png'

    # 24 hours weather data extraction
    elif '24 hours' in text:
        two_four_r = requests.get('https://api.data.gov.sg/v1/environment/24-hour-weather-forecast').json()

        # compiling the forecast data
        forecast = list(two_four_r['items'][0]['periods'][0]['regions'].values())
        temp_list = []

        for i in range(1, 3):
            temp_list.extend(list(two_four_r['items'][0]['periods'][i]['regions'].values()))

        for x in range(len(temp_list)):
            forecast.append(temp_list[x])

        # compiling the region data
        region = list(two_four_r['items'][0]['periods'][0]['regions'].keys()) * 3

        # compiling the period data
        period = ['first 8 hours'] * 5 + ['next 8 hours'] * 5 + ['subsequent 8 hours'] * 5

        # compiling all 3 above together
        d = {}
        d['forecast'] = forecast
        d['region'] = region
        d['period'] = period

        # convert into a dataframe for extraction
        two_four_df = pd.DataFrame(d)
        two_four_df = two_four_df[['period', 'region', 'forecast']]

        fig = df2img.plot_dataframe(two_four_df)
        df2img.save_dataframe(fig=fig, filename='SG 24 hour weather.png')
        return 'https://www.pythonanywhere.com/user/<purposely_masked_out>/files/home/<purposely_masked_out>/SG 24 hour weather.png'

    # 4 days weather data extraction
    elif '4 days' in text:
        four_day_r = requests.get('https://api.data.gov.sg/v1/environment/4-day-weather-forecast').json()
        four_day_df = pd.DataFrame(columns=['forecast'])

        for i in range(4):
            four_day_df.loc[i] = [four_day_r['items'][0]['forecasts'][i]['forecast']]

        fig = df2img.plot_dataframe(four_day_df)
        df2img.save_dataframe(fig=fig, filename='SG 4 days weather.png')
        return 'https://www.pythonanywhere.com/user/<purposely_masked_out>/files/home/<purposely_masked_out>/SG 4 day weather.png'

    else:
        return 'I don\'t understand. Please select between \'2 hours\', \'24 hours\' or \'4 days\' and type them properly without spacing'

async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
    text: str = update.message.text
    response = handle_response(text)

    await update.message.reply_photo(response)

if __name__ == '__main__':
    print('Starting bot...')
    app = Application.builder().token(BOT_TOKEN).build()

    app.add_handler(CommandHandler('start', start_command))
    app.add_handler(MessageHandler(filters.TEXT, handle_message))

    print('Polling...')
    app.run_polling(poll_interval=3)

错误回溯信息:

No error handlers are registered, logging exception.
Traceback (most recent call last):
  File "/home/<purposely_masked_out>/.local/lib/python3.10/site-packages/telegram/ext/_application.py", line 1184, in process_update
    await coroutine
  File "/home/<purposely_masked_out>/.local/lib/python3.10/site-packages/telegram/ext/_basehandler.py", line 141, in handle_update
    return await self.callback(update, context)
  File "/home/<purposely_masked_out>/sg-weather-telegram-bot.py", line 89, in handle_message
    await update.message.reply_photo(response)
  File "/home/<purposely_masked_out>/.local/lib/python3.10/site-packages/telegram/_message.py", line 1391, in reply_photo
    return await self.get_bot().send_photo(
  File "/home/<purposely_masked_out>/.local/lib/python3.10/site-packages/telegram/ext/_extbot.py", line 2655, in send_photo
    return await super().send_photo(
  File "/home/<purposely_masked_out>/.local/lib/python3.10/site-packages/telegram/_bot.py", line 394, in decorator
    result = await func(self, *args, **kwargs)  # skipcq: PYL-E1102
  File "/home/<purposely_masked_out>/.local/lib/python3.10/site-packages/telegram/_bot.py", line 1055, in send_photo
    return await self._send_message(
  File "/home/<purposely_masked_out>/.local/lib/python3.10/site-packages/telegram/ext/_extbot.py", line 517, in _send_message
    result = await super()._send_message(
  File "/home/<purposely_masked_out>/.local/lib/python3.10/site-packages/telegram/_bot.py", line 572, in _send_message
    result = await self._post(
  File "/home/<purposely_masked_out>/.local/lib/python3.10/site-packages/telegram/_bot.py", line 482, in _post
    return await self._do_post(
  File "/home/<purposely_masked_out>/.local/lib/python3.10/site-packages/telegram/ext/_extbot.py", line 335, in _do_post
    return await super()._do_post(
  File "/home/<purposely_masked_out>/.local/lib/python3.10/site-packages/telegram/_bot.py", line 510, in _do_post
    return await request.post(
  File "/home/<purposely_masked_out>/.local/lib/python3.10/site-packages/telegram/request/_baserequest.py", line 168, in post
    result = await self._request_wrapper(
  File "/home/<purposely_masked_out>/.local/lib/python3.10/site-packages/telegram/request/_baserequest.py", line 325, in _request_wrapper
    raise BadRequest(message)
telegram.error.BadRequest: Wrong type of the web page content
解决方案

核心原因

你使用的PythonAnywhere文件管理页面URL需要登录验证,Telegram服务器访问时会被跳转到登录页面,返回的是HTML内容而非图片,因此触发Wrong type of the web page content错误。

具体解决方法

方法1:直接发送本地文件(推荐)

无需生成外部URL,直接将本地图片文件对象传给reply_photo,Telegram Bot API会自动处理上传:

  1. 修改handle_response函数,返回本地文件路径而非URL:
    以2小时预报分支为例,将return 'https://xxx...'改为return 'SG 2 hour weather.png',另外两个预报分支同理修改。
  2. 更新handle_message函数,处理文件路径和错误提示:
    async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
        text: str = update.message.text
        result = handle_response(text)
        
        if result.endswith('.png'):
            with open(result, 'rb') as photo_file:
                await update.message.reply_photo(photo_file)
        else:
            await update.message.reply_text(result)
    

方法2:配置PythonAnywhere静态文件服务

如果坚持使用URL访问图片,需在PythonAnywhere设置静态文件目录:

  • 进入PythonAnywhere的「Web」页面,找到「Static files」板块。
  • 添加静态文件映射:
    • URL:填写/static/
    • Directory:填写图片存放的绝对路径(如/home/<你的用户名>/)
  • 保存后,图片的公开访问URL为https://<你的用户名>.pythonanywhere.com/static/SG 2 hour weather.png
  • 建议将文件名中的空格改为下划线(如SG_2_hour_weather.png),避免URL编码问题。

额外优化建议

  • 生成图片时使用绝对路径,避免路径歧义:比如filename='/home/<你的用户名>/SG_2_hour_weather.png'
  • 可给文件名添加时间戳,避免重复生成图片时的文件覆盖问题。

内容的提问来源于stack exchange,提问作者appleseed09

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 11:39:50