Python调用Channel Advisor API分页获取全量数据失败求助
Channel Advisor API分页问题排查与解决方案
问题概述
调用Channel Advisor API时,Postman可正常获取包含@odata.nextLink的完整分页结果,但Python代码仅能获取前100条订单。尝试三个版本代码均存在问题:版本1循环仅执行一次;版本2返回400状态码;版本3触发JSONDecodeError。目标是将所有订单数据存入Pandas DataFrame。
API返回示例:
{ "@odata.context": "https://api.channeladvisor.com/v1/$metadata#Orders", "value": [ {....} ], "@odata.nextLink": "https://api.channeladvisor.com/v1/Orders?refresh_token=xxx&$skip=100" }
各版本代码问题分析
版本1问题
- 循环条件逻辑错误:判断
'@odata.nextLink' in response_nextlink是检查字符串子串,而非响应中是否存在该键 - 请求目标错误:循环中调用
response_data['@odata.nextLink'],但response_data是订单数据列表,不存在该键,直接导致请求失败,循环终止 - 数据追加错误:
data.extend(response_data['value'])中,response_data已经是value列表,无需再取value属性
版本2问题
- 认证冲突:
@odata.nextLink中已包含refresh_token参数,但请求时仍携带Authorization头的Bearer Token,重复认证导致API返回400错误
版本3问题
- 未处理请求失败场景:当请求返回非200状态码时(如认证过期、URL无效),响应内容不是JSON格式,直接调用
response.json()触发JSONDecodeError
解决方案代码
import requests import pandas as pd from urllib.parse import urlparse, parse_qs, urlencode, urlunparse def get_access_token(): url = 'https://api.channeladvisor.com/oauth2/token' headers = {'Authorization': 'Basic xxxxx'} post_body = {'grant_type': 'refresh_token', 'refresh_token': 'xxxxx'} response = requests.post(url, headers=headers, data=post_body) response.raise_for_status() return response.json()['access_token'] access_token = get_access_token() base_url = 'https://api.channeladvisor.com/v1/orders' headers = { 'Authorization': f'Bearer {access_token}', 'Accept': 'application/json' } data = [] current_url = base_url while True: try: response = requests.get(current_url, headers=headers) response.raise_for_status() response_json = response.json() # 追加当前页数据 page_data = response_json.get('value', []) if not page_data: break data.extend(page_data) # 检查下一页链接 next_link = response_json.get('@odata.nextLink') if not next_link: break # 移除nextLink中的refresh_token参数,避免认证冲突 parsed_url = urlparse(next_link) query_params = parse_qs(parsed_url.query) query_params.pop('refresh_token', None) new_query = urlencode(query_params, doseq=True) current_url = urlunparse(parsed_url._replace(query=new_query)) except requests.exceptions.HTTPError as e: print(f"HTTP请求错误: {e}") break except ValueError as e: print(f"JSON解析错误: {e}") break # 转换为DataFrame df = pd.DataFrame(data) print(f"共获取{len(df)}条订单数据")
关键优化点
- 状态码检查:用
response.raise_for_status()主动捕获HTTP错误,避免无效响应导致解析问题 - 认证冲突处理:移除nextLink中的
refresh_token参数,统一使用Bearer Token认证,解决400错误 - 异常捕获:处理HTTP错误和JSON解析错误,避免程序直接崩溃
- 安全取值:用
get()方法获取value和@odata.nextLink,避免键不存在时的KeyError - 响应格式规范:将
Accept设置为application/json,确保API返回JSON格式数据
内容的提问来源于stack exchange,提问作者Dolunaykiz
相关产品推荐
相关产品推荐

