使用Python3调用Poloniex API获取数据时遇JSON解析错误求助
你遇到的这个JSONDecodeError几乎可以肯定是Poloniex的反爬机制导致的——当它识别到你的请求不是来自正常浏览器时,会返回带有Google reCAPTCHA验证码的HTML页面,而不是你预期的JSON数据,这就导致requests.get(url).json()解析失败,因为拿到的根本不是合法的JSON。
下面是几个我亲测有效的解决办法,按优先级排序:
1. 模拟浏览器请求头
Poloniex的反爬系统会检查请求的User-Agent等头信息,只要给你的请求加上真实浏览器的头,就能绕过大部分基础拦截:
修改chart_json函数里的请求代码,添加完整的请求头:
def chart_json(start, end, period, symbol): # ... 其他代码 ... headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Accept-Language': 'en-US,en;q=0.9', 'Referer': 'https://poloniex.com/', 'DNT': '1' } # 注意:把URL里的&换成&,HTML转义符在直接请求URL时不需要 url = ('https://poloniex.com/public?command' '=returnChartData¤cyPair={0}&start={1}' '&end={2}&period={3}').format(symbol, start, end, period) logger.debug(' HTTP Request URL:\n{0}'.format(url)) response = requests.get(url, headers=headers) # 先检查响应内容类型,避免直接解析失败 if 'application/json' not in response.headers.get('Content-Type', ''): logger.error('Received non-JSON response, likely blocked by anti-bot') logger.debug('Response content preview:\n{0}'.format(response.text[:500])) raise SystemExit json = response.json() # ... 其他代码 ...
2. 使用会话保持Cookie
很多反爬系统会通过Cookie识别会话,用requests.Session()模拟浏览器的会话状态,先访问Poloniex主页获取必要的Cookie,再请求API:
def chart_json(start, end, period, symbol): # ... 其他代码 ... headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Accept-Language': 'en-US,en;q=0.9', 'Referer': 'https://poloniex.com/', 'DNT': '1' } session = requests.Session() # 先访问主页获取Cookie,模拟真实用户访问流程 session.get('https://poloniex.com/', headers=headers) url = ('https://poloniex.com/public?command' '=returnChartData¤cyPair={0}&start={1}' '&end={2}&period={3}').format(symbol, start, end, period) response = session.get(url, headers=headers) # ... 后续检查和解析代码 ...
这样的请求流程更接近真实用户的操作,被拦截的概率会低很多。
3. 处理验证码(如果前两种方法失效)
如果Poloniex还是返回reCAPTCHA验证码,直接绕过Google的验证码非常困难(因为它需要真实的人机交互),这时候可以考虑用无头浏览器模拟真实操作:
首先安装依赖:
pip install selenium webdriver-manager
然后修改chart_json函数用Selenium请求:
from selenium import webdriver from selenium.webdriver.chrome.options import Options from webdriver_manager.chrome import ChromeDriverManager import json def chart_json(start, end, period, symbol): # ... 其他代码 ... url = ('https://poloniex.com/public?command' '=returnChartData¤cyPair={0}&start={1}' '&end={2}&period={3}').format(symbol, start, end, period) chrome_options = Options() chrome_options.add_argument('--headless=new') # 无头模式,不弹出浏览器窗口 chrome_options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36') chrome_options.add_argument('--disable-blink-features=AutomationControlled') # 隐藏自动化标识 chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option('useAutomationExtension', False) driver = webdriver.Chrome(ChromeDriverManager().install(), options=chrome_options) driver.get(url) # 等待页面加载完成,若出现验证码需手动处理(或接入第三方验证码服务,不推荐) driver.implicitly_wait(10) # 提取页面中的JSON数据 try: json_text = driver.find_element('tag name', 'pre').text # API通常返回pre标签包裹的JSON json_data = json.loads(json_text) except: logger.error('Failed to get JSON, check if CAPTCHA is present') logger.debug('Page source preview:\n{0}'.format(driver.page_source[:1000])) driver.quit() raise SystemExit driver.quit() # ... 后续检查代码 ... return json_data, url
注意:这种方法可能会被Poloniex的高级反爬检测到,需要根据情况调整浏览器参数。如果遇到验证码,可能需要手动介入验证。
4. 检查API参数合法性
有时候参数错误也会导致返回非JSON内容,你可以先手动在浏览器里访问生成的URL,看看返回的是什么:
- 确认
currencyPair格式正确(比如USDT_BTC,Poloniex的格式是BASE_QUOTE) - 确认
period是允许的有效值:300, 900, 1800, 7200, 14400, 86400 - 确认
start和end的时间戳在合理范围内(不要太早,比如超过Poloniex的历史数据范围)
5. 使用官方Python客户端
Poloniex有官方维护的Python库,已经处理了大部分反爬和参数问题,稳定性更高:
pip install poloniex
然后修改你的代码使用官方库:
from poloniex import Poloniex def chart_json(start, end, period, symbol): p = Poloniex() json_data = p.returnChartData(currencyPair=symbol, period=period, start=start, end=end) url = f"https://poloniex.com/public?command=returnChartData¤cyPair={symbol}&start={start}&end={end}&period={period}" # ... 后续检查代码 ... return json_data, url
最后提醒一下:不要频繁请求API,Poloniex会限制请求频率,建议添加time.sleep(1)之类的延迟,避免被封禁IP。
内容的提问来源于stack exchange,提问作者Jaffer Wilson

