Metadata-Version: 2.4
Name: cnlaw-cli
Version: 0.1.0
Summary: Unified CLI for official Chinese legal information sources
License-Expression: PolyForm-Noncommercial-1.0.0
Keywords: china-law,legal-research,regulations,cli
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Legal Industry
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Text Processing :: Indexing
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: beautifulsoup4>=4.12
Requires-Dist: cryptography>=42.0
Requires-Dist: httpx[socks]>=0.27
Requires-Dist: PyYAML>=6.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-cov>=5.0; extra == "dev"
Dynamic: license-file

# cnlaw-cli

`cnlaw-cli` 将 19 个中国境内官方法律、法规、规章、政策和交易规则来源统一为一套命令语法：

```text
cnlaw search <source-code> <keyword> [统一检索选项]
cnlaw info <source-code> <document-id-or-official-url>
cnlaw article npc <document-id> <条号>
cnlaw preview npc <document-id>
cnlaw article-search npc <keyword> --max-laws N
cnlaw download <source-code> <document-id> --format docx|pdf
```

这是一个从各官网当前实际请求重新验证、独立实现的项目。项目会明确区分公开开发 API、官网前端内部 JSON 接口和 HTML 检索端点；“能被官网调用”不等于“有公开开发文档或稳定性承诺”。

19 个来源均实现了 `info`。国家法律法规数据库使用结构化详情接口；其他来源按各站当前详情接口或官方详情 HTML 解析。URL 型输入会校验来源官方域名，不允许把任意 URL 当成请求目标。

`cnlaw article npc` 会调用国家法律法规数据库的官方 DOCX 下载接口，解析后输出完整条文。可用条号（如 `第二十八条`、`第28条`、`28`）或 `--grep` 检索单篇法规内的所有命中条文。短期签名 URL 不会写入输出或缓存；原始官方文件默认进入本地持久化缓存，避免后续条文检索重复下载。

## 安装

需要 Python 3.11 或更高版本。

PyPI 首个版本发布后，推荐通过 `uv` 安装为隔离的全局命令：

```bash
uv tool install cnlaw-cli
cnlaw --version
cnlaw sources
```

升级或卸载：

```bash
uv tool upgrade cnlaw-cli
uv tool uninstall cnlaw-cli
```

也可以使用 `pip`：

```bash
python3 -m pip install cnlaw-cli
cnlaw sources
```

当前若 PyPI 尚未出现 `cnlaw-cli` 项目，`uv tool install cnlaw-cli` 会返回“not found”；这表示发布工作流尚未完成，不是本地 `uv` 故障。

从源码参与开发时，在项目根目录运行：

```bash
python3 -m venv .venv
.venv/bin/pip install -e '.[dev]'
.venv/bin/cnlaw --version
```

## 基本用法

```bash
# 查看全部来源
cnlaw sources

# 查看单个来源原生支持的检索能力
cnlaw capabilities npc

# 查看该来源经官网请求核验过的额外检索字段及请求字段名
cnlaw parameters tax --format json

# 国家法律法规数据库：标题检索
cnlaw search npc '劳动合同法' --format json

# 国家法律法规数据库：读取官方详情
cnlaw info npc 2c909fdd678bf17901678bf74d7106b3

# 国家法律法规数据库：提取完整条文
cnlaw article npc 2c909fdd678bf17901678bf74d7106b3 '第二十八条'
cnlaw article npc 2c909fdd678bf17901678bf74d7106b3 --grep '劳动报酬'

# 返回完整目录、总条数和全部条号（不抽样）
cnlaw preview npc 2c909fdd678bf17901678bf74d7106b3

# 跨法规条文检索；候选法规数量必须显式指定
cnlaw article-search npc '民法典第三百一十一条' --max-laws 20

# 显式下载；格式参数决定官网实际请求的文件格式
cnlaw download npc 2c909fdd678bf17901678bf74d7106b3 \
  --format pdf \
  --output './劳动合同法.pdf'

# 检查持久化文件缓存
cnlaw cache stats

# 国家法律法规数据库：正文检索具体条文引用
cnlaw search npc '民法典第三百一十一条' \
  --scope content \
  --format jsonl

# 国家规章库
cnlaw search gov-rules '管理办法' --scope title --sort newest

# 上交所规则
cnlaw search sse '信息披露' --scope all

# 金融监管总局，完整写入可审计目录
cnlaw search nfra '善意取得' \
  --scope all \
  --output './runs/nfra-good-faith'

# 国家法律法规数据库：搜索建议
cnlaw suggest npc '劳动合同'

# 国家法律法规数据库：查看单篇文件中的关键词命中位置
cnlaw highlight npc 2c909fdd678bf17901678bf74d7106b3 '劳动报酬'

# 国家法律法规数据库：读取关联资料
cnlaw related npc 2c909fdd678bf17901678bf74d7106b3 '劳动合同'

# 国家法律法规数据库：批量下载；所有 ID 都会处理，失败项单独列出
cnlaw batch-download npc \
  2c909fdd678bf17901678bf74d7106b3 \
  ANOTHER_DOCUMENT_ID \
  --format docx \
  --output-dir './downloads'
```

如果没有指定 `--scope`，CLI 会为该来源自动选择其支持的优先范围：`title`、`all`、`content`。显式指定了来源不支持的筛选项时，命令会报错，不会悄悄忽略条件。

`suggest`、`highlight`、`related`、`article`、`preview`、`article-search` 和 `batch-download` 当前只支持 `npc`。批量下载会处理命令中给出的全部 ID；任一项目失败时仍保留其他成功结果，并以非零退出码和 `failures` 字段明确报告。

## 统一检索选项

```text
--scope title|content|all
--match fuzzy|exact
--status VALUE                  可重复
--document-type VALUE           可重复
--authority VALUE               可重复
--publish-from YYYY-MM-DD
--publish-to YYYY-MM-DD
--effective-from YYYY-MM-DD
--effective-to YYYY-MM-DD
--sort relevance|newest|oldest
--limit N
--source-param KEY=VALUE        来源特有字段；仅接受 cnlaw parameters 列出的名称
--format table|json|jsonl
--output DIRECTORY
```

不同官网原生能力不同。先运行 `cnlaw capabilities <source>`，即可知道某个选项是 `native`、`emulated` 还是不支持。

运行 `cnlaw parameters <source>` 可查看该站的高级字段、对应官网请求字段、类型、可重复性和已知枚举，随后用 `--source-param KEY=VALUE` 传入。未知字段、错误枚举和不允许重复的字段会直接报错。

维护仓库中的 19 站请求审计还记录了 CLI 自动维护、但不允许用户覆写的分页、回调、站点范围和动态鉴权字段。该维护档案不属于 wheel/sdist 的公开运行时内容；公开用户应以 `cnlaw capabilities` 和 `cnlaw parameters` 的实际输出为准。

`--limit` 没有默认值。未明确传入时，适配器会按照官网返回的总数或总页数继续翻页，不会为了方便静默截断。传入 `--limit` 是用户明确要求截断；输出清单会记录 `explicit_limit` 和 `truncated`。

## 原文文件缓存

NPC 的 `article`、`preview`、`article-search` 和 `download` 默认复用持久化的官方 DOCX/PDF：

- 默认目录：`~/.cache/cnlaw/documents`
- 默认有效期：7 天，命令帮助和缓存元数据均明确记录为 `604800` 秒
- 缓存键：来源 + 官方 document ID + 文件格式
- 缓存内容：原始公开文件及哈希、大小、缓存时间；不保存短期签名 URL
- `--refresh`：强制重新获取并更新缓存
- `--no-cache`：本次既不读取也不写入缓存
- `--cache-dir PATH`、`--cache-max-age-days N`：显式调整位置和有效期
- `cnlaw cache stats`：查看条目、大小、路径和有效期
- `cnlaw cache clear`：仅清理由 cnlaw 标记并拥有的缓存目录

`article`、`preview` 输出 `file_cache_hit`；`article-search` 输出 `cache_hits` 和 `files_downloaded`；显式下载输出 `cache_hit`，因此是否发生重复下载可以直接审计。

## 输出与审计

### 检索输出

每条记录统一包含：

- `source`、`source_name`、`source_document_id`
- `title`、`official_url`
- `document_type`、`issuing_authority`、`document_number`
- `publish_date`、`effective_date`
- `validity_status`、`validity_explicit`
- `summary`、`content`、`download_urls`
- `retrieved_at`、`source_rank`
- `raw_metadata`

### 详情输出（`cnlaw info`）

结构化 JSON，至少包含：

- `official_url`、`title`、`source_document_id`
- `body`、`body_availability`、`body_note`、`content_outline`
- `document_type`、`issuing_authority`、`publish_date`、`effective_date`、`validity_status`
- `attachments`（官方 `ossFile` 路径及不含签名的 `download_endpoint` 模板）
- `retrieved_at`、`raw_metadata`

当详情接口只返回目录/条文标题而无正文时，`body_availability` 为 `outline_only`；当接口未返回正文结构、仅列出可下载附件时为 `download_only`。CLI 不会下载或解析附件内容。

### 条文输出（`cnlaw article npc`）

`article` 使用官方 DOCX 下载接口取得原文并解析。输出包含官方详情页、法规标题、检索条件、完整命中条文和 `file_cache_hit`。原始文件按上文规则进入持久化缓存，但不输出带签名的临时下载 URL。

`article-search` 的每条命中都携带所属法规 ID、标题、官方详情页、条号和条文文本；任何下载或解析失败都会进入 `failures`，不会静默丢弃。输出同时记录候选总数、本批偏移、明确请求的法规数、实际解析数和下一批偏移。

使用 `--output` 时生成：

```text
DIRECTORY/
├── records.jsonl
└── manifest.json
```

`manifest.json` 记录抓取页数、写入条数、官网报告总数、显式限制以及是否截断。已有同名文件时命令拒绝覆盖。

## 来源与能力

| code | 官方来源 | 传输方式 | 检索范围 | 其他原生筛选 |
|---|---|---|---|---|
| `npc` | 国家法律法规数据库 | JSON | title, content | exact, status, 类型, 制定机关 |
| `gov-rules` | 国家规章库 | JSON + 官网动态鉴权 | title, all | newest |
| `gov-policy` | 国务院政策文件库 | JSON | title, content, all | newest；文件库、分类、标签、文号、年份、部门、日期 |
| `moj` | 司法部行政法规库 | HTML | title, content | status, 公布/施行日期, newest/oldest |
| `court` | 最高人民法院 | HTML | all | — |
| `party` | 党内法规库 | JSONP | title, content | newest |
| `treaty` | 外交部条约数据库 | HTML | title | 施行日期；条约分类、缔约国、领域、签署日期、港澳分类 |
| `tax` | 国家税务总局政策法规库 | JSON | title, all | exact, 公布日期, status, newest；效力级别、税种及二级分类、文号、行业、制定年份 |
| `mee` | 生态环境部法规标准 | HTML | title, content, all | 公布日期, newest/oldest |
| `csrc` | 证监会证券期货法规数据库 | JSON | title, content（可组合） | exact, authority, status, 公布日期, newest；标题/正文各三词 AND/OR、法规体系 |
| `samr` | 市场监管法律法规规章数据库 | JSON | title, content | 类型（可多选）, status, 公布/施行日期 |
| `miit` | 工业和信息化部政策法规 | JSON | title, content, all, 文号 | 公布日期, newest；文件类型、部门、主题 |
| `nfra` | 国家金融监督管理总局 | JSON | title, content, all | 公布日期, newest/oldest；栏目、机构、相对时间 |
| `cac` | 国家互联网信息办公室 | HTML | title, content, all | 公布日期, newest/oldest |
| `mod` | 国防部法规文献 | JSON + 官网动态凭据 | title, content, author | exact；标准/模糊/二次检索 |
| `sse` | 上海证券交易所规则 | JSONP | title, content, all | exact, 公布日期, newest |
| `szse` | 深圳证券交易所规则 | JSON | title, content, all | exact, newest |
| `bse` | 北京证券交易所规则 | JSONP | all | 公布日期, newest |
| `neeq` | 全国股转系统规则 | JSONP | all | 公布日期, newest |

其中最高法、国防部官网的检索接口是全站索引，结果会保留官网返回的栏目分类；它们不应被误解为只包含司法解释或军事法规。网信办、司法部、最高法等 HTML 来源能完整分页，但通常比 JSON 来源更容易受页面结构和 WAF 变化影响。

## 已知限制与在线巡检

自动化测试用于固定请求和解析契约，不能替代官网在线状态。截至 2026-07-24 的最近一轮全来源巡检，除国家法律法规数据库外的 18 个来源均能返回检索结果；详情严格校验中有 14 个完整通过，以下 4 个存在官网侧或文件形态限制：

- 证监会详情接口偶发超时或返回 504。
- 工信部部分官方详情页返回站点配置错误。
- 市场监管总局部分文件只提供 PDF/DOCX 附件，结构化接口中的 `content` 为 `null`。
- 上交所部分完整规则正文只通过官方 DOCX 附件提供。

因此，调用 `info` 后应检查 `body_availability`、`body_note` 和 `attachments`，不能只凭 HTTP 成功就认定已取得全文。官网接口、WAF 和页面结构可能随时变化；具体研究任务仍应核对 `official_url` 指向的官方页面。

## 数据保留规则

- 不设置默认条数、页数或摘要长度。
- 不静默去重。工信部搜索返回相似结果分组时，会逐条保留每个组成员。
- 不根据标题自行推定文件效力。仅在官网明确提供效力状态时设置 `validity_explicit=true`。
- 不把 Cookie、动态接口凭据或令牌写入源码、输出和清单。
- 国家规章库与国防部需要的官网前端鉴权值在运行时读取，只在内存中使用。
- 对官网硬性分页限制或异常字段采用显式适配，并在维护档案中记录证据和处理方式。

## 隐私与网络行为

- 安装包不包含维护者或用户的浏览器 Cookie、访问令牌、API Key、个人 IP 地址或本机路径。
- CLI 没有中心服务器、账户系统或遥测上报；检索请求由用户本机直接发往所选官方来源。
- 与任何网络访问一样，目标官网会看到请求出口的公网 IP；如果配置代理，则通常看到代理出口 IP。
- 少数官网会在请求过程中下发临时 Cookie 或动态鉴权值。适配器只在当前 HTTP 客户端内存中使用，不写入源码、输出、清单或持久化缓存。
- NPC 原始公开文件默认缓存在 `~/.cache/cnlaw/documents`；可用 `--no-cache` 禁用，或用 `cnlaw cache clear` 显式清理。

## 故障排查

- 先运行 `cnlaw --version`、`cnlaw sources`、`cnlaw capabilities <source>` 和 `cnlaw parameters <source>`，确认版本、来源代码和支持参数。
- PyPI 已发布但本地仍找不到包时，运行 `uv tool upgrade cnlaw-cli`；首版发布前安装失败属于预期。
- 官网超时、WAF 拦截或 HTML 结构变化时，CLI 会返回非零退出码。不要把失败当成“没有检索结果”，可稍后重试并核对官方页面。
- 搜索默认不设条数或页数上限；只有显式传入 `--limit` 才截断，输出清单会记录截断状态。

## 开发与验证

```bash
.venv/bin/python -m pytest
.venv/bin/python -m pytest --cov=cnlaw --cov-report=term-missing
uv build
```

维护仓库中的来源研究档案记录官网入口、检索端点、分页字段、支持能力、验证日期及稳定性说明，但不会打入面向用户的 wheel/sdist。

## 许可证

本项目采用 [PolyForm Noncommercial License 1.0.0](https://polyformproject.org/licenses/noncommercial/1.0.0)，SPDX 标识为 `PolyForm-Noncommercial-1.0.0`。

允许个人研究、学习、测试以及该许可证列明的非商业组织使用；不授权商业使用。企业内部使用、商业产品或服务集成、收费服务等商业用途应事先另行取得商业授权。完整法律条款以随安装包分发的 [`LICENSE`](LICENSE) 为准。
