㊗️本期内容已收录至专栏《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 的requestsBeautifulSoup4工具抓取经典标靶网站的哲理名言最终产出一份结构化的英文命名数据集文件。读完本文你能获得什么掌握静态网页爬虫的“黄金四步法”请求、解析、清洗、存储。学会编写具备基础容错和重试机制的工业级网络请求代码。获得一份可以直接运行并产出数据的实战源码为后续进阶打下坚实基础。1️⃣ 摘要Abstract项目核心本文旨在通过轻量级库requests与bs4解析目标静态 HTML 页面提取文本与属性并将清洗后的数据持久化至本地 CSV 文件中。读完本文你能获得什么理解合法合规采集数据的重要原则如遵循robots.txt。精通基于 CSS 选择器的 DOM 树解析与异常字段捕获技巧。了解爬虫开发中常见的 403/429 错误排查与进阶优化思路。2️⃣ 背景与需求Why为什么要爬说实话很多人学爬虫一开始只是觉得“酷”但在实际业务中爬虫是数据分析的源泉与信息聚合的核心驱动力。假设我们需要训练一个自然语言处理NLP的“每日一言”大模型或者只是想给自己的博客做一个自动更新的“名言警句”侧边栏手动复制粘贴显然不够极客。我们需要通过自动化手段快速构建属于自己的知识图谱。目标站点与字段目标站点http://quotes.toscrape.com/官方合法的爬虫测试沙盒目标字段清单Quote_Text(名言内容)Author(作者姓名)Tags(名言相关标签由于可能有多个我们将以逗号分隔)3️⃣ 合规与注意事项必写⚠️作为一名资深爱好者我必须提醒你技术无罪但使用技术要有底线。遵循 robots.txt在爬取任何网站前请习惯性地访问域名/robots.txt查看站长允许或禁止抓取的目录。频率控制不要攻击式并发不要像发起 DDoS 攻击一样去请求别人的服务器。加上time.sleep()延时温柔一点细水长流。不采集敏感信息坚决不碰涉及个人隐私、国家安全的数据。不绕过付费/登录限制尊重内容创作者的知识产权我们只获取公开的互联网公共信息。4️⃣ 技术选型与整体流程What/How技术定调静态网页爬取目标网站服务端直接通过 HTML 返回了完整的数据内容没有使用复杂的 Ajax 动态加载或加密混淆。因此这属于最经典的静态网页爬虫。为什么选requestsbs4俗话说“杀鸡焉用牛刀”面对这种结构清晰的静态网站上Scrapy框架有点重用Playwright渲染引擎又太浪费系统资源。requests负责高效建立 HTTP 通信BeautifulSoup的 CSS 选择器写起来直观且优雅是本场景的最佳组合。整体流程图如下English visualization as requested5️⃣ 环境准备与依赖安装可复现无论你是小白还是老鸟拥有一个干净的虚拟环境都是好习惯。加油把这几行命令敲起来Python 版本推荐 Python 3.8 或以上版本。依赖安装pipinstallrequests beautifulsoup4 pandas推荐项目结构quote_spider/ ├── main.py # 入口启动文件 ├── fetcher.py # 网络请求模块 ├── parser.py # 页面解析模块 ├── storage.py # 数据存储模块 └── data/ # 存放输出文件的目录(为了方便你直接复制运行接下来的代码我会整合在一个优雅的脚本中)6️⃣ 核心实现请求层Fetcher这一层是爬虫的“敲门砖”。不带Headers的请求就像没穿衣服在街上跑很容易被服务器封禁。importrequestsimporttimeimportlogging logging.basicConfig(levellogging.INFO,format%(asctime)s - %(levelname)s - %(message)s)deffetch_page(url,retries3):# 必须说明模拟真实浏览器的 Headersheaders{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,image/webp,*/*;q0.8,Referer:http://quotes.toscrape.com/# 告诉服务器我从哪里来}forattemptinrange(retries):try:# 必须说明加上 timeout 防止死锁挂起responserequests.get(url,headersheaders,timeout10)response.raise_for_status()# 遇到 4xx 或 5xx 会抛出异常returnresponse.textexceptrequests.exceptions.RequestExceptionase:logging.warning(fFetch failed on{url}. Attempt{attempt1}of{retries}. Error:{e})time.sleep(2**attempt)# 指数退避策略失败后等待 1s, 2s, 4slogging.error(fMax retries reached for{url})returnNone7️⃣ 核心实现解析层Parser拿到 HTML 源码后我们要精准地“摘取”数据。这里采用bs4的 CSS 选择器.select()。frombs4importBeautifulSoupdefparse_quotes(html_content):ifnothtml_content:return[],NonesoupBeautifulSoup(html_content,html.parser)quotes_data[]# 获取列表页中的所有名言块quote_blockssoup.select(div.quote)forblockinquote_blocks:# 提取字段并做容错处理缺失字段怎么办用 .get_text() 前先判断text_elementblock.select_one(span.text)quote_texttext_element.get_text(stripTrue)iftext_elementelseUnknown Quoteauthor_elementblock.select_one(small.author)authorauthor_element.get_text(stripTrue)ifauthor_elementelseUnknown Authortags_elementsblock.select(div.tags a.tag)tags[tag.get_text(stripTrue)fortagintags_elements]tags_str, .join(tags)iftagselseNo Tagsquotes_data.append({Quote_Text:quote_text,Author:author,Tags:tags_str})# 获取下一页的链接next_btnsoup.select_one(li.next a)next_urlfhttp://quotes.toscrape.com{next_btn[href]}ifnext_btnelseNonereturnquotes_data,next_url8️⃣ 数据存储与导出Storage这里我们选择极其通用且易于数据分析的CSV格式。我们使用 URL 或内容的 Hash 来去重这里不需要因为目标网站分页明确无重复但为了严谨我们基于Quote_Text做简单的去重校验。importcsvimportosdefsave_to_csv(data_list,filenamequotes_dataset.csv):ifnotdata_list:return# 去重策略按名言内容去重seenset()unique_data[]foritemindata_list:ifitem[Quote_Text]notinseen:seen.add(item[Quote_Text])unique_data.append(item)# 字段映射与存储keys[Quote_Text,Author,Tags]file_existsos.path.isfile(filename)withopen(filename,a,newline,encodingutf-8)asoutput_file:dict_writercsv.DictWriter(output_file,fieldnameskeys)ifnotfile_exists:dict_writer.writeheader()dict_writer.writerows(unique_data)logging.info(fSuccessfully saved{len(unique_data)}unique records to{filename}.)9️⃣ 运行方式与结果展示必写将上面的代码拼接在一起你可以自行加一个main()函数并在其中加上time.sleep(1)翻页逻辑。启动命令打开你的终端运行python main.py输出位置代码将在当前目录生成一个名为quotes_dataset.csv的文件。示例结果前3行Quote_TextAuthorTags“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”Albert Einsteinchange, deep-thoughts, thinking, world“It is our choices, Harry, that show what we truly are, far more than our abilities.”J.K. Rowlingabilities, choices“There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.”Albert Einsteininspirational, life, live, miracle 常见问题与排错强烈建议写爬虫总会遇到各种玄学问题别气馁排错过程才是长知识的黄金时刻遇上 403 或 429 怎么办403 通常是因为你的 Headers 太假了尤其是缺失了真实的User-Agent或者Referer。429 说明你的访问频率触碰了站点的警报线。解法加大time.sleep()延迟或者建立代理 IP 池轮换 IP。抓下来的 HTML 全是 JS 脚本的空壳恭喜你遇到了 SPA单页应用如 Vue/React 开发的网站。静态请求拿不到数据了。解法按 F12 打开开发者工具看Network-XHR/Fetch直接去抓取背后的 JSON 数据接口 API。解析报错NoneType object has no attribute get_text这是因为网站结构变化或某个元素本来就不存在。解法在.get_text()前一定要做非空判断参考本文第7节的容错写法。中文乱码怎么破requests有时会猜错网页编码直接在解析前强制声明response.encoding utf-8。1️⃣1️⃣ 进阶优化可选但加分如果你已经玩透了基础的想要挑战更强大的架构并发加速把简单的for循环换成concurrent.futures.ThreadPoolExecutor实现多线程抓取速度起飞但记住线程池越大越容易被封。断点续跑如果网站有 10000 页爬到 5000 页断网了怎么办可以引入 Redis 集合存储已经爬取过的 URL每次开跑前做一次差集比对。定时调度结合服务器的crontab或者更高级的Apache Airflow每天早上 8 点自动抓取更新数据。1️⃣2️⃣ 总结与延伸阅读 恭喜你读到了这里复盘一下我们今天用 Python 完成了一套完整的爬虫闭环从设置带重试机制的网络请求到 CSS 结构化解析最后稳稳地把干干净净的数据存入了CSV中。下一步的打怪升级方向当你遇到需要滑动验证码、需要执行 JavaScript 或者点击翻页的复杂网站时这套基础方案就不够用了。接下来你可以去了解Playwright无头浏览器自动化控制以及工业级的Scrapy爬虫框架。 文末好啦以上就是本期的全部内容啦如果你在实践过程中遇到任何疑问欢迎在评论区留言交流我看到都会尽量回复咱们下期见小伙伴们在批阅的过程中如果觉得文章不错欢迎点赞、收藏、关注哦三连就是对我写作道路上最好的鼓励与支持❤️✅ 专栏持续更新中建议收藏 订阅墙裂推荐订阅专栏 《Python爬虫实战》本专栏秉承着以“入门 → 进阶 → 工程化 → 项目落地”的路线持续更新争取让每一期内容都做到✅ 讲得清楚原理✅ 跑得起来代码✅ 用得上场景✅ 扛得住工程化想系统提升的小伙伴强烈建议先订阅专栏 《Python爬虫实战》再按目录大纲顺序学习效率十倍上升✅ 互动征集想让我把【某站点/某反爬/某验证码/某分布式方案】等写成某期实战评论区留言告诉我你的需求我会优先安排实现(更新)哒~⭐️ 若喜欢我就请关注我叭更新不迷路⭐️ 若对你有用就请点赞支持一下叭给我一点点动力⭐️ 若有疑问就请评论留言告诉我叭我会补坑 更新迭代✅ 免责声明本文爬虫思路、相关技术和代码仅用于学习参考对阅读本文后的进行爬虫行为的用户本作者不承担任何法律责任。使用或者参考本项目即表示您已阅读并同意以下条款合法使用 不得将本项目用于任何违法、违规或侵犯他人权益的行为包括但不限于网络攻击、诈骗、绕过身份验证、未经授权的数据抓取等。风险自负 任何因使用本项目而产生的法律责任、技术风险或经济损失由使用者自行承担项目作者不承担任何形式的责任。禁止滥用 不得将本项目用于违法牟利、黑产活动或其他不当商业用途。使用或者参考本项目即视为同意上述条款,即 “谁使用谁负责” 。如不同意请立即停止使用并删除本项目。