㊗️本期内容已收录至专栏《Python爬虫实战》持续完善知识体系与项目实战建议先订阅收藏后续查阅更方便㊙️本期爬虫难度指数⭐ (入门级)福利一次订阅后专栏内的所有文章可永久免费看持续更新中保底1000(篇)硬核实战内容。全文目录 开篇语0️⃣ 前言Preface1️⃣ 摘要Abstract2️⃣ 背景与需求Why3️⃣ 合规与注意事项必写⚠️4️⃣ 技术选型与整体流程What/How5️⃣ 环境准备与依赖安装可复现6️⃣ 核心实现请求层Fetcher7️⃣ 核心实现解析层Parser8️⃣ 数据存储与导出Storage9️⃣ 运行方式与结果展示必写 常见问题与排错强烈建议写1️⃣1️⃣ 进阶优化可选但加分1️⃣2️⃣ 总结与延伸阅读 文末✅ 专栏持续更新中建议收藏 订阅✅ 互动征集✅ 免责声明 开篇语哈喽各位小伙伴们你们好呀我是【喵手】。运营社区 C站 / 掘金 / 腾讯云 / 阿里云 / 华为云 / 51CTO欢迎大家常来逛逛一起学习一起进步我长期专注Python 爬虫工程化实战主理专栏 《Python爬虫实战》从采集策略到反爬对抗从数据清洗到分布式调度持续输出可复用的方法论与可落地案例。内容主打一个“能跑、能用、能扩展”让数据价值真正做到——抓得到、洗得净、用得上。专栏食用指南建议收藏✅ 入门基础环境搭建 / 请求与解析 / 数据落库✅ 进阶提升登录鉴权 / 动态渲染 / 反爬对抗✅ 工程实战异步并发 / 分布式调度 / 监控与容错✅ 项目落地数据治理 / 可视化分析 / 场景化应用专栏推广时间如果你想系统学爬虫而不是碎片化东拼西凑欢迎订阅专栏《Python爬虫实战》一次订阅后专栏内的所有文章可永久免费阅读持续更新中。订阅后更新会优先推送按目录学习更高效0️⃣ 前言Preface一句话说明今天我们将使用 Python 的requests配合超高性能解析库lxml深入公开的法律名词解释专栏精准提取术语及关联法条最终构建一个结构化的本地 SQLite 数据库与 CSV 导出文件legal_terms_export.csv。读完你能获得什么掌握lxml与XPath的高级语法轻松应对严密排版的文档型网页。学会处理老旧网站常见的GBK/GB2312中文乱码问题。获得将海量字典型数据优雅存入本地关系型数据库SQLite的全套代码。1️⃣ 摘要Abstract核心内容本项目针对公开性质的法律术语百科页面通过静态爬虫技术从分类栏目切入定位条目区块提取“术语、释义、相关条文、分类、详情链接”五大核心字段。着重解决了长文本清洗与缺失字段的容错处理实现了数据的自动化流转与持久化存储。读完你能获得什么理解如何在列表页与详情页之间安全传递数据。精通利用 XPath 的“兄弟节点following-sibling”提取无规则嵌套文本。建立起对政府/学术类公开网站“温和采集”的合规意识。2️⃣ 背景与需求Why为什么要爬法律行业的痛点在于信息高度专业且分散。对于法学生、法务工作者或是合规系统开发者来说频繁翻阅大部头词典效率极低。通过爬虫技术我们可以把某权威公开普法网站上的“名词解释”栏目全量聚合打造一个可以秒级检索的本地法律元数据大脑。目标字段清单精准制导Term术语如表见代理Definition释义即对该词条的详尽解释文字Related_Article相关条文如《民法典》第一百七十二条Category分类如民商法 / 刑法 / 行政法Detail_Link详情链接用于溯源查证3️⃣ 合规与注意事项必写⚠️面对这类具有一定官方或学术背景的网站我们必须把“规矩”刻在脑子里绝不越界本代码仅用于采集公开普法、名词解释性质的知识页面绝不能用于试探或抓取涉及当事人隐私的真实裁判文书非公开数据。用中性的态度对待技术。严格遵循 robots.txt请求前检查目标根目录的爬虫协议尊重站长的意愿。极度克制的并发频率控制这类网站通常服务器性能不佳且对异常流量敏感。切记单线程 随机长延时3-5秒不要攻击式并发我们做温文尔雅的数据收集者。4️⃣ 技术选型与整体流程What/How静态网页 lxml组合拳法律解释页几乎都是纯静态的 HTML 文本为了 SEO 与无障碍阅读。这次为什么选lxml而不是bs4因为法律词条经常使用dl(定义列表) 或一连串没有明确 class 的p标签。XPath 的轴定位Axes在处理这种具有严格上下文逻辑的结构时简直是降维打击整体流程图English visualization5️⃣ 环境准备与依赖安装可复现工欲善其事必先利其器。打开终端搞定依赖Python 版本推荐 Python 3.9安装命令pipinstallrequests lxml pandas推荐项目结构legal_scraper/ ├── spider_main.py # 爬虫控制大脑 ├── xpath_parser.py # 专属的解析模块 └── data/ # 存放 SQLite 数据库与 CSV6️⃣ 核心实现请求层Fetcher许多老派的普法网站可能还在用 HTTP 而不是 HTTPS或者证书过期甚至使用古老的GBK编码。我们的请求层必须足够健壮。importrequestsimporttimeimportrandomimportlogging logging.basicConfig(levellogging.INFO,format%(asctime)s - %(levelname)s - %(message)s)defget_html_safely(url,retries3): 一个极其强壮的请求抓取器 headers{User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36,Accept:text/html,application/xhtmlxml,application/xml;q0.9,}forattemptinrange(retries):try:# verifyFalse 有时应对老旧政法网站证书过期很有用但会报警告按需开启responserequests.get(url,headersheaders,timeout15)response.raise_for_status()# 【排错预警】解决古老网站中文乱码的终极杀招# 让 requests 自动去猜页面是 UTF-8 还是 GBK并强制转码response.encodingresponse.apparent_encodingreturnresponse.textexceptrequests.exceptions.RequestExceptionase:logging.warning(fFetching failed for{url}(Attempt{attempt1}). Error:{e})time.sleep(random.uniform(2,5))# 随机退避模拟人类logging.error(fMax retries reached. Abandoning{url})returnNone7️⃣ 核心实现解析层Parser这里我们展示XPath的真正实力。假设详情页的结构是这样的一个h1是术语名接下来的几个p都是释义最后有一个strong相关法条/strong跟着内容。fromlxmlimportetreedefparse_term_detail(html,url,category_name): 利用 XPath 精准切割词条详情页 ifnothtml:returnNone# 构建 XPath 解析对象treeetree.HTML(html)# 1. 抽取术语名 (容错取不到就返回 None 跳过)term_listtree.xpath(//div[classarticle-title]/h1/text())termterm_list[0].strip()ifterm_listelseUnknown Term# 2. 抽取释义 (核心难点释义可能由多个段落组成)# 逻辑选中 class 为 definition 下的所有文字并拼接到一起definition_nodestree.xpath(//div[classdefinition-content]//text())# 清洗去掉回车换行和多余空格definition.join([text.strip()fortextindefinition_nodesiftext.strip()])# 3. 抽取相关条文 (XPath 的 following-sibling 兄弟节点大显神威)# 逻辑找到包含“相关条文”这四个字的标签然后提取它后面的兄弟节点文本article_listtree.xpath(//strong[contains(text(), 相关条文)]/following-sibling::text())related_articlearticle_list[0].strip()ifarticle_listelse暂无关联条文return{Term:term,Definition:definition,Related_Article:related_article,Category:category_name,Detail_Link:url}8️⃣ 数据存储与导出Storage既然是字典类型的数据我们这次用 Python 内置的sqlite3来存储这比纯 CSV 更高级不仅支持断点续跑去重后续查询也极快importsqlite3importpandasaspdimportos DB_PATHdata/legal_glossary_database.dbdefinit_db():初始化 SQLite 数据库表os.makedirs(data,exist_okTrue)connsqlite3.connect(DB_PATH)cursorconn.cursor()cursor.execute( CREATE TABLE IF NOT EXISTS legal_terms ( id INTEGER PRIMARY KEY AUTOINCREMENT, Term TEXT UNIQUE, Definition TEXT, Related_Article TEXT, Category TEXT, Detail_Link TEXT ) )# 使用 Term 作为 UNIQUE 防止重复抓取conn.commit()conn.close()defsave_to_db(item_dict):将单条数据存入数据库ifnotitem_dict:returnFalseconnsqlite3.connect(DB_PATH)cursorconn.cursor()try:# INSERT OR IGNORE 完美解决去重问题cursor.execute( INSERT OR IGNORE INTO legal_terms (Term, Definition, Related_Article, Category, Detail_Link) VALUES (?, ?, ?, ?, ?) ,(item_dict[Term],item_dict[Definition],item_dict[Related_Article],item_dict[Category],item_dict[Detail_Link]))conn.commit()returncursor.rowcount0# 返回是否真正插入了新数据exceptsqlite3.Errorase:logging.error(fDatabase error:{e})returnFalsefinally:conn.close()defexport_to_csv(csv_filenamedata/legal_terms_export.csv):一键将 SQLite 数据导出为数据分析人员最爱的 CSVconnsqlite3.connect(DB_PATH)dfpd.read_sql_query(SELECT * FROM legal_terms,conn)# 导出时加上 utf-8-sig 防止 Excel 打开中文乱码df.to_csv(csv_filename,indexFalse,encodingutf-8-sig)conn.close()logging.info(f✅ 成功导出{len(df)}条数据至{csv_filename})9️⃣ 运行方式与结果展示必写拼凑我们的主逻辑开始愉快地跑数据吧defmain():init_db()logging.info( Legal Dictionary Spider Started...)# 模拟从分类页获取到的两个词条详情链接target_urls[{url:http://example-law.com/term/101,category:民商法},{url:http://example-law.com/term/102,category:刑法}]foritemintarget_urls:htmlget_html_safely(item[url])# 注意这里的 parse_term_detail 需要根据目标网站真实 XPath 进行调整哦data_dictparse_term_detail(html,item[url],item[category])ifdata_dict:insertedsave_to_db(data_dict)ifinserted:logging.info(f 新增词条保存成功:{data_dict[Term]})else:logging.info(f⏭️ 词条已存在跳过:{data_dict[Term]})# 爬虫礼仪请求间隔time.sleep(random.uniform(2.5,4.5))# 全部抓取完毕后导出 CSV 给业务方验收export_to_csv()if__name____main__:main()导出后的legal_terms_export.csv示例结果TermDefinitionRelated_ArticleCategoryDetail_Link表见代理是指行为人虽无代理权但相对人客观上有充分理由相信行为人具有代理权而与其成立民事法律行为…《中华人民共和国民法典》第一百七十二条民商法http://…/101寻衅滋事罪是指肆意挑衅随意殴打、骚扰他人或任意损毁、占用公私财物或者在公共场所起哄闹事…《中华人民共和国刑法》第二百九十三条刑法http://…/102 常见问题与排错强烈建议写采集这类文档型老网站坑还是不少的教你几招“避坑指南”返回全是繁体字或奇怪的符号诊断老生常谈的编码问题。除了上文提到的apparent_encoding有时你需要强硬一点直接手动指定response.encoding GBK或response.encoding GB18030。XPath 在浏览器 F12 里能查到代码里却返回空列表[]诊断这是新手最易犯的错浏览器里的 HTML 是经过 JS 动态渲染或浏览器规范化纠错后的 DOM 树尤其是自动补全的tbody标签。解法千万不要直接 Copy 浏览器的 XPath。把爬虫请求到的response.text打印出来对着最原始的源码去写 XPath。提取的释义文本里全是不规律的\r\n\t诊断格式化排版遗留字符。解法使用 Python 字符串强大的re正则或者直接text.replace(\n, ).replace(\t, )进行暴力洗白。1️⃣1️⃣ 进阶优化可选但加分断点续跑游标机制我们目前用 SQLite 的UNIQUE约束实现了去重。但在几万个词条面前每次都去请求网页然后再发现重复太浪费时间了。进阶做法是先抓取所有的 URL 列表存入一张表设置状态字段status0抓完一个更新为status1。每次启动脚本只查status0的 URL 去发请求稳如老狗关联图谱构建针对我们开头探讨的“交叉引用”你可以把释义中所有的a href...标签里的链接提取出来存入图数据库如 Neo4j瞬间就能生成一张震撼的“法律词汇关联星空图”1️⃣2️⃣ 总结与延伸阅读 太牛了通过这篇实战你不仅成功跨越了BeautifulSoup的舒适区掌握了更为硬核的XPath解析还学会了如何应对老旧网站的编码陷阱并利用 SQLite 实现了优雅的持久化存储。这套逻辑不仅适用于法律词典无论是医学百科、金融术语库还是古籍释义网底层的抓取哲学都是完全相通的。延伸阅读如果你发现某些法律网站开始加上了恶心的字体反爬比如看到的字是“法”源码里是#x3f5c;那你下一步的研究方向就是**“字体反爬解密FontTools”**啦 文末好啦以上就是本期的全部内容啦如果你在实践过程中遇到任何疑问欢迎在评论区留言交流我看到都会尽量回复咱们下期见小伙伴们在批阅的过程中如果觉得文章不错欢迎点赞、收藏、关注哦三连就是对我写作道路上最好的鼓励与支持❤️✅ 专栏持续更新中建议收藏 订阅墙裂推荐订阅专栏 《Python爬虫实战》本专栏秉承着以“入门 → 进阶 → 工程化 → 项目落地”的路线持续更新争取让每一期内容都做到✅ 讲得清楚原理✅ 跑得起来代码✅ 用得上场景✅ 扛得住工程化想系统提升的小伙伴强烈建议先订阅专栏 《Python爬虫实战》再按目录大纲顺序学习效率十倍上升✅ 互动征集想让我把【某站点/某反爬/某验证码/某分布式方案】等写成某期实战评论区留言告诉我你的需求我会优先安排实现(更新)哒~⭐️ 若喜欢我就请关注我叭更新不迷路⭐️ 若对你有用就请点赞支持一下叭给我一点点动力⭐️ 若有疑问就请评论留言告诉我叭我会补坑 更新迭代✅ 免责声明本文爬虫思路、相关技术和代码仅用于学习参考对阅读本文后的进行爬虫行为的用户本作者不承担任何法律责任。使用或者参考本项目即表示您已阅读并同意以下条款合法使用 不得将本项目用于任何违法、违规或侵犯他人权益的行为包括但不限于网络攻击、诈骗、绕过身份验证、未经授权的数据抓取等。风险自负 任何因使用本项目而产生的法律责任、技术风险或经济损失由使用者自行承担项目作者不承担任何形式的责任。禁止滥用 不得将本项目用于违法牟利、黑产活动或其他不当商业用途。使用或者参考本项目即视为同意上述条款,即 “谁使用谁负责” 。如不同意请立即停止使用并删除本项目。