三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

把全网社保问答爬下来:RAG知识库的前传

把全网社保问答爬下来:RAG知识库的前传

把全网社保问答爬下来:RAG 知识库的前传

文章目录

  • 把全网社保问答爬下来:RAG 知识库的前传
    • 一、问题
    • 二、爬:搜出所有问答链接
    • 三、解析:以"问"为刀,切开一页里的多轮问答
    • 四、存:入库 + 本地文件双保险
    • 五、Clean:去掉机构名称噪音
    • 六、为什么不用 AI 解析
    • 七、环节补全
    • 八、亮点总结
    • 九、适用场景
    • 十、扩展方向
    • 十一、总结

你问 RAG 的知识从哪来?不是买的数据集,是一个一个问题从网页上扒下来的。


一、问题

上篇搭好了 RAG 智能客服——Milvus + BGE-M3 + DeepSeek。但知识库是空的。你需要社保问答数据,结构化、一问一答的那种。

正常做法:找现成的数据集、买数据、或者人工整理。最省的办法:政府网站上有公开的在线问答页面,爬下来。


二、爬:搜出所有问答链接

某网站的社保问答入口是一个搜索结果页,分页显示。先翻页遍历:

importrequestsfrompyqueryimportPyQueryaspq i=1327# 文件编号起点forjinrange(7,0,-1):# 从第 7 页倒着爬到第 1 页url=f'https://sou.example.com/?q=关于社保那些事&title=2&type=1&page={j}'response=requests.get(url)doc=pq(response.text)

为什么倒着爬?旧数据排在前面,先归档。

然后从搜索结果页提取所有链接,过滤出.shtml结尾的——问答详情页:

links=doc('a')forlinkinlinks.items():href=link.attr('href')ifhrefand'.shtml'inhref:# 打开详情页,开始解析

三、解析:以"问"为刀,切开一页里的多轮问答

一个.shtml页面里可能包含多组问答。页面格式是:每一组以"问"开头,后面跟若干行回答文本,直到下一组"问"或页面结束。

解析规则(流程图):

读一行 ├── 这行以"问"开头? │ ├── 之前有问答 → 保存上一组(问+答),清空答案,当前行=新问题 │ └── 之前没有 → 当前行=新问题 ├── 这行包含结束标记?("您还可以通过以下渠道反映") │ └── 保存最后一组,结束 └── 其他行 → 追加到当前答案

代码:

ps=doc2('p')q=''# 当前问题answer=''# 当前答案file=Noneforpinps.items():text=p.text()iftext.startswith("问"):# 上一组问答保存iffile:file.close()myodbc.insert(q,answer,conn)answer=""# 新问题开始pathname=f"d:\\q2\\{i}.txt"i+=1file=open(pathname,"w",encoding="utf-8")q=textfile.write(text+"\n")elif"您还可以通过以下渠道反映关于"intext:# 页面结束file.close()myodbc.insert(q,answer,conn)breakelse:# 追加答案行text=text.replace("海南省社会保险服务中心(医疗保险服务中心)","")answer+=textfile.write(text+"\n")

四、存:入库 + 本地文件双保险

两条通路:

  1. 数据库入库myodbc.insert(q, answer, conn)— 结构化存储,后续直接导进 Milvus
  2. 本地文件备份d:\q2\{编号}.txt— 爬的时候备份一份,入库出问题了有源文件可回溯

五、Clean:去掉机构名称噪音

答案里经常出现"海南省社会保险服务中心(医疗保险服务中心)"这种全称,每个回答都带。直接replace去掉,留下的文本更干净。

text=text.replace("海南省社会保险服务中心(医疗保险服务中心)","")

六、为什么不用 AI 解析

现在做知识抽取,最主流的方式是让 LLM 直接从网页里提取问答对。但在这个场景下,规则比 AI 好用:

  • 格式高度统一:所有页面都是同一个 CMS 生成的,结构完全一致
  • 边界标记明确:"问"字就是天然切分符
  • 零推理成本:不需要理解上下文,不需要处理歧义
  • 可审查:规则解析不会漏,也不会编造;LLM 可能漏,也可能编

这不是反 AI。是在规则能解决的时候,用规则——简单、可控、零 API 费用。


七、环节补全

回顾整个 RAG 系统的数据链路:

网上公开的政务问答页面 → 爬虫遍历搜索结果页,提取所有 .shtml 链接 → 逐页解析,以"问"为边界切分出问题—答案对 → 清洗噪声(去掉机构名称、页面尾注) → 存入数据库 + 本地文件备份 → 向量化(Ollama + BGE-M3)入库 Milvus → RAG 检索 + DeepSeek 生成回答

这篇文章补上了 RAG 系列缺失的第一环——知识从哪来。


八、亮点总结

✅ 零成本——pyquery十几年前的库,零API费用
✅ 规则解析——if text.startswith("问")一条规则切分全部问答,比LLM更可靠
✅ 双保险——数据库入库+本地文件备份,入库出问题有源文件可回溯
✅ 人工Clean——一行replace去掉机构名称噪音
✅ 完整数据链路——从爬取到解析到清洗到入库到向量化,一环不缺
✅ 简单可控——规则不会漏也不会编造,LLM可能漏也可能编

九、适用场景

  • 政府网站公开的问答页面——CMS统一生成,格式高度一致
  • 需要构建领域知识库但没有现成数据集的场景
  • 结构化的QA页面爬取——边界标记明确,规则优于AI

十、扩展方向

  1. 增量爬取——定时检测新页面,只爬增量的问答
  2. 去重处理——多个页面可能包含相同问题,入库前做语义去重
  3. 分类标签——根据问答内容自动打标签(养老/医疗/工伤/失业)
  4. 质量过滤——排除答案过短或含"请咨询当地社保局"等无效回答

十一、总结

不是什么高深技术。pyquery 十几年前的库,解析规则就一条if text.startswith("问")。但就是这条简单的规则,把散落在网上的几千条政务问答变成了结构化数据,喂进了向量数据库,最终变成了那个能自动回答"职工缴费年限不够怎么办"的智能客服。

写这个脚本的时候,LLM 还没进入大众视野。但思路是一样的:找到规律,用最简方案把它变成数据。

← 返回列表