Python按10分钟间隔拉取API数据报JSONDecodeError排查
问题根因
报错json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)本质是传入json.loads()的内容是空字符串/非JSON格式内容,结合代码逻辑,触发原因有4个:
- 时间分片逻辑不符合需求且存在越界:代码按10分钟步长生成时间起点,但每个分片的结束时间错误加了20分钟,和需求要求的10分钟分片规则不符,存在大量重复拉取;最后一个时间点(次日00:00)加20分钟后会越界到查询范围外的未来时间,多数API查询无数据的未来时间段会返回空响应。
- 无HTTP响应状态校验:代码拿到响应后直接读取内容解析,没有校验状态码是否为200,遇到接口限流、权限错误、服务端5xx错误、204无内容响应时,返回的空字符串/HTML错误页/纯文本提示都不是合法JSON,直接解析必报错。
- 冗余逻辑触发隐藏错误:代码末尾的
start_dt += delta、end_dt += delta两行属于冗余逻辑,且delta变量未在代码中定义,第一轮循环跑完就会触发NameError中断任务。 - 无容错机制:单分片请求失败会直接中断整个批量拉取任务,稳定性差。
修复方案
按以下步骤调整代码即可解决问题:
- 修正时间分片规则:严格按照10分钟窗口切分,每个分片的结束时间为起点加10分钟,删除未定义变量的冗余递增逻辑,过滤掉超出结束时间的分片。
- 增加响应校验逻辑:先判断HTTP响应状态码,非200状态时记录错误上下文(请求URL、状态码、响应内容),根据场景选择重试或跳过当前分片。
- 增加空内容判断:响应内容为空时直接跳过当前分片,不进入JSON解析流程。
- 增加单分片异常捕获:单个分片请求/解析失败不中断整体任务,记录错误日志后继续处理下一个分片。
修复后的可运行代码如下:
import json from datetime import datetime, timedelta import pandas as pd import logging # 日志配置(按需调整) logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') def call_api(date_run, api_url, headers, client): json_arr = [] batch_start_dt = datetime.strptime(date_run, '%Y-%m-%d') batch_end_dt = batch_start_dt + timedelta(days=1) # 生成10分钟步长的时间分片起点 time_points = pd.date_range(start=batch_start_dt, end=batch_end_dt, freq='10T').to_series() for idx, start_dt_ts in time_points.iteritems(): start_dt = idx.to_pydatetime() # 严格按10分钟窗口设置结束时间,不越界 end_dt = min(start_dt + timedelta(minutes=10), batch_end_dt) # 起点等于终点时直接终止循环 if start_dt >= batch_end_dt: break start_dt_str = start_dt.strftime('%Y-%m-%dT%H:%M:%S') end_dt_str = end_dt.strftime('%Y-%m-%dT%H:%M:%S') request_url = f"https://{api_url}:443/api/ChangeList?fromDate={start_dt_str}Z&endDate={end_dt_str}Z&timeBufferInSecs=1200&firstLevelFieldsOnly=true" try: client.request("GET", request_url, headers=headers) response = client.getresponse() # 先校验状态码 if response.status != 200: err_content = response.read().decode("UTF-8", errors="ignore") logging.error(f"分片请求失败,url:{request_url}, 状态码:{response.status}, 响应:{err_content}") # 按需加重试逻辑,这里直接跳过当前分片 continue data = response.read().decode("UTF-8").strip() # 空响应直接跳过 if not data: logging.warning(f"分片{start_dt_str}~{end_dt_str}返回空内容,跳过") continue json_results = json.loads(data) # 兼容接口返回字典/列表两种格式 if isinstance(json_results, list): json_arr.extend(json_results) else: json_arr.append(json_results) logging.info(f"分片{start_dt_str}~{end_dt_str}拉取完成,累计获取{len(json_arr)}条数据") except Exception as e: logging.error(f"处理分片{start_dt_str}~{end_dt_str}异常,错误信息:{str(e)}", exc_info=True) continue return json_arr
验证要点
- 分片区间严格符合10分钟步长要求,无重叠、无越界
- 单分片异常不影响整体任务运行
- 非200响应、空响应不会触发JSON解析错误
- 拉取的数据无重复、无遗漏
内容的提问来源于stack exchange,提问作者Karthik
相关产品推荐
相关产品推荐

