50cc7cb1cf
- Import 789,853 legal articles from LawRefBook/Laws - Add 19,712 laws including national and regional regulations - Filter 1,370 expired laws - Create vectorization scripts and backup tools - Add law update monitoring mechanism - Generate comprehensive documentation Database: PostgreSQL with GIN index for full-text search Vectorization: 100% complete with LegalSemanticMatcher Performance: 7x improvement in semantic search Co-Authored-By: Claude <noreply@anthropic.com>
514 lines
18 KiB
Python
514 lines
18 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
搜索国家法律法规数据库获取优先级一法律的bbbs ID
|
||
|
||
API文档参考: docs/npc-law-database-api.md
|
||
|
||
使用方法:
|
||
python scripts/search-priority1-laws-bbbs.py --output project-docs/phase14-legal-fulltext-library/priority1-law-bbbs.json
|
||
"""
|
||
|
||
import argparse
|
||
import json
|
||
import time
|
||
import urllib.parse
|
||
import urllib.request
|
||
import ssl
|
||
from datetime import datetime
|
||
from typing import Optional, Dict, List, Any
|
||
|
||
# 忽略SSL证书验证(开发环境)
|
||
ssl_context = ssl.create_default_context()
|
||
ssl_context.check_hostname = False
|
||
ssl_context.verify_mode = ssl.CERT_NONE
|
||
|
||
API_BASE = "https://flk.npc.gov.cn/law-search"
|
||
|
||
# 优先级一法律清单(来自国家法律法规数据库)
|
||
PRIORITY1_LAWS = [
|
||
# 合同通用司法解释
|
||
{
|
||
"title": "最高人民法院关于适用《中华人民共和国民法典》合同编通则若干问题的解释",
|
||
"short_name": "民法典合同编通则司法解释",
|
||
"category": "judicial_interpretation",
|
||
"priority": 1,
|
||
"knowledge_domain": "contract-general",
|
||
"contract_types": ["所有合同类型"],
|
||
"notes": "合同审查最核心司法解释"
|
||
},
|
||
{
|
||
"title": "最高人民法院关于适用《中华人民共和国民法典》有关担保制度的解释",
|
||
"short_name": "民法典担保制度解释",
|
||
"category": "judicial_interpretation",
|
||
"priority": 1,
|
||
"knowledge_domain": "guarantee",
|
||
"contract_types": ["担保合同", "借款合同"],
|
||
"notes": "担保条款审查核心依据"
|
||
},
|
||
|
||
# 劳动用工
|
||
{
|
||
"title": "中华人民共和国劳动合同法实施条例",
|
||
"short_name": "劳动合同法实施条例",
|
||
"category": "administrative_regulation",
|
||
"priority": 1,
|
||
"knowledge_domain": "labor-employment",
|
||
"contract_types": ["劳动合同", "劳务协议"],
|
||
"notes": "劳动合同法配套行政法规"
|
||
},
|
||
{
|
||
"title": "最高人民法院关于审理劳动争议案件适用法律问题的解释(一)",
|
||
"short_name": "劳动争议司法解释",
|
||
"category": "judicial_interpretation",
|
||
"priority": 1,
|
||
"knowledge_domain": "labor-employment",
|
||
"contract_types": ["劳动合同"],
|
||
"notes": "劳动争议核心依据"
|
||
},
|
||
{
|
||
"title": "中华人民共和国社会保险法",
|
||
"short_name": "社会保险法",
|
||
"category": "law",
|
||
"priority": 1,
|
||
"knowledge_domain": "labor-employment",
|
||
"contract_types": ["劳动合同"],
|
||
"notes": "社保条款是劳动合同必备内容"
|
||
},
|
||
{
|
||
"title": "工伤保险条例",
|
||
"short_name": "工伤保险条例",
|
||
"category": "administrative_regulation",
|
||
"priority": 1,
|
||
"knowledge_domain": "labor-employment",
|
||
"contract_types": ["劳动合同"],
|
||
"notes": "用工风险条款核心依据"
|
||
},
|
||
|
||
# 采购招投标
|
||
{
|
||
"title": "中华人民共和国招标投标法实施条例",
|
||
"short_name": "招投标法实施条例",
|
||
"category": "administrative_regulation",
|
||
"priority": 1,
|
||
"knowledge_domain": "procurement-tendering",
|
||
"contract_types": ["采购合同"],
|
||
"notes": "招投标法配套行政法规"
|
||
},
|
||
{
|
||
"title": "中华人民共和国政府采购法实施条例",
|
||
"short_name": "政府采购法实施条例",
|
||
"category": "administrative_regulation",
|
||
"priority": 1,
|
||
"knowledge_domain": "procurement-tendering",
|
||
"contract_types": ["政府采购合同"],
|
||
"notes": "政府采购法配套行政法规"
|
||
},
|
||
|
||
# 建设工程
|
||
{
|
||
"title": "中华人民共和国建筑法",
|
||
"short_name": "建筑法",
|
||
"category": "law",
|
||
"priority": 1,
|
||
"knowledge_domain": "construction",
|
||
"contract_types": ["承揽合同", "技术服务"],
|
||
"notes": "建设工程主体资格审查依据"
|
||
},
|
||
{
|
||
"title": "建设工程质量管理条例",
|
||
"short_name": "建设工程质量管理条例",
|
||
"category": "administrative_regulation",
|
||
"priority": 1,
|
||
"knowledge_domain": "construction",
|
||
"contract_types": ["承揽合同"],
|
||
"notes": "质量条款审查依据"
|
||
},
|
||
{
|
||
"title": "最高人民法院关于审理建设工程施工合同纠纷案件适用法律问题的解释(一)",
|
||
"short_name": "建设工程司法解释",
|
||
"category": "judicial_interpretation",
|
||
"priority": 1,
|
||
"knowledge_domain": "construction",
|
||
"contract_types": ["承揽合同", "技术服务"],
|
||
"notes": "建设工程合同审查核心依据"
|
||
},
|
||
|
||
# 知识产权
|
||
{
|
||
"title": "最高人民法院关于审理技术合同纠纷案件适用法律若干问题的解释",
|
||
"short_name": "技术合同司法解释",
|
||
"category": "judicial_interpretation",
|
||
"priority": 1,
|
||
"knowledge_domain": "intellectual-property",
|
||
"contract_types": ["技术服务", "软件开发"],
|
||
"notes": "技术合同审查核心依据"
|
||
},
|
||
{
|
||
"title": "中华人民共和国著作权法实施条例",
|
||
"short_name": "著作权法实施条例",
|
||
"category": "administrative_regulation",
|
||
"priority": 1,
|
||
"knowledge_domain": "intellectual-property",
|
||
"contract_types": ["软件开发", "IP许可"],
|
||
"notes": "著作权法配套行政法规"
|
||
},
|
||
{
|
||
"title": "信息网络传播权保护条例",
|
||
"short_name": "信息网络传播权保护条例",
|
||
"category": "administrative_regulation",
|
||
"priority": 1,
|
||
"knowledge_domain": "intellectual-property",
|
||
"contract_types": ["软件开发", "SaaS"],
|
||
"notes": "软件IP条款核心依据"
|
||
},
|
||
|
||
# 借款担保
|
||
{
|
||
"title": "最高人民法院关于审理民间借贷案件适用法律若干问题的规定",
|
||
"short_name": "民间借贷司法解释",
|
||
"category": "judicial_interpretation",
|
||
"priority": 1,
|
||
"knowledge_domain": "loan",
|
||
"contract_types": ["企业间借款", "借款合同"],
|
||
"notes": "借款利息条款核心依据"
|
||
},
|
||
|
||
# 商事主体
|
||
{
|
||
"title": "中华人民共和国合伙企业法",
|
||
"short_name": "合伙企业法",
|
||
"category": "law",
|
||
"priority": 1,
|
||
"knowledge_domain": "company-commercial",
|
||
"contract_types": ["合伙协议"],
|
||
"notes": "合伙协议审查唯一依据"
|
||
},
|
||
{
|
||
"title": "中华人民共和国企业破产法",
|
||
"short_name": "企业破产法",
|
||
"category": "law",
|
||
"priority": 1,
|
||
"knowledge_domain": "company-commercial",
|
||
"contract_types": ["投资协议", "股权转让"],
|
||
"notes": "破产条款审查依据"
|
||
},
|
||
|
||
# 投融资
|
||
{
|
||
"title": "中华人民共和国信托法",
|
||
"short_name": "信托法",
|
||
"category": "law",
|
||
"priority": 1,
|
||
"knowledge_domain": "investment-finance",
|
||
"contract_types": ["投资协议"],
|
||
"notes": "信托结构审查依据"
|
||
},
|
||
{
|
||
"title": "中华人民共和国证券法",
|
||
"short_name": "证券法",
|
||
"category": "law",
|
||
"priority": 1,
|
||
"knowledge_domain": "investment-finance",
|
||
"contract_types": ["投资协议", "股权转让"],
|
||
"notes": "证券条款审查依据"
|
||
},
|
||
|
||
# 房地产
|
||
{
|
||
"title": "中华人民共和国城市房地产管理法",
|
||
"short_name": "城市房地产管理法",
|
||
"category": "law",
|
||
"priority": 1,
|
||
"knowledge_domain": "real-estate",
|
||
"contract_types": ["房屋租赁"],
|
||
"notes": "房地产主体审查依据"
|
||
},
|
||
{
|
||
"title": "最高人民法院关于审理商品房买卖合同纠纷案件适用法律若干问题的解释",
|
||
"short_name": "商品房买卖司法解释",
|
||
"category": "judicial_interpretation",
|
||
"priority": 1,
|
||
"knowledge_domain": "real-estate",
|
||
"contract_types": ["房屋租赁"],
|
||
"notes": "房地产合同审查依据"
|
||
},
|
||
|
||
# 数据跨境
|
||
{
|
||
"title": "数据出境安全评估办法",
|
||
"short_name": "数据出境安全评估办法",
|
||
"category": "departmental_rule",
|
||
"priority": 1,
|
||
"knowledge_domain": "data-privacy",
|
||
"contract_types": ["数据处理协议"],
|
||
"notes": "数据出境条款核心依据",
|
||
"source_hint": "国家网信办官网" # 不在国家法律法规数据库,需要从其他来源
|
||
},
|
||
{
|
||
"title": "个人信息出境标准合同办法",
|
||
"short_name": "个人信息出境标准合同办法",
|
||
"category": "departmental_rule",
|
||
"priority": 1,
|
||
"knowledge_domain": "data-privacy",
|
||
"contract_types": ["数据处理协议"],
|
||
"notes": "跨境数据处理标准合同",
|
||
"source_hint": "国家网信办官网"
|
||
},
|
||
{
|
||
"title": "关键信息基础设施安全保护条例",
|
||
"short_name": "关键信息基础设施安全保护条例",
|
||
"category": "administrative_regulation",
|
||
"priority": 1,
|
||
"knowledge_domain": "data-privacy",
|
||
"contract_types": ["SaaS", "软件开发"],
|
||
"notes": "关基设施条款依据"
|
||
},
|
||
]
|
||
|
||
# 已知bbbs ID的法律(从现有清单中提取)
|
||
KNOWN_BBBS = {
|
||
"中华人民共和国民法典": "ff808081729d1efe01729d50b5c500bf",
|
||
"中华人民共和国电子签名法": "ff8080816f135f46016f2163e4261aa1",
|
||
"中华人民共和国个人信息保护法": "ff8081817b6472a3017b656cc2040044",
|
||
"中华人民共和国劳动合同法": "2c909fdd678bf17901678bf74d7106b3",
|
||
"中华人民共和国数据安全法": "ff80818179f5e0800179f885c7e70392",
|
||
"中华人民共和国公司法": "ff8081818c9108eb018cb6922f750c07",
|
||
}
|
||
|
||
|
||
def fetch_json(url: str, max_retries: int = 3) -> Optional[Dict]:
|
||
"""发送HTTP请求获取JSON响应"""
|
||
for attempt in range(max_retries):
|
||
try:
|
||
req = urllib.request.Request(
|
||
url,
|
||
headers={
|
||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
||
'Accept': 'application/json',
|
||
'Referer': 'https://flk.npc.gov.cn/'
|
||
}
|
||
)
|
||
with urllib.request.urlopen(req, context=ssl_context, timeout=30) as response:
|
||
return json.loads(response.read().decode('utf-8'))
|
||
except Exception as e:
|
||
print(f" 请求失败 (尝试 {attempt + 1}/{max_retries}): {e}")
|
||
if attempt < max_retries - 1:
|
||
time.sleep(1)
|
||
return None
|
||
|
||
|
||
def search_law_suggestions(title: str) -> List[Dict]:
|
||
"""搜索法律建议"""
|
||
encoded = urllib.parse.quote(title)
|
||
url = f"{API_BASE}/prompts/search?title={encoded}"
|
||
response = fetch_json(url)
|
||
if response and response.get('code') == 200:
|
||
return response.get('data', [])
|
||
return []
|
||
|
||
|
||
def get_law_details(bbbs: str) -> Optional[Dict]:
|
||
"""获取法律详情"""
|
||
encoded = urllib.parse.quote(bbbs)
|
||
url = f"{API_BASE}/search/flfgDetails?bbbs={encoded}"
|
||
response = fetch_json(url)
|
||
if response and response.get('code') == 200:
|
||
return response.get('data')
|
||
return None
|
||
|
||
|
||
def get_aggregate_data() -> Optional[Dict]:
|
||
"""获取统计数据(包含热门法律的bbbs)"""
|
||
url = f"{API_BASE}/index/aggregateData"
|
||
response = fetch_json(url)
|
||
if response and response.get('code') == 200:
|
||
return response.get('data')
|
||
return None
|
||
|
||
|
||
def search_law_bbbs(title: str) -> Dict[str, Any]:
|
||
"""搜索法律并获取bbbs ID"""
|
||
|
||
# 1. 先检查已知bbbs
|
||
if title in KNOWN_BBBS:
|
||
return {
|
||
"found": True,
|
||
"bbbs": KNOWN_BBBS[title],
|
||
"source": "known_list"
|
||
}
|
||
|
||
# 2. 从统计数据的热门搜索中查找
|
||
aggregate = get_aggregate_data()
|
||
if aggregate:
|
||
for item in aggregate.get('popularSearch', []):
|
||
if item.get('title') == title:
|
||
return {
|
||
"found": True,
|
||
"bbbs": item.get('bbbs'),
|
||
"source": "popular_search"
|
||
}
|
||
for item in aggregate.get('popularDownload', []):
|
||
if item.get('title') == title:
|
||
return {
|
||
"found": True,
|
||
"bbbs": item.get('bbbs'),
|
||
"source": "popular_download"
|
||
}
|
||
|
||
# 3. 使用搜索建议API
|
||
suggestions = search_law_suggestions(title)
|
||
if not suggestions:
|
||
return {
|
||
"found": False,
|
||
"reason": "no_search_results"
|
||
}
|
||
|
||
# 尝试精确匹配
|
||
for suggestion in suggestions:
|
||
if suggestion.get('title') == title:
|
||
# 搜索建议不返回bbbs,需要进一步获取详情
|
||
# 这里我们需要另一种方法来获取bbbs
|
||
return {
|
||
"found": True,
|
||
"exact_match": title,
|
||
"suggestion_title": suggestion.get('title'),
|
||
"source": "search_suggestion",
|
||
"needs_bbbs_lookup": True
|
||
}
|
||
|
||
# 返回最接近的匹配
|
||
return {
|
||
"found": False,
|
||
"reason": "no_exact_match",
|
||
"closest_matches": [s.get('title') for s in suggestions[:3]]
|
||
}
|
||
|
||
|
||
def main():
|
||
parser = argparse.ArgumentParser(description='搜索优先级一法律的bbbs ID')
|
||
parser.add_argument('--output', '-o', default='project-docs/phase14-legal-fulltext-library/priority1-law-bbbs.json',
|
||
help='输出文件路径')
|
||
parser.add_argument('--verbose', '-v', action='store_true', help='显示详细信息')
|
||
args = parser.parse_args()
|
||
|
||
print("=" * 60)
|
||
print("搜索国家法律法规数据库获取优先级一法律")
|
||
print("=" * 60)
|
||
|
||
results = {
|
||
"search_date": datetime.now().isoformat(),
|
||
"source_system": "国家法律法规数据库",
|
||
"api_base": API_BASE,
|
||
"total_laws": len(PRIORITY1_LAWS),
|
||
"found_count": 0,
|
||
"not_found_count": 0,
|
||
"needs_manual_lookup": [],
|
||
"laws": [],
|
||
"statistics": {}
|
||
}
|
||
|
||
# 获取统计数据
|
||
print("\n获取统计数据...")
|
||
aggregate = get_aggregate_data()
|
||
if aggregate:
|
||
print(f" 法律总数: {sum(c.get('count', 0) for c in aggregate.get('flflCount', []))}")
|
||
print(f" 热门搜索: {len(aggregate.get('popularSearch', []))} 部")
|
||
print(f" 热门下载: {len(aggregate.get('popularDownload', []))} 部")
|
||
results["statistics"] = {
|
||
"categories": aggregate.get('flflCount', []),
|
||
"popular_search_count": len(aggregate.get('popularSearch', [])),
|
||
"popular_download_count": len(aggregate.get('popularDownload', []))
|
||
}
|
||
|
||
# 提取热门搜索中的法律信息(包含bbbs)
|
||
popular_laws = {}
|
||
for item in aggregate.get('popularSearch', []):
|
||
popular_laws[item.get('title')] = {
|
||
"bbbs": item.get('bbbs'),
|
||
"type": item.get('flxz'),
|
||
"publish_date": item.get('gbrq')
|
||
}
|
||
for item in aggregate.get('popularDownload', []):
|
||
if item.get('title') not in popular_laws:
|
||
popular_laws[item.get('title')] = {
|
||
"bbbs": item.get('bbbs'),
|
||
"type": item.get('flxz'),
|
||
"publish_date": item.get('gbrq')
|
||
}
|
||
|
||
# 搜索每部法律
|
||
print("\n搜索法律...")
|
||
for law in PRIORITY1_LAWS:
|
||
title = law['title']
|
||
print(f"\n搜索: {title}")
|
||
|
||
result = {
|
||
**law,
|
||
"bbbs": None,
|
||
"found_in_database": False,
|
||
"source": None
|
||
}
|
||
|
||
# 检查是否在热门列表中
|
||
if title in popular_laws:
|
||
result["bbbs"] = popular_laws[title]["bbbs"]
|
||
result["found_in_database"] = True
|
||
result["source"] = "popular_list"
|
||
print(f" [OK] Found in popular list: bbbs={result['bbbs']}")
|
||
results["found_count"] += 1
|
||
elif "source_hint" in law:
|
||
result["found_in_database"] = False
|
||
result["source"] = law["source_hint"]
|
||
result["notes"] = f"需从 {law['source_hint']} 获取"
|
||
results["needs_manual_lookup"].append({
|
||
"title": title,
|
||
"source": law["source_hint"]
|
||
})
|
||
print(f" [WARN] Need to get from other source: {law['source_hint']}")
|
||
results["not_found_count"] += 1
|
||
else:
|
||
# 使用搜索建议API
|
||
suggestions = search_law_suggestions(title)
|
||
if suggestions:
|
||
# 检查是否有精确匹配
|
||
exact = next((s for s in suggestions if s.get('title') == title), None)
|
||
if exact:
|
||
result["found_in_database"] = True
|
||
result["source"] = "search_suggestion"
|
||
result["needs_bbbs_lookup"] = True
|
||
print(f" [OK] Exact match found, need bbbs lookup")
|
||
results["needs_manual_lookup"].append({
|
||
"title": title,
|
||
"source": "search_api"
|
||
})
|
||
else:
|
||
result["found_in_database"] = False
|
||
result["closest_matches"] = [s.get('title') for s in suggestions[:3]]
|
||
print(f" [X] No exact match, closest: {result['closest_matches'][0]}")
|
||
results["not_found_count"] += 1
|
||
else:
|
||
result["found_in_database"] = False
|
||
print(f" [X] No results found")
|
||
results["not_found_count"] += 1
|
||
|
||
results["laws"].append(result)
|
||
time.sleep(0.3) # 避免请求过快
|
||
|
||
# 保存结果
|
||
with open(args.output, 'w', encoding='utf-8') as f:
|
||
json.dump(results, f, ensure_ascii=False, indent=2)
|
||
|
||
print("\n" + "=" * 60)
|
||
print("搜索完成!")
|
||
print("=" * 60)
|
||
print(f"总计: {results['total_laws']} 部法律")
|
||
print(f"找到: {results['found_count']} 部")
|
||
print(f"未找到: {results['not_found_count']} 部")
|
||
print(f"需手动查找: {len(results['needs_manual_lookup'])} 部")
|
||
print(f"\n结果保存到: {args.output}")
|
||
|
||
return results
|
||
|
||
|
||
if __name__ == '__main__':
|
||
main() |