跳转至

后端-数据库-publish_time字符串导致SQLite拒绝写入

问题现象

  • 爬虫采集的新闻写入数据库时报错:strptime() argument 1 must be str, not int 或 SQLite DateTime 列拒绝字符串类型
  • 问题仅出现在网页爬虫模块,微信模块正常

核心问题

根因有两个,按重要性排列:

  1. 爬虫脚本透传字符串时间modules/web-crawler/crawlers/scanner.py:143 归一化爬虫返回结果时,直接透传原始 publish_time,不做类型转换。爬虫从 HTML/API 解析出的时间是字符串(如 "2025-06-15 10:30:00"),不是 Python datetime 对象。

  2. _to_datetime() 缺少类型守卫modules/web-crawler/service.py:11-22_to_datetime() 只捕获 ValueError,未检查 isinstance(value, str),导致传入 int 等非预期类型时抛出 TypeError 而非安全返回 None

对比微信模块(wechat_crawler.py:230-254),其 parse_article_timestamp() 在源头就处理了所有非标准格式(bool、int、毫秒时间戳),最终统一通过 datetime.fromtimestamp() 产出标准 datetime 对象。

解决方法

步骤 1:修复 scanner.py 归一化逻辑

# modules/web-crawler/crawlers/scanner.py

+ from ..service import _to_datetime

  normalized.append({
      "title": title[:500],
      "link": link[:1000],
      "content": (item.get("content") or "")[:50000],
-     "publish_time": item.get("publish_time") or None,
+     "publish_time": _to_datetime(item.get("publish_time")),
  })

步骤 2:增强 _to_datetime 健壮性

# modules/web-crawler/service.py

  def _to_datetime(value):
      if value is None:
          return None
      if isinstance(value, datetime):
          return value
+     if not isinstance(value, str):
+         return None
      for fmt in _TIME_FORMATS:
          try:
              return datetime.strptime(value, fmt)
          except ValueError:
              continue
      return None

步骤 3:验证修复

cd d:/product/news
venv/Scripts/python.exe -m pytest tests/test_scanner_datetime.py -v

预期 9 个测试全部通过。

下次防错措施

  • 快速定位:搜索 WebNews( 所有调用点,检查 publish_time= 赋值前是否有 _to_datetime() 包装
  • 写入验证脚本
cd d:/product/news
rg "publish_time.*=" modules/web-crawler/ -n | rg -v "_to_datetime" | rg -v "#"
# 应只有 model 定义和 None 赋值,不应有裸字符串赋值
  • 流程改进:新增爬虫脚本时,在 CR 中确认 publish_time 返回值为 Python datetime 对象或 None,不允许返回字符串