车源同步 API:车商批量拉取在售车源图片、里程与首付信息
车商、二手车平台、内容站点都有同一个需求:把在售车源同步到自己的系统里。自己抓列表页要处理 JS 渲染、滚动懒加载、分页签名,还要把「3.2 万公里」「首付 3.8 万」这类文本逐个清洗------工作量大部分花在了数据获取上,而不是业务本身。
usedcar.list 把这一步做成一次 GET 请求:返回当前可查的车源列表,车型名称、图片链接、行驶里程、注册年份、首付、标签 一次拿全,单位已经统一,用 limit 控制条数,并且当前没有可查车源时不收费。
接口速览
| 关键事实 | 说明 |
|---|---|
| 接口地址 | https://api.xujian.tech/openapi/usedcar/list |
| 接口编码 | usedcar.list |
| 请求方式 | GET(limit 放 Query String) |
| 鉴权方式 | 请求头 X-API-Key,不做签名、时间戳或加密 |
| 业务入参 | 仅可选的 limit,取值 1 ~ 50,缺省按上限返回 |
| 返回核心字段 | carName / imageUrl / mileage / regDate / downPayment / tags |
| 计费方式 | 按次计费,0.01 元/次,先预鉴权、查到车源后再扣费 |
| 不计费场景 | 服务暂时不可用、上游返回空车源列表 |
| 字段口径 | 里程统一为万公里 、首付统一为万元 、regDate 为「2024年」文本、标签为数组 |
| 单次耗时 | 数百毫秒 ~ 数秒,costMs 为真实耗时 |
一、哪些业务需要这一步
| 场景 | 具体用法 |
|---|---|
| 车源同步入库 | 定时拉取写进自己的库,支撑站内搜索、推荐与列表页 |
| 车型库建设 | 用 carName 拆出品牌、年款、配置,反向搭建车型字典 |
| 行情抽样统计 | 按注册年份、里程、首付做分布统计,输出行情报告 |
| 收车选品参考 | 按里程 / 年份筛出符合条件的车源,辅助收车决策 |
| 金融方案设计 | 统计各车型的首付水平,设计分期产品 |
| 内容素材生成 | 车源卡片、车型图集、购车攻略的图文素材来源 |
| 竞品车源监控 | 定期比对在售车源结构与定价区间 |
| 库存周转测算 | 同一批车源在多轮拉取中的留存时长,估算周转速度 |
| 库存去重同步 | 以「车型 + 年份 + 里程」组合键做增量同步 |
| 本地筛选替代接口筛选 | 单次最多 50 条,本地过滤比堆接口参数更灵活 |
二、请求参数
2.1 请求头
| 参数名 | 必填 | 说明 |
|---|---|---|
X-API-Key |
是 | 开发者 API Key,缺失或无效直接返回失败 |
2.2 业务参数
| 参数名 | 必填 | 类型 | 示例 | 说明 |
|---|---|---|---|---|
limit |
否 | Integer | 20 | 期望返回条数;范围 1 ~ 50,缺省按上限 50 返回;传 0 或负数按上限处理 |
这个接口没有筛选入参(品牌 / 价格 / 里程筛选要在调用侧自己做)。设计上是「一次拉一批、本地再过滤」:单次最多 50 条,本地筛选远比在接口上堆一堆分不清的参数省心。
三、返回字段
3.1 顶层与 data
| 字段 | 类型 | 说明 |
|---|---|---|
code |
int | 0 成功,非 0 失败(统一为 500) |
msg |
String | 成功为 success,失败为具体原因 |
data |
Object | 业务数据,失败时为 null |
data 字段:
| 字段 | 类型 | 示例 | 说明 |
|---|---|---|---|
total |
int | 20 | 本次实际返回的车源条数 |
list |
Array | ... | 车源列表 |
apiCode |
String | usedcar.list | 接口编码 |
apiName |
String | 二手车信息查询 | 接口名称 |
chargeType |
String | PER_CALL | 计费类型 |
balance |
BigDecimal | 99.9800 | 扣费后的账户余额(元) |
costMs |
Long | 1120 | 本次调用耗时(毫秒) |
3.2 list\[\] 车源对象
| 字段 | 类型 | 示例 | 说明 |
|---|---|---|---|
carName |
String | 长安启源E07 2025款 纯电 两驱 90kWh Max智驾版 | 车型名称(含品牌、年款、配置版本) |
imageUrl |
String | https://.../car.jpg | 车辆图片链接,可直接用于 <img src> |
mileage |
String | 3.20 | 行驶里程,单位:万公里(纯数值文本) |
regDate |
String | 2024年 | 车辆注册年份 |
downPayment |
String | 3.80 | 首付,单位:万元(纯数值文本) |
tags |
Array | "新上架","准新车","0次过户" | 车辆标签数组 |
常见 tags 取值:新上架 / 准新车 / 0 次过户 / 原厂质保 / 个人一手 / 支持分期 / 7 天无理由退车 等,属于运营标签,会动态增减,建议做白名单翻译而不是硬编码全部枚举。
两个细节:一是
data不含keyword(没有业务入参),别按企业系列接口的写法取;二是上游内部主键(dataId/dId/cid)不对外返回 ,需要唯一标识时用carName+regDate+mileage组合键。
四、调用示例
4.1 curl
bash
# 拉满 50 条
curl -s -G "https://api.xujian.tech/openapi/usedcar/list" \
-H "X-API-Key: 你的APIKey"
# 只要 20 条
curl -s -G "https://api.xujian.tech/openapi/usedcar/list" \
--data-urlencode "limit=20" \
-H "X-API-Key: 你的APIKey"
4.2 Java(Hutool)
java
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
public class UsedCarListClient {
private static final String API_URL = "https://api.xujian.tech/openapi/usedcar/list";
/**
* 拉取在售车源
*
* @param apiKey 开发者 API Key
* @param limit 期望条数 1 ~ 50;传 null 取上限
* @return 车源列表;无车源或失败返回 null,且不扣费
*/
public static JSONArray list(String apiKey, Integer limit) {
HttpRequest req = HttpRequest.get(API_URL).header("X-API-Key", apiKey).timeout(20000);
if (limit != null && limit > 0) {
req.form("limit", limit);
}
JSONObject json = JSONUtil.parseObj(req.execute().body());
if (json.getInt("code") == null || json.getInt("code") != 0) {
System.out.println("查询失败(不收费):" + json.getStr("msg"));
return null;
}
return json.getJSONObject("data").getJSONArray("list");
}
public static void main(String[] args) {
JSONArray list = list("你的APIKey", 20);
if (list == null) {
return;
}
for (int i = 0; i < list.size(); i++) {
JSONObject c = list.getJSONObject(i);
System.out.printf("%s | %s万公里 | %s | 首付 %s万%n",
c.getStr("carName"), c.getStr("mileage"),
c.getStr("regDate"), c.getStr("downPayment"));
}
}
}
4.3 Python
python
import requests
def usedcar_list(api_key: str, limit: int = 50):
"""返回车源列表;无车源或失败返回 None,且不扣费"""
resp = requests.get(
"https://api.xujian.tech/openapi/usedcar/list",
params={"limit": limit},
headers={"X-API-Key": api_key},
timeout=20,
)
result = resp.json()
if result.get("code") != 0:
print("查询失败(不收费):", result.get("msg"))
return None
return result["data"]["list"]
if __name__ == "__main__":
for car in usedcar_list("你的APIKey", 20) or []:
print(car["carName"], car["mileage"], car["regDate"], car["tags"])
4.4 JavaScript
javascript
async function usedCarList(apiKey, limit = 50) {
const resp = await fetch(
`https://api.xujian.tech/openapi/usedcar/list?limit=${limit}`,
{ headers: { "X-API-Key": apiKey } }
);
const result = await resp.json();
if (result.code !== 0) {
throw new Error(result.msg);
}
return result.data.list;
}
五、返回示例
json
{
"code": 0,
"msg": "success",
"data": {
"total": 3,
"list": [
{
"carName": "长安启源E07 2025款 纯电 两驱 90kWh Max智驾版",
"imageUrl": "https://example.com/car/e07-1.jpg",
"mileage": "0.50",
"regDate": "2025年",
"downPayment": "5.60",
"tags": ["新上架", "准新车", "0次过户", "原厂质保"]
},
{
"carName": "大众迈腾 2021款 330TSI DSG 豪华型",
"imageUrl": "https://example.com/car/magotan-1.jpg",
"mileage": "3.20",
"regDate": "2021年",
"downPayment": "3.80",
"tags": ["个人一手", "支持分期"]
},
{
"carName": "丰田凯美瑞 2019款 2.5G 豪华版",
"imageUrl": "https://example.com/car/camry-1.jpg",
"mileage": "6.80",
"regDate": "2019年",
"downPayment": "2.90",
"tags": ["7天无理由退车"]
}
],
"apiCode": "usedcar.list",
"apiName": "二手车信息查询",
"chargeType": "PER_CALL",
"balance": 99.9800,
"costMs": 1120
}
}
无可用车源(不收费):
json
{
"code": 500,
"msg": "未查询到可用车源,请稍后重试;本次调用不计费",
"data": null
}
六、可直接复用的两段代码
6.1 拆出品牌 / 年款,建车型字典
python
def split_car_name(car_name: str):
"""把长车型名拆成 品牌 / 年款 / 其余配置"""
parts = car_name.split()
brand = parts[0] if parts else ""
year_model = next((p for p in parts if p.endswith("款")), "")
config = car_name.replace(brand, "", 1).replace(year_model, "", 1).strip()
return {"brand": brand, "year_model": year_model, "config": config}
6.2 增量同步去重
python
def dedup_key(car: dict) -> tuple:
"""接口不返回业务主键,用组合键做增量同步"""
return (car["carName"], car["regDate"], car["mileage"])
def sync(api_key: str, known: set, limit: int = 50):
"""只返回本次新增的车源"""
cars = usedcar_list(api_key, limit) or []
fresh = [c for c in cars if dedup_key(c) not in known]
known.update(dedup_key(c) for c in fresh)
return fresh
七、实践建议
limit别贪心。上限 50 条,选品抽查、行情抽样用 20 ~ 30 条足够,省带宽也省解析开销。- 数值字段已统一单位 。
mileage万公里、downPayment万元,直接Float.parseFloat,不要再解析单位文本。 - 图片尽快转存。第三方图片链接有防盗链与过期风险,展示型业务建议同步时转存到自己的 OSS。
- 标签做白名单翻译 。
tags会动态增减,未知标签原样展示比写死枚举好。 - 定时任务做好幂等 。没有业务主键,务必用组合键(
carName+regDate+mileage)去重。 - 区分「无车源」与「服务异常」 。前者是
未查询到可用车源......本次调用不计费,后者是数据服务暂时不可用......,重试策略应不同。 - 本地筛选,别指望接口筛选。接口不提供品牌 / 价格 / 里程过滤,拉回来在本地过滤更灵活。
- 不要高频轮询。车源变化没那么快,定时同步(小时级或天级)足够,配合本地缓存。
八、错误码与排查
| code | msg | 是否扣费 |
|---|---|---|
| 0 | success | 扣费(返回车源后结算) |
| 500 | 缺少请求头 X-API-Key | 否 |
| 500 | API Key 无效 / API Key 已停用 | 否 |
| 500 | 客户不存在或已停用 | 否 |
| 500 | 接口不存在或已停用 | 否 |
| 500 | 余额不足,请先充值 | 否 |
| 500 | 未查询到可用车源...... | 否 |
| 500 | 二手车服务未启用 / 二手车服务未配置(上游凭证缺失) | 否 |
| 500 | 数据服务暂时不可用(请求上游超时或网络异常) | 否 |
九、计费与接入
| 项目 | 说明 |
|---|---|
| 单价 | 0.01 元/次 |
| 计费方式 | 按次计费,调用前校验余额;先预鉴权,返回车源后才扣费 |
| 不计费场景 | 服务暂时不可用、上游返回空车源列表 |
| 返回条数 | 最多 50 条,用 limit 收敛 |
接入流程:注册开发者账号 → 控制台创建 API Key → 请求头带上 X-API-Key 即可调用,无需签名或加密。控制台可查看调用量、扣费流水与余额。
服务站点:
api.xujian.tech(纯文本域名,不做跳转)。接口试用、数据与充值咨询可在控制台提交工单,或联系 Vxujian_cq。
十、小结
车源同步的难点从来不在算法,而在「拿到干净的结构化数据」这一层。这个接口把渲染型页面里最难处理的部分提前做完:车型长文本、图片链接、里程与首付的单位统一、动态运营标签。
四条关键取舍:
- 无车源不收费:定时任务遇到空结果不产生费用;
- 单位收敛到字段语义 :
mileage万公里、downPayment万元,都是可直接 parse 的数值文本; - 不放一堆看不懂的筛选参数:单次上限 50 条,本地过滤更灵活;
- 内部标识不外传:上游主键不返回,别依赖随时可能变的内部约定。
如果要对这些车源做价格判断,可以搭配二手车价格评估接口 usedcar.price(0.5 元/次):本接口拉车源,评估接口算合理价格区间,两者组合即可完成「选品 → 定价」的闭环。