×

懂车帝item_get - 获取详情数据接口对接全攻略:从入门到精通

万邦科技Lex 万邦科技Lex 发表于2026-02-03 09:10:34 浏览27 评论0

抢沙发发表评论

一、接口概览

1.1 接口简介

item_get接口是懂车帝开放平台的核心接口之一,用于获取车辆的完整详细信息,包括车辆基本参数、配置信息、图片、价格、评测数据、用户评价等全方位数据。

1.2 接口特性

  • 数据全面:返回车辆的全维度信息,涵盖技术参数、配置、图片、价格等

  • 实时更新:数据与懂车帝APP/网站保持同步

  • 结构化返回:JSON格式,字段定义清晰,便于解析

  • 权限分级:支持不同数据粒度的访问权限控制

二、准备工作

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 DongchediConfig:    # 懂车帝API配置
    DONGCHEDI_APP_KEY = os.getenv('DONGCHEDI_APP_KEY')
    DONGCHEDI_APP_SECRET = os.getenv('DONGCHEDI_APP_SECRET')
    DONGCHEDI_API_BASE = os.getenv('DONGCHEDI_API_BASE', 
        'https://openapi.dongchedi.com/api/v1'
    )    
    # 请求配置
    REQUEST_TIMEOUT = 30
    MAX_RETRIES = 3
    DEFAULT_PAGE_SIZE = 20
    
    # 缓存配置
    CACHE_TTL = 3600  # 1小时

三、接口详解

3.1 接口地址

GET /vehicle/{vehicle_id}

3.2 请求参数详解

公共参数

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

业务参数

参数名
类型
必填
说明
示例
vehicle_id
int
车辆ID
12345
include_images
bool
是否包含图片
true
include_specs
bool
是否包含详细配置
true
include_prices
bool
是否包含价格信息
true
include_reviews
bool
是否包含用户评价
true
include_ratings
bool
是否包含评分数据
true
include_dealers
bool
是否包含经销商信息
true
fields
string
指定返回字段
id,title,price,brand,series

3.3 签名算法

import hashlibimport hmacfrom typing import Dict, Anydef generate_signature(params: Dict[str, Any], app_secret: str) -> str:    """
    生成懂车帝API请求签名
    # 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
    Args:
        params: 请求参数字典
        app_secret: 应用密钥
    
    Returns:
        签名字符串
    """
    # 1. 过滤空值和sign参数,按键名ASCII升序排序
    filtered_params = {
        k: v for k, v in params.items() 
        if v is not None and k != 'sign'
    }
    sorted_keys = sorted(filtered_params.keys())    
    # 2. 拼接键值对
    sign_str = ''
    for key in sorted_keys:        if isinstance(filtered_params[key], (list, dict)):            # 处理复杂类型参数
            import json
            value = json.dumps(filtered_params[key], separators=(',', ':'))        else:
            value = str(filtered_params[key])
        sign_str += f"{key}{value}"
    
    # 3. 拼接app_secret
    sign_str += app_secret    
    # 4. 计算HMAC-SHA256签名
    signature = hmac.new(
        app_secret.encode('utf-8'),
        sign_str.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()    
    return signature

四、完整代码实现

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 VehicleBasicInfo:    """车辆基本信息"""
    vehicle_id: int
    title: str
    brand: str
    series: str
    model: str
    year: int
    fuel_type: str
    transmission: str
    body_type: str
    displacement: str
    power: str
    torque: str
    fuel_consumption: str
    msrp: float
    market_price: float
    create_time: str
    update_time: str@dataclassclass VehicleImage:    """车辆图片信息"""
    image_id: int
    url: str
    title: str
    type: str  # exterior, interior, detail, 360
    size: str  # small, medium, large, original
    width: int
    height: int@dataclassclass VehicleSpec:    """车辆配置信息"""
    category: str
    name: str
    value: str
    description: str
    is_standard: bool@dataclassclass VehiclePrice:    """车辆价格信息"""
    price_type: str  # msrp, dealer_price, market_price, min_price, max_price
    amount: float
    currency: str
    region: str
    update_time: str@dataclassclass VehicleReview:    """车辆评价信息"""
    review_id: int
    user_id: int
    user_name: str
    rating: float
    title: str
    content: str
    create_time: str
    helpful_count: int
    comment_count: int
    pros: List[str]
    cons: List[str]@dataclassclass VehicleRating:    """车辆评分信息"""
    overall: float
    exterior: float
    interior: float
    performance: float
    comfort: float
    fuel_economy: float
    safety: float
    technology: float
    review_count: int
    recommend_rate: floatclass DongchediAPI:    """懂车帝API客户端"""
    # 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
    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.dongchedi.com" if sandbox else "https://openapi.dongchedi.com"
        self.session = requests.Session()        self.session.headers.update({            'User-Agent': 'Dongchedi-API-Client/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:        """生成请求签名"""
        # 过滤并排序参数
        filtered_params = {
            k: v for k, v in params.items() 
            if v is not None and k != 'sign'
        }
        sorted_keys = sorted(filtered_params.keys())        
        # 拼接参数字符串
        sign_str = ''
        for key in sorted_keys:            if isinstance(filtered_params[key], (list, dict)):
                value = json.dumps(filtered_params[key], separators=(',', ':'))            else:
                value = str(filtered_params[key])
            sign_str += f"{key}{value}"
        # 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
        # 添加app_secret
        sign_str += 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 get_vehicle_detail(
        self,
        vehicle_id: int,
        include_images: bool = True,
        include_specs: bool = True,
        include_prices: bool = True,
        include_reviews: bool = False,
        include_ratings: bool = True,
        include_dealers: bool = False,
        fields: Optional[List[str]] = None
    ) -> Dict[str, Any]:        """
        获取车辆详细信息
        
        Args:
            vehicle_id: 车辆ID
            include_images: 是否包含图片
            include_specs: 是否包含详细配置
            include_prices: 是否包含价格信息
            include_reviews: 是否包含用户评价
            include_ratings: 是否包含评分数据
            include_dealers: 是否包含经销商信息
            fields: 指定返回字段
        
        Returns:
            车辆详情数据
        """
        # 获取访问令牌
        access_token = self._get_access_token()        
        # 构建请求参数
        params = {            'app_key': self.app_key,            'timestamp': int(time.time()),            'format': 'json',            'version': '1.0',            'include_images': str(include_images).lower(),            'include_specs': str(include_specs).lower(),            'include_prices': str(include_prices).lower(),            'include_reviews': str(include_reviews).lower(),            'include_ratings': str(include_ratings).lower(),            'include_dealers': str(include_dealers).lower()
        }        
        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/vehicle/{vehicle_id}"
        
        try:
            response = self.session.get(
                url,
                params=params,
                headers=headers,
                timeout=DongchediConfig.REQUEST_TIMEOUT
            )            
            if response.status_code == 200:                return response.json()            elif response.status_code == 404:                raise VehicleNotFoundException(f"车辆ID {vehicle_id} 不存在")            elif response.status_code == 401:                # Token过期,重新获取
                self._access_token = None
                return self.get_vehicle_detail(
                    vehicle_id, include_images, include_specs, 
                    include_prices, include_reviews, include_ratings, 
                    include_dealers, fields
                )            else:                raise Exception(f"请求失败: {response.status_code} - {response.text}")                
        except requests.exceptions.Timeout:            raise Exception("请求超时")        except requests.exceptions.RequestException as e:            raise Exception(f"网络请求异常: {str(e)}")    
    def get_vehicle_detail_structured(
        self,
        vehicle_id: int,
        **kwargs    ) -> Dict[str, Any]:        """
        获取结构化的车辆详情信息
        """
        raw_data = self.get_vehicle_detail(vehicle_id, **kwargs)        
        if not raw_data.get('success'):            raise Exception(f"获取车辆详情失败: {raw_data.get('message')}")
        
        data = raw_data.get('data', {})        
        # 解析基础信息
        basic_info = VehicleBasicInfo(
            vehicle_id=data.get('id'),
            title=data.get('title', ''),
            brand=data.get('brand', {}).get('name', ''),
            series=data.get('series', {}).get('name', ''),
            model=data.get('model', ''),
            year=data.get('year', 0),
            fuel_type=data.get('fuel_type', ''),
            transmission=data.get('transmission', ''),
            body_type=data.get('body_type', ''),
            displacement=data.get('displacement', ''),
            power=data.get('power', ''),
            torque=data.get('torque', ''),
            fuel_consumption=data.get('fuel_consumption', ''),
            msrp=data.get('msrp', 0),
            market_price=data.get('market_price', 0),
            create_time=data.get('create_time', ''),
            update_time=data.get('update_time', '')
        )        
        # 解析图片信息
        images = []        for img_data in data.get('images', []):
            images.append(VehicleImage(
                image_id=img_data.get('id'),
                url=img_data.get('url'),
                title=img_data.get('title'),                type=img_data.get('type'),
                size=img_data.get('size'),
                width=img_data.get('width'),
                height=img_data.get('height')
            ))        
        # 解析配置信息
        specs = []        for spec_data in data.get('specs', []):
            specs.append(VehicleSpec(
                category=spec_data.get('category'),
                name=spec_data.get('name'),
                value=spec_data.get('value'),
                description=spec_data.get('description'),
                is_standard=spec_data.get('is_standard', False)
            ))        
        # 解析价格信息
        prices = []        for price_data in data.get('prices', []):
            prices.append(VehiclePrice(
                price_type=price_data.get('type'),
                amount=price_data.get('amount'),
                currency=price_data.get('currency'),
                region=price_data.get('region'),
                update_time=price_data.get('update_time')
            ))        
        # 解析评分信息
        rating_data = data.get('rating', {})
        rating = VehicleRating(
            overall=rating_data.get('overall', 0),
            exterior=rating_data.get('exterior', 0),
            interior=rating_data.get('interior', 0),
            performance=rating_data.get('performance', 0),
            comfort=rating_data.get('comfort', 0),
            fuel_economy=rating_data.get('fuel_economy', 0),
            safety=rating_data.get('safety', 0),
            technology=rating_data.get('technology', 0),
            review_count=rating_data.get('review_count', 0),
            recommend_rate=rating_data.get('recommend_rate', 0)
        )        
        # 解析评价信息
        reviews = []        for review_data in data.get('reviews', []):
            reviews.append(VehicleReview(
                review_id=review_data.get('id'),
                user_id=review_data.get('user_id'),
                user_name=review_data.get('user_name'),
                rating=review_data.get('rating'),
                title=review_data.get('title'),
                content=review_data.get('content'),
                create_time=review_data.get('create_time'),
                helpful_count=review_data.get('helpful_count'),
                comment_count=review_data.get('comment_count'),
                pros=review_data.get('pros', []),
                cons=review_data.get('cons', [])
            ))        
        return {            'basic_info': basic_info,            'images': images,            'specs': specs,            'prices': prices,            'rating': rating,            'reviews': reviews,            'raw_data': raw_data
        }    
    def batch_get_vehicle_details(
        self,
        vehicle_ids: List[int],
        max_workers: int = 5,
        **kwargs    ) -> Dict[int, Dict[str, Any]]:        """
        批量获取车辆详情
        """
        from concurrent.futures import ThreadPoolExecutor, as_completed
        
        results = {}        
        with ThreadPoolExecutor(max_workers=max_workers) as executor:            # 提交所有任务
            future_to_id = {
                executor.submit(self.get_vehicle_detail, vehicle_id, **kwargs): vehicle_id                for vehicle_id in vehicle_ids
            }            
            # 收集结果
            for future in as_completed(future_to_id):
                vehicle_id = future_to_id[future]                try:
                    result = future.result(timeout=30)
                    results[vehicle_id] = result                except Exception as e:                    print(f"获取车辆 {vehicle_id} 详情失败: {e}")
                    results[vehicle_id] = {'error': str(e)}        
        return resultsclass VehicleNotFoundException(Exception):    """车辆不存在异常"""
    pass# 使用示例def demo_dongchedi_api():    """懂车帝API使用演示"""
    
    # 初始化客户端
    client = DongchediAPI(
        app_key=DongchediConfig.DONGCHEDI_APP_KEY,
        app_secret=DongchediConfig.DONGCHEDI_APP_SECRET,
        sandbox=True
    )    
    # 获取单个车辆详情
    print("=== 获取单个车辆详情 ===")
    vehicle_detail = client.get_vehicle_detail(12345)    print(json.dumps(vehicle_detail, ensure_ascii=False, indent=2))    
    # 获取结构化信息
    print("\n=== 获取结构化车辆信息 ===")
    structured_info = client.get_vehicle_detail_structured(12345)
    basic_info = structured_info['basic_info']    print(f"车辆: {basic_info.brand} {basic_info.series} {basic_info.model}")    print(f"指导价: {basic_info.msrp}万")    print(f"市场价: {basic_info.market_price}万")    print(f"综合评分: {structured_info['rating'].overall}")    
    # 批量获取
    print("\n=== 批量获取车辆详情 ===")
    vehicle_ids = [12345, 12346, 12347, 12348]
    batch_results = client.batch_get_vehicle_details(vehicle_ids)    for vid, result in batch_results.items():        if 'error' not in result:
            data = result.get('data', {})            print(f"车辆 {vid}: {data.get('brand', {}).get('name')} {data.get('model')}")        else:            print(f"车辆 {vid}: 获取失败 - {result['error']}")if __name__ == "__main__":
    demo_dongchedi_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 DongchediApiClient {    private static final Logger logger = LoggerFactory.getLogger(DongchediApiClient.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 DongchediApiClient(String appKey, String appSecret, boolean sandbox) {        this.appKey = appKey;        this.appSecret = appSecret;        this.baseUrl = sandbox ? 
            "https://sandbox-openapi.dongchedi.com" : 
            "https://openapi.dongchedi.com";        
        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 Map<String, Object> getVehicleDetail(int vehicleId, Map<String, Object> params) throws IOException {        // 获取访问令牌
        String token = getAccessToken();        
        // 构建请求URL
        HttpUrl.Builder urlBuilder = HttpUrl.parse(baseUrl + "/api/v1/vehicle/" + vehicleId).newBuilder();        
        if (params != null) {            for (Map.Entry<String, Object> param : params.entrySet()) {
                urlBuilder.addQueryParameter(param.getKey(), param.getValue().toString());
            }
        }        
        // 构建请求
        Request request = new Request.Builder()
                .url(urlBuilder.build())
                .addHeader("Authorization", "Bearer " + token)
                .addHeader("Content-Type", "application/json")
                .addHeader("User-Agent", "Dongchedi-Java-Client/1.0")
                .build();  
                # 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex      
        // 发送请求
        try (Response response = httpClient.newCall(request).execute()) {            if (response.isSuccessful()) {                String responseBody = response.body().string();                return objectMapper.readValue(responseBody, Map.class);
            } else if (response.code() == 404) {                throw new VehicleNotFoundException("车辆ID " + vehicleId + " 不存在");
            } else if (response.code() == 401) {                // Token过期,重新获取
                this.accessToken = null;                return getVehicleDetail(vehicleId, params);
            } else {                throw new IOException("请求失败: " + response.code() + " - " + response.message());
            }
        }
    }    
    private String getAccessToken() throws IOException {        // 检查token是否有效
        if (accessToken != null && tokenExpires != null && tokenExpires.isAfter(LocalDateTime.now())) {            return accessToken;
        }        
        // 获取新token
        long timestamp = System.currentTimeMillis() / 1000;
        Map<String, Object> params = new HashMap<>();
        params.put("app_key", appKey);
        params.put("timestamp", timestamp);
        params.put("grant_type", "client_credentials");        
        // 生成签名
        String signature = generateSignature(params, timestamp);
        params.put("sign", signature);        
        // 构建请求
        FormBody.Builder formBuilder = new FormBody.Builder();        for (Map.Entry<String, Object> param : params.entrySet()) {
            formBuilder.add(param.getKey(), param.getValue().toString());
        }        
        Request request = new Request.Builder()
                .url(baseUrl + "/oauth/token")
                .post(formBuilder.build())
                .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);                this.accessToken = (String) result.get("access_token");                int expiresIn = (Integer) result.get("expires_in");                this.tokenExpires = LocalDateTime.now().plusSeconds(expiresIn - 300); // 提前5分钟过期
                return accessToken;
            } else {                throw new IOException("获取token失败: " + response.code());
            }
        }
    }    
    private String generateSignature(Map<String, Object> params, long timestamp) {        try {            // 排序参数
            List<String> keys = new ArrayList<>(params.keySet());
            Collections.sort(keys);            
            // 构建参数字符串
            StringBuilder paramStr = new StringBuilder();            for (String key : keys) {
                paramStr.append(key).append("=").append(params.get(key)).append("&");
            }            if (paramStr.length() > 0) {
                paramStr.deleteCharAt(paramStr.length() - 1); // 移除最后一个&
            }            
            // 构建签名字符串
            String signStr = appKey + paramStr.toString() + timestamp + appSecret;            
            // 计算HMAC-SHA256
            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");            SecretKeySpec secret_key = new SecretKeySpec(appSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            sha256_HMAC.init(secret_key);            byte[] hash = sha256_HMAC.doFinal(signStr.getBytes(StandardCharsets.UTF_8));            
            // 转换为十六进制
            StringBuilder hexString = new StringBuilder();            for (byte b : hash) {                String hex = Integer.toHexString(0xff & b);                if (hex.length() == 1) hexString.append('0');
                hexString.append(hex);
            }            
            return hexString.toString();
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {            throw new RuntimeException("生成签名失败", e);
        }
    }
}class VehicleNotFoundException extends RuntimeException {    public VehicleNotFoundException(String message) {        super(message);
    }
}

4.3 PHP实现

<?phpclass DongchediApiClient{    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.dongchedi.com'
            : 'https://openapi.dongchedi.com';
    }    
    public function getVehicleDetail($vehicleId, $params = [])    {        // 获取访问令牌
        $token = $this->getAccessToken();        
        // 构建请求URL
        $url = $this->baseUrl . '/api/v1/vehicle/' . $vehicleId;        if (!empty($params)) {            $url .= '?' . http_build_query($params);
        }        
        // 发送请求
        $ch = curl_init();        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HTTPHEADER => [                'Authorization: Bearer ' . $token,                'Content-Type: application/json',                'User-Agent: Dongchedi-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);
        } elseif ($httpCode === 404) {            throw new Exception("车辆ID {$vehicleId} 不存在");
        } elseif ($httpCode === 401) {            // Token过期,重新获取
            $this->accessToken = null;            return $this->getVehicleDetail($vehicleId, $params);
        } else {            throw new Exception("请求失败: HTTP {$httpCode}");
        }
    }  # 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex  
    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, $timestamp);        $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, $timestamp)    {        // 排序参数
        ksort($params);        $paramStr = '';        foreach ($params as $key => $value) {            $paramStr .= $key . '=' . $value . '&';
        }        $paramStr = rtrim($paramStr, '&');        
        // 构建签名字符串
        $signStr = $this->appKey . $paramStr . $timestamp . $this->appSecret;        
        // 计算HMAC-SHA256
        return hash_hmac('sha256', $signStr, $this->appSecret);
    }
}// 使用示例try {    $client = new DongchediApiClient('your_app_key', 'your_app_secret', true);    $vehicleDetail = $client->getVehicleDetail(12345, [        'include_images' => 'true',        'include_specs' => 'true',        'include_ratings' => 'true'
    ]);    
    echo "车辆信息:\n";    echo "品牌: " . $vehicleDetail['data']['brand']['name'] . "\n";    echo "车系: " . $vehicleDetail['data']['series']['name'] . "\n";    echo "车型: " . $vehicleDetail['data']['model'] . "\n";    echo "综合评分: " . $vehicleDetail['data']['rating']['overall'] . "\n";
    
} catch (Exception $e) {    echo "错误: " . $e->getMessage() . "\n";
}?>

五、返回结果解析

5.1 成功响应示例

{
  "success": true,
  "code": 200,
  "message": "成功",
  "data": {
    "id": 12345,
    "title": "2023款 宝马3系 325Li M运动套装",
    "brand": {
      "id": 2,
      "name": "宝马",
      "logo": "https://img.dongchedi.com/brand/2.png"
    },
    "series": {
      "id": 20,
      "name": "3系",
      "image": "https://img.dongchedi.com/series/20.jpg"
    },
    "model": "325Li M运动套装",
    "year": 2023,
    "fuel_type": "汽油",
    "transmission": "8挡手自一体",
    "body_type": "轿车",
    "displacement": "2.0T",
    "power": "184马力/5000-6500rpm",
    "torque": "300牛·米/1350-4000rpm",
    "fuel_consumption": "6.2L/100km",
    "msrp": 34.99,
    "market_price": 32.5,
    "images": [
      {
        "id": 1,
        "url": "https://img.dongchedi.com/vehicle/12345_1.jpg",
        "title": "外观前脸",
        "type": "exterior",
        "size": "large",
        "width": 1920,
        "height": 1080
      }
    ],
    "specs": [
      {
        "category": "车身",
        "name": "长宽高",
        "value": "4838×1827×1454mm",
        "description": "车身尺寸",
        "is_standard": true
      }
    ],
    "prices": [
      {
        "type": "msrp",
        "amount": 34.99,
        "currency": "CNY",
        "region": "全国",
        "update_time": "2023-01-15 10:00:00"
      }
    ],
    "rating": {
      "overall": 4.5,
      "exterior": 4.7,
      "interior": 4.3,
      "performance": 4.6,
      "comfort": 4.4,
      "fuel_economy": 4.2,
      "safety": 4.8,
      "technology": 4.5,
      "review_count": 1250,
      "recommend_rate": 92.5
    },
    "reviews": [
      {
        "id": 1001,
        "user_id": 5001,
        "user_name": "懂车帝用户",
        "rating": 5.0,
        "title": "操控性很棒,动力充沛",
        "content": "3系的操控性确实名不虚传...",
        "create_time": "2023-05-20 14:30:00",
        "helpful_count": 25,
        "comment_count": 8,
        "pros": ["操控好", "动力强", "外观漂亮"],
        "cons": ["后排空间一般", "油耗偏高"]
      }
    ],
    "create_time": "2022-12-01 09:00:00",
    "update_time": "2023-06-15 16:30:00"
  }}

5.2 错误响应示例

{
  "success": false,
  "code": 404,
  "message": "车辆不存在",
  "data": null}

5.3 状态码说明

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

六、高级功能实现

6.1 智能数据解析

class IntelligentVehicleParser:    """智能车辆数据解析器"""
    
    def __init__(self):        self.spec_categories = {            '车身': ['长宽高', '轴距', '整备质量', '车门数'],            '发动机': ['排量', '最大功率', '最大扭矩', '气缸数', '燃料形式'],            '变速箱': ['变速箱类型', '挡位个数'],            '底盘转向': ['驱动方式', '前悬架', '后悬架'],            '车轮制动': ['前制动器', '后制动器', '驻车制动'],            '安全配置': ['气囊数量', 'ABS', 'ESP'],            '舒适配置': ['座椅材质', '空调类型', '天窗']
        }    
    def parse_vehicle_specs(self, specs: List[VehicleSpec]) -> Dict[str, Dict[str, str]]:        """解析车辆配置信息"""
        parsed_specs = {}        
        for category in self.spec_categories.keys():
            parsed_specs[category] = {}        
        for spec in specs:            for category, spec_names in self.spec_categories.items():                if spec.name in spec_names:
                    parsed_specs[category][spec.name] = spec.value                    break
            else:                # 未分类的配置
                if '其他' not in parsed_specs:
                    parsed_specs['其他'] = {}
                parsed_specs['其他'][spec.name] = spec.value        
        return parsed_specs    
    def extract_technical_data(self, vehicle_data: Dict[str, Any]) -> Dict[str, Any]:        """提取技术数据"""
        basic_info = vehicle_data.get('basic_info', {})        
        # 解析功率和扭矩
        power_match = re.search(r'(\d+(\.\d+)?)', basic_info.power or '')
        torque_match = re.search(r'(\d+(\.\d+)?)', basic_info.torque or '')
        fuel_match = re.search(r'(\d+(\.\d+)?)', basic_info.fuel_consumption or '')        
        return {            'power_kw': float(power_match.group(1)) * 0.735 if power_match else None,            'torque_nm': float(torque_match.group(1)) if torque_match else None,            'fuel_consumption_l_100km': float(fuel_match.group(1)) if fuel_match else None,            'displacement_cc': self._parse_displacement(basic_info.displacement or ''),            'transmission_type': self._classify_transmission(basic_info.transmission or ''),            'body_type_code': self._classify_body_type(basic_info.body_type or '')
        }    
    def _parse_displacement(self, displacement: str) -> int:        """解析排量"""
        match = re.search(r'(\d+(\.\d+)?)', displacement)        if match:            return int(float(match.group(1)) * 1000)        return 0
    
    def _classify_transmission(self, transmission: str) -> str:        """分类变速箱类型"""
        if '手自一体' in transmission or 'AT' in transmission:            return 'AT'
        elif '双离合' in transmission or 'DCT' in transmission:            return 'DCT'
        elif '无级变速' in transmission or 'CVT' in transmission:            return 'CVT'
        elif '手动' in transmission or 'MT' in transmission:            return 'MT'
        else:            return 'UNKNOWN'
    
    def _classify_body_type(self, body_type: str) -> str:        """分类车身类型"""
        mapping = {            '轿车': 'SEDAN',            'SUV': 'SUV',            'MPV': 'MPV',            '跑车': 'COUPE',            '皮卡': 'PICKUP',            '微面': 'VAN'
        }        return mapping.get(body_type, 'UNKNOWN')

6.2 数据缓存优化

import redisfrom functools import lru_cacheclass CachedDongchediAPI(DongchediAPI):    """带缓存的懂车帝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 = "dongchedi:vehicle:"
        @lru_cache(maxsize=1000)
    def get_vehicle_detail_cached(self, vehicle_id: int, **kwargs) -> Dict[str, Any]:        """
        带缓存的车辆详情获取
        """
        cache_key = f"{self.cache_prefix}{vehicle_id}"
        
        # 检查Redis缓存
        if self.redis:
            cached = self.redis.get(cache_key)            if cached:                return json.loads(cached)        
        # 调用API
        data = super().get_vehicle_detail(vehicle_id, **kwargs)        
        # 缓存到Redis
        if self.redis and data.get('success'):            # 根据数据更新频率设置不同TTL
            ttl = self._calculate_ttl(data)            self.redis.setex(cache_key, ttl, json.dumps(data))        
        return data    
    def _calculate_ttl(self, vehicle_data: Dict[str, Any]) -> int:        """根据车辆信息计算缓存时间"""
        year = vehicle_data.get('data', {}).get('year', 0)
        current_year = datetime.now().year        
        # 老车型缓存时间更长
        if year < current_year - 3:            return 24 * 3600  # 24小时
        elif year < current_year - 1:            return 12 * 3600  # 12小时
        else:            return 3600  # 1小时

6.3 批量处理优化

import asyncioimport aiohttpclass AsyncDongchediAPI:    """异步懂车帝API客户端"""
    
    def __init__(self, app_key, app_secret, sandbox=True):        self.app_key = app_key        self.app_secret = app_secret        self.base_url = "https://sandbox-openapi.dongchedi.com" if sandbox else "https://openapi.dongchedi.com"
        self.session = None
        self.access_token = None
    
    async def __aenter__(self):        self.session = aiohttp.ClientSession()        await self._get_access_token()        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):        await self.session.close()    
    async def _get_access_token(self):        """异步获取访问令牌"""
        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        
        async with self.session.post(            f"{self.base_url}/oauth/token",
            data=params
        ) as response:            if response.status == 200:
                data = await response.json()                self.access_token = data['access_token']            else:                raise Exception(f"获取token失败: {response.status}")    
    async def get_vehicle_detail_async(self, vehicle_id: int, **kwargs) -> Dict[str, Any]:        """异步获取车辆详情"""
        params = {            'include_images': str(kwargs.get('include_images', True)).lower(),            'include_specs': str(kwargs.get('include_specs', True)).lower(),            'include_prices': str(kwargs.get('include_prices', True)).lower(),            'include_reviews': str(kwargs.get('include_reviews', False)).lower(),            'include_ratings': str(kwargs.get('include_ratings', True)).lower()
        }
        
        headers = {            'Authorization': f'Bearer {self.access_token}',            'Content-Type': 'application/json'
        }
        
        url = f"{self.base_url}/api/v1/vehicle/{vehicle_id}"
        
        async with self.session.get(
            url,
            params=params,
            headers=headers
        ) as response:            if response.status == 200:                return await response.json()            else:                raise Exception(f"请求失败: {response.status}")    
    async def batch_get_vehicle_details_async(
        self, 
        vehicle_ids: List[int], 
        **kwargs    ) -> Dict[int, Dict[str, Any]]:        """异步批量获取车辆详情"""
        tasks = []        for vehicle_id in vehicle_ids:
            task = self.get_vehicle_detail_async(vehicle_id, **kwargs)
            tasks.append(task)
        
        results = await asyncio.gather(*tasks, return_exceptions=True)        
        return {
            vehicle_id: result            for vehicle_id, result in zip(vehicle_ids, results)            if not isinstance(result, Exception)
        }# 使用示例async def demo_async_api():    """异步API使用示例"""
    async with AsyncDongchediAPI('your_app_key', 'your_app_secret') as client:
        vehicle_ids = [12345, 12346, 12347, 12348, 12349]
        results = await client.batch_get_vehicle_details_async(vehicle_ids)        
        for vehicle_id, result in results.items():            print(f"车辆 {vehicle_id}: {result.get('data', {}).get('model')}")

七、实战应用场景

7.1 汽车电商平台集成

class CarEcommercePlatform:    """汽车电商平台集成"""
    
    def __init__(self, dongchedi_client):        self.client = dongchedi_client        self.vehicle_cache = {}    
    def get_vehicle_display_info(self, vehicle_id: int) -> Dict[str, Any]:        """获取车辆展示信息"""
        # 获取车辆详情
        vehicle_data = self.client.get_vehicle_detail_structured(vehicle_id)
        basic_info = vehicle_data['basic_info']
        images = vehicle_data['images']
        rating = vehicle_data['rating']        
        # 构建展示信息
        display_info = {            'vehicle_id': vehicle_id,            'title': f"{basic_info.brand} {basic_info.series} {basic_info.model}",            'year': basic_info.year,            'specs': {                'fuel_type': basic_info.fuel_type,                'transmission': basic_info.transmission,                'power': basic_info.power,                'fuel_consumption': basic_info.fuel_consumption
            },            'main_image': self._get_main_image(images),            'price_info': {                'msrp': basic_info.msrp,                'market_price': basic_info.market_price,                'discount': basic_info.msrp - basic_info.market_price
            },            'rating_info': {                'overall': rating.overall,                'review_count': rating.rereview_count,                'recommend_rate': rating.recommend_rate
            },            'features': self._extract_features(vehicle_data)
        }        
        return display_info    
    def _get_main_image(self, images: List[VehicleImage]) -> str:        """获取主图"""
        for image in images:            if image.type == 'exterior' and image.size == 'large':                return image.url        return images[0].url if images else ''

7.2 汽车对比工具

class VehicleComparisonTool:    """车辆对比工具"""
    
    def __init__(self, dongchedi_client):        self.client = dongchedi_client    
    def compare_vehicles(self, vehicle_ids: List[int]) -> Dict[str, Any]:        """对比多个车辆"""
        if len(vehicle_ids) > 5:            raise Exception("最多支持同时对比5辆车")        
        # 获取车辆详情
        vehicle_details = self.client.batch_get_vehicle_details(vehicle_ids)        
        # 构建对比数据
        comparison_data = {            'vehicles': [],            'common_specs': self._get_common_specs(vehicle_details),            'price_comparison': self._compare_prices(vehicle_details),            'rating_comparison': self._compare_ratings(vehicle_details)
        }        
        for vehicle_id, detail in vehicle_details.items():            if 'error' not in detail:
                data = detail.get('data', {})
                comparison_data['vehicles'].append({                    'vehicle_id': vehicle_id,                    'basic_info': {                        'brand': data.get('brand', {}).get('name'),                        'series': data.get('series', {}).get('name'),                        'model': data.get('model'),                        'year': data.get('year'),                        'msrp': data.get('msrp')
                    },                    'rating': data.get('rating', {})
                })        
        return comparison_data    
    def _get_common_specs(self, vehicle_details: Dict[int, Dict[str, Any]]) -> List[Dict[str, Any]]:        """获取共同配置项"""
        all_spec_names = set()
        specs_by_vehicle = {}        
        for vehicle_id, detail in vehicle_details.items():            if 'error' not in detail:
                specs = detail.get('data', {}).get('specs', [])
                spec_names = [spec.get('name') for spec in specs]
                all_spec_names.update(spec_names)
                specs_by_vehicle[vehicle_id] = {spec.get('name'): spec.get('value') for spec in specs}        
        # 返回出现次数大于1的配置项
        common_specs = []        for spec_name in all_spec_names:
            spec_values = {}            for vehicle_id in vehicle_details.keys():                if vehicle_id in specs_by_vehicle and spec_name in specs_by_vehicle[vehicle_id]:
                    spec_values[vehicle_id] = specs_by_vehicle[vehicle_id][spec_name]            
            if len(spec_values) > 1:
                common_specs.append({                    'name': spec_name,                    'values': spec_values
                })        
        return common_specs[:10]  # 限制返回数量

八、故障排查与优化

8.1 常见问题解决

问题1:签名验证失败

def debug_signature_generation(params, app_secret, timestamp):    """调试签名生成过程"""
    print("=== 签名调试信息 ===")    
    # 排序参数
    sorted_params = sorted(params.items())
    param_str = ''
    for key, value in sorted_params:        if value is not None and key != 'sign':            if isinstance(value, (list, dict)):
                value = json.dumps(value, separators=(',', ':'))
            param_str += f"{key}{value}"
    
    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:Token过期处理

def get_vehicle_detail_with_retry(self, vehicle_id: int, max_retries: int = 3, **kwargs):    """带重试的车辆详情获取"""
    for attempt in range(max_retries):        try:            return self.get_vehicle_detail(vehicle_id, **kwargs)        except Exception as e:            if "401" in str(e) and attempt < max_retries - 1:                # Token过期,重新获取
                self._access_token = None
                time.sleep(1)                continue
            else:                raise

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_vehicle_data(self, vehicle_id):        # 1. 检查内存缓存
        if vehicle_id in self.memory_cache:
            data, expire_time = self.memory_cache[vehicle_id]            if time.time() < expire_time:                return data        
        # 2. 检查Redis缓存
        if self.redis:
            cache_key = f"dongchedi:vehicle:{vehicle_id}"
            cached = self.redis.get(cache_key)            if cached:
                data = json.loads(cached)                # 更新内存缓存
                self.memory_cache[vehicle_id] = (data, time.time() + self.memory_ttl)                return data        
        return None
  1. 批量请求优化

# 使用异步处理提高吞吐量async def process_vehicle_batch(vehicle_ids, batch_size=10):    """批量处理车辆数据"""
    results = []    
    for i in range(0, len(vehicle_ids), batch_size):
        batch = vehicle_ids[i:i+batch_size]
        batch_results = await asyncio.gather(*[
            get_vehicle_detail_async(vehicle_id)            for vehicle_id in batch
        ])
        results.extend(batch_results)        await asyncio.sleep(0.1)  # 避免频率限制
    
    return results

九、最佳实践总结

9.1 安全实践

  1. 密钥保护:使用环境变量存储API密钥

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

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

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

9.2 性能实践

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

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

  3. 异步处理:使用异步IO提高并发性能

  4. 连接复用:使用连接池减少连接建立开销

9.3 代码质量

  1. 异常处理:完善的异常处理和重试机制

  2. 日志记录:详细记录API调用情况

  3. 单元测试:编写测试用例覆盖主要功能

  4. 类型注解:使用类型注解提高代码可读性


附录:快速开始模板

# quick_start.pyfrom dongchedi_api import DongchediAPI# 1. 初始化客户端client = DongchediAPI(
    app_key="your_app_key",
    app_secret="your_app_secret",
    sandbox=True)# 2. 获取车辆详情vehicle_detail = client.get_vehicle_detail(12345)print(f"车辆: {vehicle_detail['data']['brand']['name']} {vehicle_detail['data']['model']}")# 3. 获取结构化信息structured_info = client.get_vehicle_detail_structured(12345)print(f"排量: {structured_info['basic_info'].displacement}")print(f"功率: {structured_info['basic_info'].power}")print(f"综合评分: {structured_info['rating'].overall}")# 4. 批量获取vehicle_ids = [12345, 12346, 12347]
batch_results = client.batch_get_vehicle_details(vehicle_ids)for vid, result in batch_results.items():    if 'error' not in result:
        data = result.get('data', {})        print(f"车辆 {vid}: {data.get('brand', {}).get('name')} {data.get('model')}")
通过本攻略,您应该能够:
  • 理解懂车帝item_get接口的完整功能

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

  • 处理各种错误情况和性能优化

  • 在实际项目中灵活应用该接口

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


群贤毕至

访客