模块-爬虫扫描-变量引用导致爬取网址为空
问题现象
- 站点管理页面中,"中国证券报快讯"(爬虫文件
news_zhon.py)的"爬取网址"列显示为空 - 其他使用直接字符串常量的站点(如
crawl_caixin.py)URL 正常显示
核心问题
根因 1:scanner.py 的 _parse_crawler_meta() 仅解析 ast.Constant 类型的赋值值,不处理变量引用。
news_zhon.py 中写入形式:
target_url = _TARGET_URL # _TARGET_URL 是模块级变量,值为字符串
AST 节点类型为 ast.Name,被 isinstance(item.value, ast.Constant) 条件过滤掉,URL 始终为空字符串存入数据库。
根因 2:sync_crawlers_to_db() 只新增不更新已有记录。即使解析逻辑修复,数据库中已存在的空 URL 记录不会被覆盖。
解决方法
步骤 1:修复 AST 解析,支持变量引用
modules/web-crawler/crawlers/scanner.py
新增 _resolve_ast_value() 辅助函数,支持三种值类型:
- ast.Constant:直接字符串常量("https://...")
- ast.Name:变量引用(_TARGET_URL),从模块级常量表查找
- ast.JoinedStr:f-string(f"https://...")
def _resolve_ast_value(node, constants):
if isinstance(node, ast.Constant) and isinstance(node.value, str):
return node.value
if isinstance(node, ast.Name) and node.id in constants:
return constants[node.id]
if isinstance(node, ast.JoinedStr):
# f-string 拼接
...
修改前需先收集模块级常量:
top_level_constants = {}
for node in ast.iter_child_nodes(tree):
if isinstance(node, ast.Assign):
...
top_level_constants[target.id] = str(node.value.value)
步骤 2:同步时更新已有记录
sync_crawlers_to_db() 中,对已存在的记录也重新解析元数据并更新:
for code_file in code_files:
meta = _parse_crawler_meta(code_file)
if code_file not in db_sites:
# 新增
...
else:
# 更新已有记录的 name 和 url
existing = db_sites[code_file]
if existing.name != meta["name"] or existing.url != meta["url"]:
existing.name = meta["name"]
existing.url = meta["url"]
步骤 3:部署
# 本地
git add modules/web-crawler/crawlers/scanner.py
git commit -m "fix: 同步时更新已有爬虫记录的 name 和 url 元数据"
git push origin main
# 服务器(后端代码变更,需重启)
ssh news "cd /www/news && git pull origin main && systemctl restart news-backend"
下次防错措施
- 快速定位:检查
_parse_crawler_meta()中 AST 节点类型判断是否覆盖了爬虫文件中使用的赋值形式 - 验证命令:
ssh news "cd /www/news && venv/bin/python -c \" import requests r = requests.get('http://127.0.0.1:8000/api/web-crawler/sites') for s in r.json()['data']: if not s['url']: print(f'空白URL: {s[\"name\"]} (file={s[\"code_file\"]})') \"" - 流程改进:新增爬虫文件后,在站点管理页面检查"爬取网址"是否正常显示