news 2026/7/18 12:06:05

从0到1写爬虫:爬取博客园文章标题+链接,BeautifulSoup解析超详细

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从0到1写爬虫:爬取博客园文章标题+链接,BeautifulSoup解析超详细

摘要:本文面向零基础读者,以爬取博客园文章列表页的“标题+链接”为实战目标,手把手带你走完爬虫全流程。重点拆解 BeautifulSoup 的核心API与调试技巧,附带DOM结构分析图、完整可运行代码及常见踩坑解决方案。不讲玄学,只讲能复用的方法论。


一、 为什么选博客园做第一个爬虫项目?

在CSDN上搜“爬虫入门”,示例站点五花八门,但很多并不适合新手:

  • 动态渲染页面(如SPA)需要Selenium/Playwright,门槛过高
  • 反爬严格的站点(如某宝、某点评)容易触发封禁,挫败感强
  • 结构过于简单的站点学不到东西,换个站就不会了

博客园是难得的“黄金练习场”

优势说明
服务端渲染HTML直出,requests即可获取完整内容
结构规范class命名语义化,CSS选择器友好
反爬温和合理频率下不会封IP,适合反复调试
数据有价值真实技术文章,爬完可直接用于RSS/知识库

💡核心理念:入门阶段的目标不是“爬到多少数据”,而是建立“观察→解析→验证”的肌肉记忆。博客园恰好能让这个循环转起来。


二、 动手之前:先学会“看”网页

90%的新手爬虫失败,不是因为代码写错,而是因为没看清HTML结构就急着写选择器。请务必养成“先审查,后编码”的习惯。

2.1 浏览器开发者工具使用要点

打开博客园首页或任意分类页(如https://www.cnblogs.com/),按F12打开DevTools:

  1. Elements面板→ 鼠标悬停文章标题,观察其DOM层级
  2. Network面板→ 刷新页面,确认请求是HTML文档而非JSON API
  3. Console面板→ 输入document.querySelectorAll('.post-item-title')预验证选择器

2.2 博客园文章列表DOM结构分析

经过观察,博客园文章列表的典型结构如下(已简化):

div.post-list

div.post-item

h2.post-item-title

a[href] 文章标题文本

div.post-item-summary

div.post-item-footer

关键发现

  • 每篇文章包裹在div.post-item
  • 标题位于h2.post-item-title > a标签内
  • 链接地址在a标签的href属性中
  • 该结构在首页、分类页、搜索结果页高度一致

⚠️注意:网站可能随时改版。本文基于2026年7月的页面结构编写,若你运行时选择器失效,请重新执行上述审查步骤。“会审查”比“记住选择器”重要一万倍。


三、 BeautifulSoup核心API速查表

BS4的API不多,但新手常混淆。下面这张表覆盖了95%的使用场景:

方法/属性用途返回值典型用法
find()查找第一个匹配节点Tag / Nonesoup.find('h2', class_='title')
find_all()查找所有匹配节点ResultSet (list)soup.find_all('a', href=True)
select()CSS选择器查找listsoup.select('div.post-item h2 a')
select_one()CSS选择器查找首个Tag / Nonesoup.select_one('.title a')
.text/.get_text()获取标签内纯文本strtag.get_text(strip=True)
['attr']获取属性值str / Nonetag['href']
.get('attr', default)安全获取属性str / defaulttag.get('href', '')

3.1findvsselect:如何选择?

  • 简单条件(单标签+class/id)→ 用find/find_all,语义直观
  • 复杂层级(后代、兄弟、属性组合)→ 用select,表达力强
  • 性能敏感find略快(无需CSS解析器),但差异可忽略

🎯本文推荐:统一使用select/select_one。CSS选择器是可迁移技能,换了lxml/parsel也能直接用。


四、 完整代码实现(逐行精讲)

4.1 环境准备

pipinstallrequests beautifulsoup4 lxml

lxml作为BS4的解析后端,比内置的html.parser快3-5倍,且容错性更好。永远指定解析器,避免警告和隐式行为。

4.2 完整代码

importtimeimportrandomimportrequestsfrombs4importBeautifulSoup# ========== 配置区 ==========TARGET_URL="https://www.cnblogs.com/"HEADERS={"User-Agent":("Mozilla/5.0 (Windows NT 10.0; Win64; x64) ""AppleWebKit/537.36 (KHTML, like Gecko) ""Chrome/126.0.0.0 Safari/537.36"),}OUTPUT_FILE="cnblogs_articles.txt"# ============================deffetch_html(url:str)->str|None:""" 安全获取页面HTML 返回None表示请求失败,调用方需处理 """try:resp=requests.get(url,headers=HEADERS,timeout=10)resp.raise_for_status()# 非2xx状态码抛异常resp.encoding=resp.apparent_encoding# 自动检测编码returnresp.textexceptrequests.RequestExceptionase:print(f"[ERROR] 请求失败:{url}=>{e}")returnNonedefparse_articles(html:str)->list[dict]:""" 解析文章标题与链接 核心:CSS选择器 + 防御性取值 """soup=BeautifulSoup(html,"lxml")articles=[]# CSS选择器定位所有文章条目中的标题链接links=soup.select("div.post-item h2.post-item-title a")fortaginlinks:title=tag.get_text(strip=True)# strip=True去除首尾空白href=tag.get("href","")# 安全取值,避免KeyErroriftitleandhref:# 过滤空数据articles.append({"title":title,"link":href,})returnarticlesdefsave_to_file(articles:list[dict],filepath:str):"""保存为可读文本格式"""withopen(filepath,"w",encoding="utf-8")asf:forartinarticles:f.write(f"{art['title']}\n{art['link']}\n{'-'*60}\n")print(f"[OK] 已保存{len(articles)}条记录至{filepath}")defmain():print(f"🔍 目标:{TARGET_URL}")html=fetch_html(TARGET_URL)ifhtmlisNone:print("❌ 获取页面失败,退出")returnarticles=parse_articles(html)print(f"📦 解析到{len(articles)}篇文章")ifarticles:save_to_file(articles,OUTPUT_FILE)else:print("⚠️ 未解析到任何文章,请检查页面结构是否变化")if__name__=="__main__":main()

4.3 三个容易被忽视的细节

resp.apparent_encoding而非resp.encoding

requests默认的resp.encoding仅根据HTTP头推断,博客园有时返回ISO-8859-1导致中文乱码。apparent_encoding通过内容特征检测,准确率远高于前者。这一行代码能消灭80%的乱码问题。

get_text(strip=True)而非.text.strip()

两者结果相同,但get_text()还支持separator参数(如get_text(' ', strip=True)将多个子节点文本用空格连接)。当标题内含<span>等嵌套标签时,.text可能产生意外拼接。养成用get_text()的习惯,未来少踩坑。

③ 选择器写在独立函数中

parse_articles函数的全部价值就是“把HTML变成结构化数据”。如果明天博客园改了class名,你只需修改这一个函数里的选择器字符串,fetch_htmlsave_to_file完全不动。这就是单一职责原则在爬虫中的落地。


五、 调试实战:选择器找不到元素怎么办?

这是新手最高频的问题。按以下流程图排查:

select返回空列表

打印html[:500]
确认内容非空?

请求失败或被拦截
检查headers/状态码

DevTools中
同一选择器有结果?

选择器写错了
重新审查DOM结构

requests获取的HTML
与浏览器一致?

页面依赖JS渲染
改用Selenium或找API

编码是否正确?
打印soup.prettify()检查

修正encoding

检查是否有iframe/
shadow DOM等特殊结构

实用调试技巧

# 技巧1:保存原始HTML到本地,离线调试withopen("debug.html","w",encoding="utf-8")asf:f.write(html)# 技巧2:逐步缩小选择器范围print(soup.select("div.post-item"))# 第1步:容器是否存在print(soup.select("div.post-item h2"))# 第2步:h2是否存在print(soup.select("div.post-item h2 a"))# 第3步:a是否存在# 技巧3:打印Tag对象而非仅文本,观察完整属性fortaginsoup.select("div.post-item h2 a")[:3]:print(repr(tag))# repr显示完整标签,包括隐藏属性

🔑黄金法则永远不要假设HTML长什么样,永远用实际获取的内容验证选择器。浏览器看到的 ≠ requests拿到的,这是两个完全不同的世界。


六、 进阶方向:从“能用”到“好用”

当你跑通基础版本后,可以按需叠加以下能力:

方向技术方案适用场景
多页抓取URL分页参数 + 循环 + 随机sleep分类页、搜索结果
增量去重SQLite/set记录已爬URL定时任务、长期监控
异步加速aiohttp + asyncio百页以上大规模抓取
数据持久化pandas.to_csv / SQLAlchemy后续分析、可视化
代理池requests proxies参数高频抓取防封

⚠️重要提醒:爬取前务必阅读博客园的 robots.txt 和使用条款。控制请求频率(建议≥2秒/次),仅用于个人学习研究,不对服务器造成负担。合规是爬虫工程师的第一素养。


七、 总结:爬虫入门的正确姿势

回顾全文,我们实际上只做了一件事:把“人眼看到的信息”翻译成“程序能提取的结构”

BeautifulSoup只是翻译工具,真正的核心能力是:

  1. 观察力:能从混乱的HTML中识别出稳定的数据模式
  2. 验证习惯:每一步都有据可查,不靠猜测写代码
  3. 工程意识:代码分层、防御性编程、错误可追溯

这三项能力,无论你将来用BS4、parsel、lxml还是Scrapy,都是通用的。

别急着学框架,先把一个页面吃透。当你能在10分钟内完成“审查→选择器→验证→提取”的完整闭环时,你就已经入门了。


参考资料

  • BeautifulSoup官方文档
  • requests编码处理机制详解
  • 博客园robots.txt

📌免责声明:本文代码仅供学习交流,请严格遵守目标网站的使用条款和相关法律法规。作者不对任何因使用本文代码而产生的法律后果负责。


如果这篇帮你理清了BS4的使用思路,欢迎点赞收藏。遇到选择器问题可以在评论区贴出你的HTML片段和目标数据,我会帮你分析。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/18 12:02:54

WordPress到Hugo导出器CLI使用指南:命令行批量迁移技巧

WordPress到Hugo导出器CLI使用指南&#xff1a;命令行批量迁移技巧 【免费下载链接】wordpress-to-hugo-exporter Hugo is static site generator written in golang. Wordpress is a tool for remote access to your server ;-) ❗️Contributions welcome! 项目地址: https…

作者头像 李华
网站建设 2026/7/18 12:01:30

MEV-template-rs与Discord集成:构建智能警报系统的完整指南

MEV-template-rs与Discord集成&#xff1a;构建智能警报系统的完整指南 【免费下载链接】mev-template-rs Bootstrap your MEV bot strategies with a simple boilerplate to build on top of. 项目地址: https://gitcode.com/gh_mirrors/me/mev-template-rs MEV-templa…

作者头像 李华
网站建设 2026/7/18 12:01:21

低成本机器人手臂终极指南:如何用250美元打造专业级机械臂

低成本机器人手臂终极指南&#xff1a;如何用250美元打造专业级机械臂 【免费下载链接】low_cost_robot 项目地址: https://gitcode.com/GitHub_Trending/lo/low_cost_robot 想要拥有一台属于自己的机器人手臂&#xff0c;但被高昂的价格劝退&#xff1f;现在&#xff…

作者头像 李华