Metadata-Version: 2.5
Name: dongchedi-cli
Version: 0.2.0
Summary: 懂车帝（dongchedi.com）数据查询 CLI：销量榜 / 品牌 / 车系 / 车型库筛选 / 车型 / 参数配置 / 车主评论 / 搜索
Author: weisanju
Keywords: automobile,car,cli,dongchedi,vehicle-data
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Natural Language :: Chinese (Simplified)
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# dongchedi-cli

懂车帝（www.dongchedi.com）数据查询 CLI。免登录命令走 PC 站公开 JSON 接口；登录命令读取浏览器登录态，走 HTML 页面的 SSR 数据。无第三方依赖（纯标准库）。

## 安装

```bash
uv tool install dongchedi-cli    # 从 PyPI 安装；也可 pipx install dongchedi-cli 或 pip install dongchedi-cli

# 从源码安装（开发）
uv tool install --editable scripts/dongchedi-cli
# 免安装临时运行
PYTHONPATH=scripts/dongchedi-cli/src python3 -m dongchedi_cli.cli rank
```

## 用法

```bash
# ---- 免登录 ----
dcd rank                          # 销量总榜（默认前 20，全国零售量）
dcd rank -c 杭州 -n 50            # 指定城市与条数（注意：榜单仍是全国榜，仅指导价按城市变化）
dcd rank --local -c 杭州          # 杭州城市榜：本地新车上牌量（共 317 款车系）
dcd brands -f J                   # 品牌列表，按名称/首字母过滤
dcd series 858                    # 吉利银河下的全部车系（含指导价/经销商价/评分）
dcd filter --price 10,20 --fuel 纯电 --body 轿车   # 车型库筛选：10-20万纯电轿车
dcd filter --body 小型SUV         # 全部小型SUV（级别细分，如 紧凑型SUV/中大型车/中型MPV）
dcd filter --price 10, --fuel 新能源 --sort 销量高 -n 50   # 10万以上新能源，按销量排序
dcd cars 20154                    # 星愿的车型年款与价格（含停售/未上市）
dcd specs 20154 259371            # 车型参数配置表
dcd specs 20154 259371 259369 -s 电池   # 多车对比，只看"电池"章节
dcd reviews 20154 -p 1 -n 20      # 车主评论（含成交价/评分）
dcd search 秦plus                 # 搜车系
dcd dealer 259371                 # 某车型的经销商报价与优惠（默认杭州）
dcd dealer 259371 259369 -c 上海  # 多车型对比、指定城市

# ---- 需登录态（见下方「登录态」）----
dcd series-info 20154             # 车系主页 SSR：概览/评分/价格卡/经销商
dcd series-info 20154 -s dealers  # 只看经销商（overview/scores/price/dealers）
dcd series-info 20154 -c 北京     # 指定城市（覆盖登录态里的城市 Cookie）
dcd me                            # 当前登录账号信息

# 任意命令加 --json 输出原始数据
```

典型链条：`dcd brands -f 吉利` → `dcd series 858` → `dcd cars 20154` → `dcd specs 20154 <车型ID>`。

表格结果输出到 stdout，进度/提示输出到 stderr，可安全重定向。

## 登录态

`series-info` / `me` 需要已登录懂车帝的 Cookie。获取流程（配合 playwright-cli）：

```bash
playwright-cli open https://www.dongchedi.com --persistent   # 登录（拼图滑块 + 短信验证码）
playwright-cli state-save scripts/dongchedi-cli/.auth/state.json
dcd auth-import scripts/dongchedi-cli/.auth/state.json       # 提取 Cookie 并当场校验
# → 写入 ~/.config/dcd/cookies.txt（chmod 600），文件含 sessionid，勿提交
```

Cookie 文件解析优先级：`--cookie-file` 参数 → `DCD_COOKIE_FILE` 环境变量 → `~/.config/dcd/cookies.txt`。
登录态过期后（报错提示会话过期）重新登录并重跑 `state-save` + `auth-import` 即可。

## 已验证接口（2026-09 实测）

| 命令 | 接口 | 备注 |
| --- | --- | --- |
| rank | `GET /motor/pc/car/rank_data` | `rank_data_type=11` 零售量总榜；`=64` 为城市榜（`--local`，需 city_name，销量=本地新车上牌量）；`=2` 批发量 |
| brands | `GET /motor/brand/v4/brand/` | 品牌在 `data[].info`（其中 4 个热门品牌在 `info.brand`） |
| series | `POST /motor/pc/car/brand/select_series_v2` | 表单参数是 `brand`（不是 `brand_id`，传错会静默返回全站热门车系） |
| filter | `POST /motor/pc/car/brand/select_series_v2` | 与 series 同接口，隐藏筛选参数：`price="10,20"`（万元，区间重叠即命中，`-1` 表示不限）、`fuel_form`（1汽油/2柴油/3油电混合/4纯电/5增程/6插混/13轻混）、`series_type`（0轿车/1SUV/2MPV…）、`outter_detail_type`（细分级别：10小型SUV/11紧凑型SUV…）；`page` 分页有效，总数在 `data.series_count`；枚举出自车型库页前端 chunk（2026-09 逐项实测） |
| cars | `GET /motor/pc/car/series/car_list` | `data.tab_list[]`，type 1115=车型、1137=年款分组，1068 为占位需跳过 |
| specs | `GET /motor/pc/car/get_full_config_info` | 需 `series_id` + `car_ids`；实测忽略 car_ids，总是返回全车系，CLI 已按请求过滤 |
| reviews | `GET /motor/pc/car/series/get_review_list` | 需 `Referer: /auto/series/score/{series_id}` |
| search | `GET /motor/searchapi/search_content` | `cur_tab=2`，车系卡片为 `cell_type=5002`（不一定出现，无则回退内容标题） |
| dealer | `GET /motor/pc/car/series/car_dealer_price` | 匿名可用；依赖 `city_name`（全国 → 暂无报价），未覆盖城市会回落邻近城市 |
| series-info | HTML `GET /auto/series/{id}` | 需登录态；数据在 `__NEXT_DATA__.props.pageProps`（经销商/价格卡/评分） |
| me | `GET /passport/account/info/v2/` | 需登录态；匿名返回 `error_code=13` 会话过期 |

公共参数 `aid=1839&app_name=auto_web_pc`；请求头用桌面 Chrome UA。

## 注意事项

- HTML 路由（`/auto/series/*`、`/auto/params-*`）无登录一律 302 到 `/login-required`；只有带完整登录 Cookie 才能拿到 SSR 数据（仅有 ttwid/tt_webid 不够）。
- HTML 路由有 CDN 缓存且缓存键不含 Cookie，会串城市数据；CLI 已自动附加 `?_r=<毫秒时间戳>` 破缓存。
- 城市由 `city_name` Cookie 控制且值为 **percent-encoded**（如 `%E6%9D%AD%E5%B7%9E`），URL 上的 `city_name` 参数会被页面逻辑忽略；CLI 的 `-c` 已按此处理。
- 登录态 Cookie 含中文值，urllib 请求头默认 latin-1 编码，发送前已转 UTF-8 裸字节（与浏览器线上行为一致）。
- 参数配置表字段：`data.properties[]` 为行定义（type 0/2 为章节标题，1 普通行，3 带子项，6 跳过），值在 `data.car_info[].info[<key>].value`；type 3 的值挂在 `sub_list[].key` 上。注意 `type` 字段时而为 int 时而为字符串，代码里已统一归一化。
- 车型库筛选中 `series_type` 与 `outter_detail_type` **互斥**：同传时服务端会忽略后者（按大类返回）；CLI 的 `--body` 已自动只传其一（轿车/SUV 传 series_type，小型SUV 等细分传 outter_detail_type）。
- 接口可能随版本变化（版本参数当前为 version_code=476），失效时优先用 `--json` 排查原始返回。

## 开发与发布

开发与发布由 `Makefile` 管理（`make help` 查看全部目标）：

```bash
make lint            # ruff 检查
make smoke           # 走工作区源码对真实接口冒烟（覆盖全部免登录命令，需外网）
make bump part=minor # 升版本号（同步 pyproject.toml 与 __init__.py）
make check           # 离线校验：lint + 构建 + 版本一致性 + twine 元数据检查
make publish-test    # 发布到 TestPyPI 预演（token 放 ~/.config/dcd/testpypi-token）
make publish         # 发布到 PyPI（token 放 ~/.config/dcd/pypi-token）
make release         # 一键发布：check → smoke → bump → publish → tag
```

发布前在 pypi.org 生成 API token（`Account settings → API tokens`；首次发布 scope 只能选 "Entire account"，项目建好后可换成项目级），
存到 `~/.config/dcd/pypi-token`（`chmod 600`）即可，或临时 `export UV_PUBLISH_TOKEN=pypi-xxx` 覆盖。
