×

汽车之家item_search - 根据地区获取二手车列表接口对接全攻略:从入门到精通

万邦科技Lex 万邦科技Lex 发表于2026-02-02 09:29:49 浏览872 评论0

抢沙发发表评论

一、接口概览

1.1 接口简介

item_search接口是汽车之家开放平台的核心接口之一,专门用于二手车信息检索。支持按地区、品牌、价格、车龄等多维度筛选二手车,返回结构化的车辆列表信息。

1.2 核心功能

  • ✅ 地区筛选:按省市区精准定位二手车源

  • ✅ 多条件搜索:品牌、车系、价格、里程、车龄等

  • ✅ 分页查询:支持大数据量的分页加载

  • ✅ 排序功能:按价格、里程、发布时间等排序

  • ✅ 字段选择:可指定返回字段,优化网络传输

二、准备工作

2.1 环境配置

# requirements.txtrequests>=2.28.0python-dotenv>=1.0.0pydantic>=2.0.0aiohttp>=3.8.0redis>=4.5.0

2.2 认证配置

# config.pyimport osfrom dotenv import load_dotenv

load_dotenv()class Config:    # 汽车之家API配置
    AUTOHOME_APP_KEY = os.getenv('AUTOHOME_APP_KEY')
    AUTOHOME_APP_SECRET = os.getenv('AUTOHOME_APP_SECRET')
    AUTOHOME_API_BASE = os.getenv('AUTOHOME_API_BASE', 
        'https://openapi.autohome.com.cn/api/v1'
    )    
    # 请求配置
    REQUEST_TIMEOUT = 30
    MAX_RETRIES = 3
    DEFAULT_PAGE_SIZE = 20
    MAX_PAGE_SIZE = 100
    
    # 缓存配置
    CACHE_TTL = 3600  # 1小时

三、接口详解

3.1 接口地址

GET /usedcar/search

3.2 请求参数详解

基础参数

参数名
类型
必填
说明
示例
app_key
string
是
应用标识
autohome_app_2024
timestamp
int
是
时间戳
1706774400
sign
string
是
请求签名
详见签名算法
format
string
否
返回格式
json(默认)
version
string
是
API版本
1.0

搜索参数

参数名
类型
必填
说明
示例
province_id
int
否
省份ID
11(北京)
city_id
int
否
城市ID
1101(北京市)
district_id
int
否
区县ID
110101(东城区)
brand_id
int
否
品牌ID
1(奥迪)
series_id
int
否
车系ID
10(A6L)
min_price
float
否
最低价格(万元)
10.0
max_price
float
否
最高价格(万元)
50.0
min_mileage
int
否
最低里程(万公里)
1
max_mileage
int
否
最高里程(万公里)
20
min_year
int
否
最低年份
2018
max_year
int
否
最高年份
2023
fuel_type
string
否
燃油类型
汽油/柴油/新能源
transmission
string
否
变速箱类型
自动/手动
body_type
string
否
车身类型
轿车/SUV/MPV
keyword
string
否
搜索关键词
"奥迪A6L 2020款"
sort_field
string
否
排序字段
price/mileage/year/publish_time
sort_order
string
否
排序方向
asc/desc(默认desc)
page_no
int
否
页码
1(默认)
page_size
int
否
每页条数
20(默认)
fields
string
否
返回字段
id,title,price,mileage,year

四、完整代码实现

4.1 Python完整实现

import requestsimport timeimport hashlibimport hmacimport jsonfrom typing import Dict, Any, List, Optionalfrom datetime import datetime, timedeltafrom dataclasses import dataclassfrom urllib.parse import urlencodeimport redis@dataclassclass UsedCarBasicInfo:    """二手车基本信息"""
    car_id: int
    title: str
    price: float
    original_price: float
    mileage: float
    year: int
    month: int
    city: str
    district: str
    brand: str
    series: str
    model: str
    fuel_type: str
    transmission: str
    body_type: str
    publish_time: str
    thumbnail_url: str
    source_type: str  # 个人/商家@dataclassclass UsedCarDetail:    """二手车详细信息"""
    basic_info: UsedCarBasicInfo
    images: List[str]
    specs: Dict[str, str]
    seller_info: Dict[str, Any]
    inspection_report: Dict[str, Any]@dataclassclass SearchResult:    """搜索结果"""
    success: bool
    code: int
    message: str
    data: Dict[str, Any]
    used_cars: List[UsedCarBasicInfo]
    pagination: Dict[str, Any]class AutoHomeUsedCarAPI:    """汽车之家二手车API客户端"""
    
    def __init__(self, app_key: str, app_secret: str, sandbox: bool = True, redis_client=None):        self.app_key = app_key        self.app_secret = app_secret        self.base_url = "https://sandbox-openapi.autohome.com.cn" if sandbox else "https://openapi.autohome.com.cn"
        self.session = requests.Session()        self.session.headers.update({            'User-Agent': 'AutoHome-UsedCar-API/1.0',            'Accept': 'application/json'
        })        self.redis = redis_client        self._access_token = None
        self._token_expires = None
    
    def _generate_signature(self, params: Dict[str, Any], timestamp: int) -> str:        """生成请求签名"""
        # 排序参数
        sorted_params = sorted(params.items())
        param_str = '&'.join([f"{k}={v}" for k, v in sorted_params])        
        # 构建签名字符串
        sign_str = f"{self.app_key}{param_str}{timestamp}{self.app_secret}"
        
        # 计算HMAC-SHA256签名
        signature = hmac.new(            self.app_secret.encode('utf-8'),
            sign_str.encode('utf-8'),
            hashlib.sha256
        ).hexdigest()        
        return signature    
    def _get_access_token(self) -> str:        """获取访问令牌"""
        # 检查token是否有效
        if self._access_token and self._token_expires and self._token_expires > datetime.now():            return self._access_token        
        # 获取新token
        timestamp = int(time.time())
        params = {            'app_key': self.app_key,            'timestamp': timestamp,            'grant_type': 'client_credentials'
        }        
        # 生成签名
        signature = self._generate_signature(params, timestamp)
        params['sign'] = signature        
        # 请求token
        url = f"{self.base_url}/oauth/token"
        response = self.session.post(url, data=params)        
        if response.status_code == 200:
            data = response.json()            self._access_token = data['access_token']            self._token_expires = datetime.now() + timedelta(seconds=data['expires_in'] - 300)  # 提前5分钟过期
            return self._access_token        else:            raise Exception(f"获取token失败: {response.status_code} - {response.text}")    
    def search_used_cars(
        self,
        province_id: Optional[int] = None,
        city_id: Optional[int] = None,
        district_id: Optional[int] = None,
        brand_id: Optional[int] = None,
        series_id: Optional[int] = None,
        min_price: Optional[float] = None,
        max_price: Optional[float] = None,
        min_mileage: Optional[float] = None,
        max_mileage: Optional[float] = None,
        min_year: Optional[int] = None,
        max_year: Optional[int] = None,
        fuel_type: Optional[str] = None,
        transmission: Optional[str] = None,
        body_type: Optional[str] = None,
        keyword: Optional[str] = None,
        sort_field: str = "publish_time",
        sort_order: str = "desc",
        page_no: int = 1,
        page_size: int = 20,
        fields: Optional[List[str]] = None
    ) -> SearchResult:        """
        搜索二手车
        # 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex 
        Args:
            province_id: 省份ID
            city_id: 城市ID
            district_id: 区县ID
            brand_id: 品牌ID
            series_id: 车系ID
            min_price: 最低价格(万元)
            max_price: 最高价格(万元)
            min_mileage: 最低里程(万公里)
            max_mileage: 最高里程(万公里)
            min_year: 最低年份
            max_year: 最高年份
            fuel_type: 燃油类型
            transmission: 变速箱类型
            body_type: 车身类型
            keyword: 搜索关键词
            sort_field: 排序字段
            sort_order: 排序方向
            page_no: 页码
            page_size: 每页条数
            fields: 返回字段列表
        # 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex 
        Returns:
            搜索结果
        """
        # 获取访问令牌
        access_token = self._get_access_token()        
        # 构建请求参数
        params = {            'app_key': self.app_key,            'timestamp': int(time.time()),            'format': 'json',            'version': '1.0',            'sort_field': sort_field,            'sort_order': sort_order,            'page_no': page_no,            'page_size': min(page_size, Config.MAX_PAGE_SIZE)
        }        
        # 添加可选参数
        if province_id:
            params['province_id'] = province_id        if city_id:
            params['city_id'] = city_id        if district_id:
            params['district_id'] = district_id        if brand_id:
            params['brand_id'] = brand_id        if series_id:
            params['series_id'] = series_id        if min_price:
            params['min_price'] = min_price        if max_price:
            params['max_price'] = max_price        if min_mileage:
            params['min_mileage'] = min_mileage        if max_mileage:
            params['max_mileage'] = max_mileage        if min_year:
            params['min_year'] = min_year        if max_year:
            params['max_year'] = max_year        if fuel_type:
            params['fuel_type'] = fuel_type        if transmission:
            params['transmission'] = transmission        if body_type:
            params['body_type'] = body_type        if keyword:
            params['keyword'] = keyword        if fields:
            params['fields'] = ','.join(fields)        
        # 生成签名
        signature = self._generate_signature(params, params['timestamp'])
        params['sign'] = signature        
        # 添加认证头
        headers = {            'Authorization': f'Bearer {access_token}',            'Content-Type': 'application/json'
        }        
        # 发送请求
        url = f"{self.base_url}/api/v1/usedcar/search"
        
        try:
            response = self.session.get(
                url,
                params=params,
                headers=headers,
                timeout=Config.REQUEST_TIMEOUT
            )            
            if response.status_code == 200:
                result = response.json()                
                # 解析结果
                used_cars = self._parse_used_cars(result.get('data', {}).get('list', []))
                pagination = result.get('data', {}).get('pagination', {})                
                return SearchResult(
                    success=result.get('success', False),
                    code=result.get('code', 0),
                    message=result.get('message', ''),
                    data=result.get('data', {}),
                    used_cars=used_cars,
                    pagination=pagination
                )            elif response.status_code == 401:                # Token过期,重新获取
                self._access_token = None
                return self.search_used_cars(
                    province_id=province_id, city_id=city_id, district_id=district_id,
                    brand_id=brand_id, series_id=series_id, min_price=min_price, max_price=max_price,
                    min_mileage=min_mileage, max_mileage=max_mileage, min_year=min_year, max_year=max_year,
                    fuel_type=fuel_type, transmission=transmission, body_type=body_type, keyword=keyword,
                    sort_field=sort_field, sort_order=sort_order, page_no=page_no, page_size=page_size,
                    fields=fields
                )            else:                return SearchResult(
                    success=False,
                    code=response.status_code,
                    message=f"HTTP {response.status_code}",
                    data={},
                    used_cars=[],
                    pagination={}
                )                
        except requests.exceptions.Timeout:            return SearchResult(
                success=False,
                code=408,
                message="请求超时",
                data={},
                used_cars=[],
                pagination={}
            )        except requests.exceptions.RequestException as e:            return SearchResult(
                success=False,
                code=500,
                message=f"网络请求异常: {str(e)}",
                data={},
                used_cars=[],
                pagination={}
            )    
    def _parse_used_cars(self, car_list: List[Dict[str, Any]]) -> List[UsedCarBasicInfo]:        """解析二手车列表数据"""
        used_cars = []        
        for car_data in car_list:            try:
                basic_info = UsedCarBasicInfo(
                    car_id=car_data.get('id'),
                    title=car_data.get('title', ''),
                    price=car_data.get('price', 0),
                    original_price=car_data.get('original_price', 0),
                    mileage=car_data.get('mileage', 0),
                    year=car_data.get('year', 0),
                    month=car_data.get('month', 0),
                    city=car_data.get('city', ''),
                    district=car_data.get('district', ''),
                    brand=car_data.get('brand', {}).get('name', ''),
                    series=car_data.get('series', {}).get('name', ''),
                    model=car_data.get('model', ''),
                    fuel_type=car_data.get('fuel_type', ''),
                    transmission=car_data.get('transmission', ''),
                    body_type=car_data.get('body_type', ''),
                    publish_time=car_data.get('publish_time', ''),
                    thumbnail_url=car_data.get('thumbnail_url', ''),
                    source_type=car_data.get('source_type', '个人')
                )
                used_cars.append(basic_info)            except Exception as e:                print(f"解析车辆数据失败: {e}, 数据: {car_data}")                continue
        
        return used_cars    
    def search_all_used_cars(
        self,
        max_pages: int = 10,
        **search_params    ) -> List[UsedCarBasicInfo]:        """
        获取所有符合条件的二手车(自动处理分页)
        
        Args:
            max_pages: 最大页数限制
            **search_params: 搜索参数
        
        Returns:
            二手车列表
        """
        all_cars = []
        page_no = 1
        
        while page_no <= max_pages:
            result = self.search_used_cars(page_no=page_no, **search_params)            
            if not result.success:                print(f"第{page_no}页查询失败: {result.message}")                break
            
            # 添加当前页数据
            all_cars.extend(result.used_cars)
            pagination = result.pagination            
            print(f"已获取第{page_no}页,共{len(result.used_cars)}条,总计{len(all_cars)}条")            
            # 检查是否还有下一页
            has_next = pagination.get('has_next', False)
            total_pages = pagination.get('total_pages', 0)            
            if not has_next or page_no >= total_pages:                break
            
            page_no += 1
            
            # 避免请求过于频繁
            time.sleep(0.5)        
        return all_cars    
    def get_used_car_detail(self, car_id: int) -> Optional[UsedCarDetail]:        """
        获取二手车详细信息
        """
        # 获取访问令牌
        access_token = self._get_access_token()        
        # 构建请求
        headers = {            'Authorization': f'Bearer {access_token}',            'Content-Type': 'application/json'
        }
        
        url = f"{self.base_url}/api/v1/usedcar/detail/{car_id}"
        
        try:
            response = self.session.get(url, headers=headers, timeout=30)            
            if response.status_code == 200:
                data = response.json().get('data', {})                
                # 解析基础信息
                basic_info = UsedCarBasicInfo(
                    car_id=data.get('id'),
                    title=data.get('title', ''),
                    price=data.get('price', 0),
                    original_price=data.get('original_price', 0),
                    mileage=data.get('mileage', 0),
                    year=data.get('year', 0),
                    month=data.get('month', 0),
                    city=data.get('city', ''),
                    district=data.get('district', ''),
                    brand=data.get('brand', {}).get('name', ''),
                    series=data.get('series', {}).get('name', ''),
                    model=data.get('model', ''),
                    fuel_type=data.get('fuel_type', ''),
                    transmission=data.get('transmission', ''),
                    body_type=data.get('body_type', ''),
                    publish_time=data.get('publish_time', ''),
                    thumbnail_url=data.get('thumbnail_url', ''),
                    source_type=data.get('source_type', '个人')
                )                
                # 解析详细信息
                images = data.get('images', [])
                specs = data.get('specs', {})
                seller_info = data.get('seller_info', {})
                inspection_report = data.get('inspection_report', {})                
                return UsedCarDetail(
                    basic_info=basic_info,
                    images=images,
                    specs=specs,
                    seller_info=seller_info,
                    inspection_report=inspection_report
                )            else:                return None
                
        except Exception as e:            print(f"获取车辆详情失败: {e}")            return None# 使用示例def demo_used_car_api():    """二手车API使用演示"""
    
    # 初始化客户端
    client = AutoHomeUsedCarAPI(
        app_key=Config.AUTOHOME_APP_KEY,
        app_secret=Config.AUTOHOME_APP_SECRET,
        sandbox=True
    )    
    print("=== 示例1:按地区搜索二手车 ===")
    result = client.search_used_cars(
        province_id=11,  # 北京
        city_id=1101,    # 北京市
        min_price=10,
        max_price=30,
        min_year=2018,
        max_year=2022,
        page_size=5
    )    
    if result.success:        for car in result.used_cars:            print(f"{car.brand} {car.series} - {car.price}万 - {car.mileage}万公里 - {car.year}年")    
    print("\n=== 示例2:按品牌搜索 ===")
    result = client.search_used_cars(
        brand_id=1,  # 奥迪
        min_price=20,
        max_price=50,
        sort_field="price",
        sort_order="asc"
    )    
    print("\n=== 示例3:获取所有符合条件的二手车 ===")
    all_cars = client.search_all_used_cars(
        province_id=11,
        min_price=15,
        max_price=25,
        min_year=2019,
        max_mileage=15
    )    print(f"共找到 {len(all_cars)} 辆符合条件的二手车")if __name__ == "__main__":
    demo_used_car_api()

4.2 Java实现

import com.fasterxml.jackson.annotation.JsonInclude;import com.fasterxml.jackson.databind.ObjectMapper;import okhttp3.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;import java.io.IOException;import java.nio.charset.StandardCharsets;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.time.LocalDateTime;import java.util.*;import java.util.concurrent.TimeUnit;public class AutoHomeUsedCarClient {    private static final Logger logger = LoggerFactory.getLogger(AutoHomeUsedCarClient.class);    
    private final String appKey;    private final String appSecret;    private final String baseUrl;    private final OkHttpClient httpClient;    private final ObjectMapper objectMapper;    
    private String accessToken;    private LocalDateTime tokenExpires;    
    public AutoHomeUsedCarClient(String appKey, String appSecret, boolean sandbox) {        this.appKey = appKey;        this.appSecret = appSecret;        this.baseUrl = sandbox ? 
            "https://sandbox-openapi.autohome.com.cn" : 
            "https://openapi.autohome.com.cn";        
        this.httpClient = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .build();        
        this.objectMapper = new ObjectMapper();        this.objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    }    
    public UsedCarSearchResult searchUsedCars(UsedCarSearchParams params) throws IOException {        // 获取访问令牌
        String token = getAccessToken();        
        # 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex 
        // 构建请求参数
        Map<String, Object> requestParams = new HashMap<>();
        requestParams.put("app_key", appKey);
        requestParams.put("timestamp", System.currentTimeMillis() / 1000);
        requestParams.put("format", "json");
        requestParams.put("version", "1.0");        
        // 添加搜索参数
        if (params.getProvinceId() != null) {
            requestParams.put("province_id", params.getProvinceId());
        }        if (params.getCityId() != null) {
            requestParams.put("city_id", params.getCityId());
        }        // ... 其他参数
        
        // 生成签名
        String signature = generateSignature(requestParams, (Long) requestParams.get("timestamp"));
        requestParams.put("sign", signature);        
        // 构建请求URL
        HttpUrl.Builder urlBuilder = HttpUrl.parse(baseUrl + "/api/v1/usedcar/search").newBuilder();        for (Map.Entry<String, Object> param : requestParams.entrySet()) {
            urlBuilder.addQueryParameter(param.getKey(), param.getValue().toString());
        }        
        // 发送请求
        Request request = new Request.Builder()
                .url(urlBuilder.build())
                .addHeader("Authorization", "Bearer " + token)
                .addHeader("User-Agent", "AutoHome-Java-Client/1.0")
                .build();        
        try (Response response = httpClient.newCall(request).execute()) {            if (response.isSuccessful()) {                String responseBody = response.body().string();
                Map<String, Object> result = objectMapper.readValue(responseBody, Map.class);                return parseSearchResult(result);
            } else {                throw new IOException("请求失败: " + response.code());
            }
        }
    }    
    // 省略其他方法...}class UsedCarSearchParams {    private Integer provinceId;    private Integer cityId;    private Integer districtId;    private Integer brandId;    private Integer seriesId;    private Double minPrice;    private Double maxPrice;    private Double minMileage;    private Double maxMileage;    private Integer minYear;    private Integer maxYear;    private String fuelType;    private String transmission;    private String bodyType;    private String keyword;    private String sortField = "publish_time";    private String sortOrder = "desc";    private Integer pageNo = 1;    private Integer pageSize = 20;    
    // 省略getter/setter方法}

4.3 PHP实现

<?phpclass AutoHomeUsedCarService{    private $appKey;    private $appSecret;    private $baseUrl;    private $accessToken;    private $tokenExpires;    
    public function __construct($appKey, $appSecret, $sandbox = true)    {        $this->appKey = $appKey;        $this->appSecret = $appSecret;        $this->baseUrl = $sandbox 
            ? 'https://sandbox-openapi.autohome.com.cn'
            : 'https://openapi.autohome.com.cn';
    }    
    public function searchUsedCars($params = [])    {        // 获取访问令牌
        $token = $this->getAccessToken();        
        // 构建请求参数
        # 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex 
        $requestParams = [            'app_key' => $this->appKey,            'timestamp' => time(),            'format' => 'json',            'version' => '1.0'
        ];        
        // 合并搜索参数
        $requestParams = array_merge($requestParams, $params);        
        // 生成签名
        $signature = $this->generateSignature($requestParams);        $requestParams['sign'] = $signature;        
        // 发送请求
        $url = $this->baseUrl . '/api/v1/usedcar/search?' . http_build_query($requestParams);        
        $ch = curl_init();        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HTTPHEADER => [                'Authorization: Bearer ' . $token,                'User-Agent: AutoHome-PHP-Client/1.0'
            ]
        ]);        
        $response = curl_exec($ch);        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);        curl_close($ch);        
        if ($httpCode === 200) {            return json_decode($response, true);
        } else {            throw new Exception("请求失败: HTTP {$httpCode}");
        }
    }    
    private function getAccessToken()    {        // 检查token是否有效
        if ($this->accessToken && $this->tokenExpires && $this->tokenExpires > time()) {            return $this->accessToken;
        }        
        // 获取新token
        $timestamp = time();        $params = [            'app_key' => $this->appKey,            'timestamp' => $timestamp,            'grant_type' => 'client_credentials'
        ];        
        $signature = $this->generateSignature($params);        $params['sign'] = $signature;        
        $ch = curl_init();        curl_setopt_array($ch, [
            CURLOPT_URL => $this->baseUrl . '/oauth/token',
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => http_build_query($params),
            CURLOPT_TIMEOUT => 30
        ]);        
        $response = curl_exec($ch);        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);        curl_close($ch);        
        if ($httpCode === 200) {            $result = json_decode($response, true);            $this->accessToken = $result['access_token'];            $this->tokenExpires = time() + $result['expires_in'] - 300; // 提前5分钟过期
            return $this->accessToken;
        } else {            throw new Exception("获取token失败: HTTP {$httpCode}");
        }
    }    
    private function generateSignature($params)    {        // 移除sign参数并排序
        unset($params['sign']);        ksort($params);        
        // 拼接参数字符串
        $paramStr = '';        foreach ($params as $key => $value) {            $paramStr .= $key . '=' . $value . '&';
        }        $paramStr = rtrim($paramStr, '&');        
        // 构建签名字符串
        $signStr = $this->appKey . $paramStr . $params['timestamp'] . $this->appSecret;        
        // 计算HMAC-SHA256
        return hash_hmac('sha256', $signStr, $this->appSecret);
    }
}// 使用示例try {    $service = new AutoHomeUsedCarService('your_app_key', 'your_app_secret');    
    $result = $service->searchUsedCars([        'province_id' => 11,        'city_id' => 1101,        'min_price' => 10,        'max_price' => 30,        'min_year' => 2018,        'page_size' => 10
    ]);    
    if ($result['success']) {        foreach ($result['data']['list'] as $car) {            echo "{$car['brand']['name']} {$car['series']['name']} - {$car['price']}万\n";
        }
    }
} catch (Exception $e) {    echo "错误: " . $e->getMessage() . "\n";
}?>

五、返回结果解析

5.1 成功响应示例

{
  "success": true,
  "code": 200,
  "message": "成功",
  "data": {
    "list": [
      {
        "id": 12345,
        "title": "2020款 奥迪A6L 45 TFSI 臻选致雅型",
        "price": 28.5,
        "original_price": 45.8,
        "mileage": 5.2,
        "year": 2020,
        "month": 6,
        "city": "北京市",
        "district": "朝阳区",
        "brand": {
          "id": 1,
          "name": "奥迪"
        },
        "series": {
          "id": 10,
          "name": "A6L"
        },
        "model": "45 TFSI 臻选致雅型",
        "fuel_type": "汽油",
        "transmission": "自动",
        "body_type": "轿车",
        "publish_time": "2026-01-15 14:30:00",
        "thumbnail_url": "https://img.autohome.com.cn/usedcar/12345.jpg",
        "source_type": "商家"
      }
    ],
    "pagination": {
      "page_no": 1,
      "page_size": 20,
      "total_count": 125,
      "total_pages": 7,
      "has_next": true,
      "has_previous": false
    },
    "summary": {
      "avg_price": 25.8,
      "avg_mileage": 6.5,
      "avg_year": 2019.5,
      "brand_distribution": {
        "奥迪": 15,
        "宝马": 12,
        "奔驰": 10
      }
    }
  }}

5.2 错误响应示例

{
  "success": false,
  "code": 400,
  "message": "参数错误:province_id无效",
  "data": null}

5.3 状态码说明

状态码
说明
处理建议
200
成功
-
400
参数错误
检查请求参数格式
401
认证失败
检查API密钥和签名
403
权限不足
检查API权限范围
404
数据不存在
检查搜索条件
429
请求频率超限
降低请求频率
500
服务器错误
稍后重试

六、高级功能实现

6.1 智能搜索建议

class IntelligentUsedCarSearch:    """智能二手车搜索服务"""
    
    def __init__(self, api_client):        self.client = api_client        self.search_history = []    
    def smart_search(self, query: str, location: str = None) -> SearchResult:        """
        智能搜索:自动识别搜索类型
        
        Args:
            query: 搜索查询字符串
            location: 地区信息
        
        Returns:
            搜索结果
        """
        # 解析查询类型
        search_type = self._detect_search_type(query)        
        # 构建搜索参数
        params = self._build_search_params(query, search_type, location)        
        # 执行搜索
        result = self.client.search_used_cars(**params)        
        # 记录搜索历史
        self._record_search_history(query, search_type, result)        
        return result    
    def _detect_search_type(self, query: str) -> str:        """自动识别搜索类型"""
        import re        
        # 检查是否为价格范围
        if re.match(r'^\d+-\d+万$', query):            return 'price_range'
        
        # 检查是否为年份范围
        if re.match(r'^\d+-\d+年$', query):            return 'year_range'
        
        # 检查是否为里程范围
        if re.match(r'^\d+-\d+万公里$', query):            return 'mileage_range'
        
        # 检查是否为品牌+车系
        brand_patterns = ['奥迪', '宝马', '奔驰', '大众', '丰田', '本田']        for brand in brand_patterns:            if brand in query:                return 'brand_model'
        
        # 默认为关键词搜索
        return 'keyword'
    
    def _build_search_params(self, query: str, search_type: str, location: str) -> Dict[str, Any]:        """根据搜索类型构建参数"""
        params = {}        import re        
        if search_type == 'price_range':            # 解析价格范围
            match = re.match(r'^(\d+)-(\d+)万$', query)            if match:
                params['min_price'] = float(match.group(1))
                params['max_price'] = float(match.group(2))        
        elif search_type == 'year_range':            # 解析年份范围
            match = re.match(r'^(\d+)-(\d+)年$', query)            if match:
                params['min_year'] = int(match.group(1))
                params['max_year'] = int(match.group(2))        
        elif search_type == 'mileage_range':            # 解析里程范围
            match = re.match(r'^(\d+)-(\d+)万公里$', query)            if match:
                params['min_mileage'] = float(match.group(1))
                params['max_mileage'] = float(match.group(2))        
        elif search_type == 'brand_model':            # 解析品牌和车型
            params['keyword'] = query        
        else:
            params['keyword'] = query        
        # 添加地区信息
        if location:            # 这里可以集成地理编码服务将地址转换为ID
            pass
        
        return params

6.2 数据缓存优化

import redisfrom functools import lru_cacheclass CachedUsedCarAPI(AutoHomeUsedCarAPI):    """带缓存的二手车API"""
    
    def __init__(self, app_key, app_secret, redis_client, sandbox=True):        super().__init__(app_key, app_secret, sandbox)        self.redis = redis_client        self.cache_prefix = "autohome:usedcar:"
    
    def search_used_cars_cached(self, cache_key: str, **params) -> SearchResult:        """
        带缓存的二手车搜索
        """
        # 检查缓存
        cached = self.redis.get(cache_key)        if cached:
            data = json.loads(cached)            return SearchResult(**data)        
        # 调用API
        result = super().search_used_cars(**params)        
        # 缓存结果
        if result.success:            # 根据数据量设置缓存时间
            ttl = self._calculate_ttl(result)            self.redis.setex(
                cache_key,
                ttl,
                json.dumps(result.__dict__)
            )        
        return result    
    def _calculate_ttl(self, result: SearchResult) -> int:        """根据搜索结果计算缓存时间"""
        total_count = result.pagination.get('total_count', 0)        
        if total_count == 0:            return 1800  # 30分钟
        elif total_count <= 100:            return 3600  # 1小时
        else:            return 7200  # 2小时
    
    def get_cache_key(self, **params) -> str:        """生成缓存键"""
        # 移除分页参数
        cache_params = params.copy()
        cache_params.pop('page_no', None)
        cache_params.pop('page_size', None)        
        # 生成唯一键
        param_str = json.dumps(cache_params, sort_keys=True)        return f"{self.cache_prefix}{hashlib.md5(param_str.encode()).hexdigest()}"

6.3 批量处理优化

from concurrent.futures import ThreadPoolExecutor, as_completedclass BatchUsedCarProcessor:    """批量二手车处理器"""
    
    def __init__(self, api_client):        self.client = api_client    
    def batch_search_by_regions(
        self,
        regions: List[Dict[str, int]],
        search_params: Dict[str, Any],
        max_workers: int = 3
    ) -> Dict[str, List[UsedCarBasicInfo]]:        """
        按地区批量搜索二手车
        
        Args:
            regions: 地区列表 [{"province_id": 11, "city_id": 1101}, ...]
            search_params: 搜索参数
            max_workers: 最大并发数
        
        Returns:
            按地区分组的搜索结果
        """
        results = {}        
        with ThreadPoolExecutor(max_workers=max_workers) as executor:            # 提交所有地区搜索任务
            future_to_region = {
                executor.submit(                    self.client.search_all_used_cars,
                    **{**search_params, **region}
                ): region                for region in regions
            }            
            # 收集结果
            for future in as_completed(future_to_region):
                region = future_to_region[future]                try:
                    region_cars = future.result(timeout=300)  # 5分钟超时
                    region_key = f"{region.get('province_id')}_{region.get('city_id')}"
                    results[region_key] = region_cars                except Exception as e:                    print(f"地区 {region} 搜索失败: {e}")        
        return results    
    def analyze_regional_prices(
        self,
        regional_results: Dict[str, List[UsedCarBasicInfo]]    ) -> Dict[str, Dict[str, float]]:        """
        分析地区价格差异
        """
        analysis = {}        
        for region_key, cars in regional_results.items():            if not cars:                continue
            
            prices = [car.price for car in cars if car.price > 0]
            mileages = [car.mileage for car in cars if car.mileage > 0]
            years = [car.year for car in cars if car.year > 0]
            
            analysis[region_key] = {                'avg_price': sum(prices) / len(prices) if prices else 0,                'avg_mileage': sum(mileages) / len(mileages) if mileages else 0,                'avg_year': sum(years) / len(years) if years else 0,                'car_count': len(cars)
            }        
        return analysis

七、实战应用场景

7.1 二手车比价平台

class UsedCarPriceComparator:    """二手车比价平台"""
    
    def __init__(self, api_client):        self.client = api_client        self.price_history = {}    
    def compare_prices_by_model(
        self,
        brand: str,
        model: str,
        regions: List[Dict[str, int]],
        year_range: Tuple[int, int] = (2018, 2023)    ) -> Dict[str, Any]:        """
        按车型比较地区价格差异
        """
        # 搜索各地区的同款车型
        search_params = {            'min_year': year_range[0],            'max_year': year_range[1],            'keyword': f"{brand} {model}"
        }
        
        regional_results = self.client.batch_search_by_regions(regions, search_params)        
        # 分析价格差异
        price_analysis = self.client.analyze_regional_prices(regional_results)        
        # 生成价格对比报告
        report = {            'brand': brand,            'model': model,            'year_range': year_range,            'regional_prices': price_analysis,            'recommendation': self._generate_recommendation(price_analysis)
        }        
        return report    
    def track_price_trend(
        self,
        car_id: int,
        duration_days: int = 30
    ) -> List[Dict[str, Any]]:        """
        跟踪二手车价格趋势
        """
        price_history = []        
        # 模拟获取历史价格数据
        for i in range(duration_days, 0, -1):            # 实际应用中可以从数据库获取历史数据
            # 这里简化实现
            price_point = {                'date': (datetime.now() - timedelta(days=i)).strftime('%Y-%m-%d'),                'price': 25.5 + random.uniform(-1, 1),  # 模拟价格波动
                'market_avg': 26.0 + random.uniform(-0.5, 0.5)
            }
            price_history.append(price_point)        
        return price_history

7.2 二手车推荐系统

class UsedCarRecommender:    """二手车推荐系统"""
    
    def __init__(self, api_client):        self.client = api_client    
    def recommend_cars_by_budget(
        self,
        budget: float,
        user_preferences: Dict[str, Any],
        region: Dict[str, int]    ) -> List[UsedCarBasicInfo]:        """
        根据预算推荐二手车
        """
        # 构建搜索参数
        search_params = {            'province_id': region.get('province_id'),            'city_id': region.get('city_id'),            'min_price': max(1, budget * 0.7),  # 预算的70%作为最低价
            'max_price': budget * 1.1,  # 预算的110%作为最高价
            'min_year': user_preferences.get('min_year', 2018),            'max_mileage': user_preferences.get('max_mileage', 15),            'fuel_type': user_preferences.get('fuel_type'),            'body_type': user_preferences.get('body_type'),            'sort_field': 'publish_time',            'sort_order': 'desc'
        }        
        # 执行搜索
        result = self.client.search_used_cars(**search_params)        
        if not result.success:            return []
        
        cars = result.used_cars        
        # 应用推荐算法
        recommended_cars = self._apply_recommendation_algorithm(cars, user_preferences)        
        return recommended_cars[:10]  # 返回前10个推荐
    
    def _apply_recommendation_algorithm(
        self,
        cars: List[UsedCarBasicInfo],
        preferences: Dict[str, Any]    ) -> List[UsedCarBasicInfo]:        """应用推荐算法"""
        scored_cars = []        
        for car in cars:
            score = 0
            
            # 价格得分(越接近预算上限得分越高)
            target_price = preferences.get('target_price', car.price)
            price_diff = abs(car.price - target_price)
            price_score = max(0, 100 - price_diff * 10)
            score += price_score * 0.3
            
            # 车龄得分
            current_year = datetime.now().year
            car_age = current_year - car.year
            age_score = max(0, 100 - car_age * 5)
            score += age_score * 0.25
            
            # 里程得分
            mileage_score = max(0, 100 - car.mileage * 2)
            score += mileage_score * 0.2
            
            # 品牌偏好得分
            preferred_brands = preferences.get('preferred_brands', [])            if car.brand in preferred_brands:
                score += 50
            
            # 发布时间得分(越新越好)
            publish_time = datetime.fromisoformat(car.publish_time.replace(' ', 'T'))
            days_ago = (datetime.now() - publish_time).days
            recency_score = max(0, 100 - days_ago)
            score += recency_score * 0.1
            
            scored_cars.append((car, score))        
        # 按得分排序
        scored_cars.sort(key=lambda x: x[1], reverse=True)        
        return [car for car, score in scored_cars]

八、故障排查与优化

8.1 常见问题解决

问题1:签名验证失败

def debug_signature_generation(params, app_secret, timestamp):    """调试签名生成过程"""
    print("=== 签名调试信息 ===")    
    # 排序参数
    sorted_params = sorted(params.items())
    param_str = '&'.join([f"{k}={v}" for k, v in sorted_params])    print(f"参数字符串: {param_str}")    
    # 构建签名字符串
    sign_str = f"{app_key}{param_str}{timestamp}{app_secret}"
    print(f"签名字符串: {sign_str}")    
    # 计算签名
    import hmac
    signature = hmac.new(
        app_secret.encode('utf-8'),
        sign_str.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()    print(f"计算签名: {signature}")    
    return signature

问题2:分页数据异常

def stable_pagination_search(self, **params):    """稳定的分页搜索"""
    # 确保有排序字段
    if 'sort_field' not in params:
        params['sort_field'] = 'id'  # 使用唯一字段排序
    
    if 'sort_order' not in params:
        params['sort_order'] = 'desc'
    
    # 使用游标分页
    all_cars = []
    last_id = None
    
    while True:        if last_id:            # 使用游标进行分页
            params['cursor'] = last_id
        
        result = self.search_used_cars(**params)        
        if not result.success or not result.used_cars:            break
        
        all_cars.extend(result.used_cars)
        last_id = result.used_cars[-1].car_id        
        # 检查是否还有更多数据
        pagination = result.pagination        if not pagination.get('has_next', False):            break
        
        # 避免频繁请求
        time.sleep(0.5)    
    return all_cars

8.2 性能优化建议

  1. 合理使用缓存

# 多级缓存策略class MultiLevelCache:    def __init__(self, redis_client):        self.memory_cache = {}        self.redis = redis_client        self.memory_ttl = 300  # 5分钟
        self.redis_ttl = 3600  # 1小时
    
    def get_used_car_data(self, cache_key):        # 1. 检查内存缓存
        if cache_key in self.memory_cache:
            data, expire_time = self.memory_cache[cache_key]            if time.time() < expire_time:                return data        
        # 2. 检查Redis缓存
        if self.redis:
            cached = self.redis.get(cache_key)            if cached:
                data = json.loads(cached)                # 更新内存缓存
                self.memory_cache[cache_key] = (data, time.time() + self.memory_ttl)                return data        
        return None
  1. 批量请求优化

import asyncioimport aiohttpasync def batch_search_async(api_client, search_queries):    """异步批量搜索"""
    async with aiohttp.ClientSession() as session:
        tasks = []        for query in search_queries:
            task = api_client.search_used_cars_async(session, **query)
            tasks.append(task)
        
        results = await asyncio.gather(*tasks, return_exceptions=True)        return results

九、最佳实践总结

9.1 安全实践

  1. 密钥管理:使用环境变量存储API密钥

  2. HTTPS强制:确保所有请求使用HTTPS

  3. 输入验证:验证所有输入参数

  4. 错误处理:不暴露敏感错误信息

9.2 性能实践

  1. 缓存策略:根据数据更新频率设置合适的缓存时间

  2. 批量操作:合并多个请求减少API调用次数

  3. 分页优化:使用游标分页提高稳定性

  4. 异步处理:批量操作使用异步方式提高吞吐量

9.3 业务实践

  1. 地区数据管理:维护地区ID映射表

  2. 品牌车系管理:缓存品牌车系信息

  3. 价格趋势分析:记录历史价格数据

  4. 推荐算法优化:基于用户行为优化推荐


附录:快速开始模板

# quick_start.pyfrom autohome_usedcar import AutoHomeUsedCarAPI# 1. 初始化客户端client = AutoHomeUsedCarAPI(
    app_key="your_app_key",
    app_secret="your_app_secret",
    sandbox=True)# 2. 简单搜索result = client.search_used_cars(
    province_id=11,  # 北京
    min_price=10,
    max_price=30,
    min_year=2018)if result.success:    for car in result.used_cars:        print(f"{car.brand} {car.series} - {car.price}万")# 3. 批量获取all_cars = client.search_all_used_cars(
    province_id=11,
    min_price=15,
    max_price=25)print(f"共找到 {len(all_cars)} 辆二手车")# 4. 获取详情car_detail = client.get_used_car_detail(12345)if car_detail:    print(f"车辆详情: {car_detail.basic_info.title}")
通过本攻略,您应该能够:
  • 理解汽车之家二手车搜索接口的完整功能

  • 实现安全的API认证和请求

  • 处理各种搜索条件和分页逻辑

  • 构建高性能的二手车搜索应用

  • 在实际业务中灵活应用该接口

建议根据实际业务需求选择合适的实现方案,并遵循最佳实践确保系统的稳定性和可维护性。


群贤毕至

访客