PythonAnywhere免费账户能否调用外部HTTPS API?请求被拒排查
问题背景
正在开发一款服务于关联卡牌游戏的Telegram机器人,参考PythonAnywhere教程结合ChatGPT输出编写代码。机器人可正常启动,但调用www.relationalgames.com获取卡牌数据时出现连接拒绝错误。
错误信息
File "/usr/local/lib/python3.10/site-packages/urllib3/util/retry.py", line 592, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='www.relationalgames.com', port=443): Max retries exceeded with url: /cards?deck=Papo%20a%20Papo (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f46da0873a0>: Failed to establish a new connection: [Errno 111] Connection refused'))
当前代码
import telepot import json import random import urllib3 import time # You can leave this bit out if you're using a paid PythonAnywhere account proxy_url = "http://proxy.server:3128" telepot.api._pools = { 'default': urllib3.ProxyManager(proxy_url=proxy_url, num_pools=3, maxsize=10, retries=False, timeout=30), } telepot.api._onetime_pool_spec = (urllib3.ProxyManager, dict(proxy_url=proxy_url, num_pools=1, maxsize=1, retries=False, timeout=30)) # end of the stuff that's only needed for free accounts http = urllib3.PoolManager(timeout=60) def handle(msg): content_type, chat_type, chat_id = telepot.glance(msg) if content_type == 'text': if msg['text'] == '/start': bot.sendMessage(chat_id, "Enter the name of a deck:") else: #try: deck_name = msg['text'] response = http.request('GET', f'https://www.relationalgames.com/cards?deck={deck_name}') # requests.get(f'https://www.relationalgames.com/cards?deck={deck_name}') print(response) playable_deck = json.loads(response.text) random.shuffle(playable_deck) while len(playable_deck) > 0: card = playable_deck.pop() if 'url' in card: bot.sendMessage(chat_id, card['url']) else: bot.sendMessage(chat_id, card['cardText']) if len(playable_deck) == 0: bot.sendMessage(chat_id, "Do you want to restart the game? (yes or no)") break bot.sendMessage(chat_id, "Press any key for next card") bot.getUpdates() #except: # bot.sendMessage(chat_id, "Error processing your request") TOKEN = 'My Token' bot = telepot.Bot(TOKEN) bot.message_loop(handle) print ('Listening ...') # Keep the program running. while 1: time.sleep(10)
疑问与需求
需明确错误原因是PythonAnywhere免费账户限制,还是代码问题,并获取解决思路。
解决思路分析
1. 核心原因:代理配置不完整
PythonAnywhere免费账户对外发起所有HTTP/HTTPS请求必须使用官方指定代理(http://proxy.server:3128)。当前代码仅给Telepot库配置了代理,但用于请求卡牌网站的http = urllib3.PoolManager(timeout=60)未使用代理,导致连接被拒绝。
2. 代码修正步骤
- 替换请求管理器为代理版本:
把原有的http = urllib3.PoolManager(timeout=60)替换为:http = urllib3.ProxyManager(proxy_url=proxy_url, timeout=60) - 恢复异常捕获逻辑:取消
try-except块的注释,避免程序崩溃,同时给用户返回错误提示。 - 修复消息处理逻辑:
bot.getUpdates()与message_loop冲突,会导致重复处理消息,建议改为基于状态的等待逻辑(比如用变量记录用户当前处于“等待下一张卡牌”的状态)。 - URL编码优化:直接拼接
deck_name可能导致编码错误,需对参数进行URL编码:from urllib.parse import quote encoded_deck_name = quote(deck_name) response = http.request('GET', f'https://www.relationalgames.com/cards?deck={encoded_deck_name}')
3. 验证步骤
在PythonAnywhere控制台执行以下命令,测试代理是否能正常访问目标网站:
curl -x http://proxy.server:3128 https://www.relationalgames.com/cards?deck=Papo
若能返回数据,说明代理配置有效;若仍失败,可能是目标网站屏蔽了PythonAnywhere的代理IP,或网站本身不可用。
4. 额外检查点
确认目标API路径是否正确:用户提供的示例URL是/cards/deck?Papo,但代码中使用的是/cards?deck={deck_name},需核对官方API文档确认正确路径。
内容的提问来源于stack exchange,提问作者MrWater

