Move policy-analysis reports to output/ subdirectory

This commit is contained in:
liam
2026-09-11 12:47:13 +08:00
parent 1664a25d9d
commit 1538dac595
40 changed files with 4028 additions and 15 deletions
File diff suppressed because it is too large Load Diff
+21 -9
View File
@@ -448,7 +448,8 @@ def print_stats(listings, new_items=None, updated_items=None, early_stopped=Fals
def scrape(keyword="塘厦", cate_id="15", sort_field="11", def scrape(keyword="塘厦", cate_id="15", sort_field="11",
max_scrolls=100, output_dir=".", incremental=False): max_scrolls=100, output_dir="output/法拍",
incremental=False, csv_only=False):
os.makedirs(output_dir, exist_ok=True) os.makedirs(output_dir, exist_ok=True)
now_str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") now_str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
@@ -463,10 +464,12 @@ def scrape(keyword="塘厦", cate_id="15", sort_field="11",
if incremental: if incremental:
existing, known_ids = load_existing(json_path) existing, known_ids = load_existing(json_path)
if not known_ids: if not known_ids:
print("未找到已有数据,转为首次抓取模式") print("未找到已有 JSON 数据,转为首次抓取模式")
incremental = False incremental = False
else: else:
print(f"已有数据: {len(existing)} 条, 已知 {len(known_ids)} 个 paimaiId") print(f"已有数据: {len(existing)} 条, 已知 {len(known_ids)} 个 paimaiId")
if csv_only:
print("提示: csv_only 模式下增量更新仍需 JSON 做合并,临时使用后删除")
new_listings, early_stopped = fetch_listings( new_listings, early_stopped = fetch_listings(
keyword, cate_id, sort_field, max_scrolls, keyword, cate_id, sort_field, max_scrolls,
@@ -482,9 +485,12 @@ def scrape(keyword="塘厦", cate_id="15", sort_field="11",
print(f"合并后总数: {len(merged)}") print(f"合并后总数: {len(merged)}")
print(f"新增: {len(new_items)} 条 | 更新: {len(updated_items)}") print(f"新增: {len(new_items)} 条 | 更新: {len(updated_items)}")
with open(json_path, "w", encoding="utf-8") as f: if not csv_only:
json.dump(merged, f, indent=2, ensure_ascii=False) with open(json_path, "w", encoding="utf-8") as f:
json.dump(merged, f, indent=2, ensure_ascii=False)
save_csv(merged, csv_path) save_csv(merged, csv_path)
if csv_only and os.path.exists(json_path):
os.remove(json_path)
log_path = os.path.join(output_dir, f"{keyword}_增量日志.log") log_path = os.path.join(output_dir, f"{keyword}_增量日志.log")
with open(log_path, "a", encoding="utf-8") as f: with open(log_path, "a", encoding="utf-8") as f:
@@ -505,7 +511,8 @@ def scrape(keyword="塘厦", cate_id="15", sort_field="11",
f"{ts_to_str(item.get('_startTime'))}\n") f"{ts_to_str(item.get('_startTime'))}\n")
print(f"\n输出文件:") print(f"\n输出文件:")
print(f" JSON: {json_path}") if not csv_only:
print(f" JSON: {json_path}")
print(f" CSV: {csv_path}") print(f" CSV: {csv_path}")
print(f" 日志: {log_path}") print(f" 日志: {log_path}")
@@ -517,12 +524,14 @@ def scrape(keyword="塘厦", cate_id="15", sort_field="11",
item["_first_seen"] = now_str item["_first_seen"] = now_str
item["_last_seen"] = now_str item["_last_seen"] = now_str
with open(json_path, "w", encoding="utf-8") as f: if not csv_only:
json.dump(sorted_listings, f, indent=2, ensure_ascii=False) with open(json_path, "w", encoding="utf-8") as f:
json.dump(sorted_listings, f, indent=2, ensure_ascii=False)
save_csv(sorted_listings, csv_path) save_csv(sorted_listings, csv_path)
print(f"\n输出文件:") print(f"\n输出文件:")
print(f" JSON: {json_path}") if not csv_only:
print(f" JSON: {json_path}")
print(f" CSV: {csv_path}") print(f" CSV: {csv_path}")
print_stats(sorted_listings) print_stats(sorted_listings)
@@ -535,9 +544,11 @@ if __name__ == "__main__":
parser.add_argument("--cate-id", default="15", help="类目ID (默认: 15=法拍房)") parser.add_argument("--cate-id", default="15", help="类目ID (默认: 15=法拍房)")
parser.add_argument("--sort-field", default="11", help="排序 (默认: 11=最新发布)") parser.add_argument("--sort-field", default="11", help="排序 (默认: 11=最新发布)")
parser.add_argument("--max-scrolls", type=int, default=100, help="最大滚动次数") parser.add_argument("--max-scrolls", type=int, default=100, help="最大滚动次数")
parser.add_argument("--output-dir", default=".", help="输出目录") parser.add_argument("--output-dir", default="output/法拍", help="输出目录 (默认: output/法拍)")
parser.add_argument("--incremental", "-i", action="store_true", parser.add_argument("--incremental", "-i", action="store_true",
help="增量更新:只下载新房源,遇到已知项即停止") help="增量更新:只下载新房源,遇到已知项即停止")
parser.add_argument("--csv-only", action="store_true",
help="只输出 CSV,不保存 JSON(增量模式下 JSON 临时使用后删除)")
args = parser.parse_args() args = parser.parse_args()
@@ -548,4 +559,5 @@ if __name__ == "__main__":
max_scrolls=args.max_scrolls, max_scrolls=args.max_scrolls,
output_dir=args.output_dir, output_dir=args.output_dir,
incremental=args.incremental, incremental=args.incremental,
csv_only=args.csv_only,
) )
+6 -6
View File
@@ -14,7 +14,7 @@ description: 政策雷达 — 从中国政府公开信息源抓取最新政策
**角色:** 你是一个政策分析师,专为中国A股市场的投资者提供政策解读服务。你不会凭空猜测——所有判断都基于政策原文。 **角色:** 你是一个政策分析师,专为中国A股市场的投资者提供政策解读服务。你不会凭空猜测——所有判断都基于政策原文。
**目标产物:** 一份 `policy-analysis/policy-analysis-{日期}.md`,包含: **目标产物:** 一份 `output/policy-analysis/policy-analysis-{日期}.md`,包含:
1. 本期抓取到的所有相关政策清单(附原文链接/引文) 1. 本期抓取到的所有相关政策清单(附原文链接/引文)
2. 每条政策的四步法解读 2. 每条政策的四步法解读
3. 政策连续性验证(对比上一期分析) 3. 政策连续性验证(对比上一期分析)
@@ -104,9 +104,9 @@ description: 政策雷达 — 从中国政府公开信息源抓取最新政策
**基线建立规则(硬步骤,不可跳过):** **基线建立规则(硬步骤,不可跳过):**
- **非首次运行**: 将本期政策与上一期 `policy-analysis/policy-analysis-{上期日期}.md` 的结论逐条对比,标注每条政策的「新增表述/措辞变化/排序变化/新增措施/删除内容」。 - **非首次运行**: 将本期政策与上一期 `output/policy-analysis/policy-analysis-{上期日期}.md` 的结论逐条对比,标注每条政策的「新增表述/措辞变化/排序变化/新增措施/删除内容」。
- **首次运行**: 必须执行「基线扫描」子步骤——搜索过去 3 个月的相关政策(至少覆盖本次关键词领域),建立一份简短的基线摘要(每条政策的核心方向+关键措辞),作为 4.2 的对比锚点。基线摘要写入报告的「基线对比」字段,不得省略。 - **首次运行**: 必须执行「基线扫描」子步骤——搜索过去 3 个月的相关政策(至少覆盖本次关键词领域),建立一份简短的基线摘要(每条政策的核心方向+关键措辞),作为 4.2 的对比锚点。基线摘要写入报告的「基线对比」字段,不得省略。
- **后续运行输入**: 将上一期 `policy-analysis/policy-analysis-{日期}.md` 作为上下文输入,使 4.2 的增量判断可验证,而非依赖 agent 的历史知识。 - **后续运行输入**: 将上一期 `output/policy-analysis/policy-analysis-{日期}.md` 作为上下文输入,使 4.2 的增量判断可验证,而非依赖 agent 的历史知识。
#### 4.3 分类:区分货币政策与财政政策 #### 4.3 分类:区分货币政策与财政政策
@@ -134,7 +134,7 @@ description: 政策雷达 — 从中国政府公开信息源抓取最新政策
**Step 5 — 生成结构化分析报告。** **Step 5 — 生成结构化分析报告。**
使用以下模板(第4节)生成 `policy-analysis/policy-analysis-{日期}.md` 使用以下模板(第4节)生成 `output/policy-analysis/policy-analysis-{日期}.md`
**Step 6 — 写入文件并汇报。** **Step 6 — 写入文件并汇报。**
@@ -349,7 +349,7 @@ article = scrape_article("gov.cn", url) # 返回 [{text}, ...]
1. **原文可追溯** — 每条政策都有原文链接或原文引文。原文获取不完整时须有 ⚠️ 降级标注。 1. **原文可追溯** — 每条政策都有原文链接或原文引文。原文获取不完整时须有 ⚠️ 降级标注。
2. **四步法齐全** — 每条政策都经过 4.1→4.2→4.3→4.4 四步。缺失项不得臆测填充,应标注「原文不可得」。 2. **四步法齐全** — 每条政策都经过 4.1→4.2→4.3→4.4 四步。缺失项不得臆测填充,应标注「原文不可得」。
3. **基线对比** — 非首次运行对比上一期 `policy-analysis/policy-analysis-{日期}.md`;首次运行执行 3 个月基线扫描并建立基线摘要。 3. **基线对比** — 非首次运行对比上一期 `output/policy-analysis/policy-analysis-{日期}.md`;首次运行执行 3 个月基线扫描并建立基线摘要。
4. **方向判断有依据** — 每个投资判断(含看空赛道)指向具体政策编号,格式为 `{政策编号} 中的 ...` 4. **方向判断有依据** — 每个投资判断(含看空赛道)指向具体政策编号,格式为 `{政策编号} 中的 ...`
5. **无臆测** — 所有分析基于原文。推测部分必须标注「(推测,非原文)」。 5. **无臆测** — 所有分析基于原文。推测部分必须标注「(推测,非原文)」。
6. **优先级标注** — 每条政策在清单中标注了 P0-P4 优先级。 6. **优先级标注** — 每条政策在清单中标注了 P0-P4 优先级。
@@ -368,5 +368,5 @@ article = scrape_article("gov.cn", url) # 返回 [{text}, ...]
## 9. 一句话调用 ## 9. 一句话调用
> 「运行政策雷达,搜索{关键词/时间范围},抓取政策原文,按四步法解读,输出 policy-analysis/policy-analysis-{日期}.md。」 > 「运行政策雷达,搜索{关键词/时间范围},抓取政策原文,按四步法解读,输出 output/policy-analysis/policy-analysis-{日期}.md。」