3、Python爬虫实战(一):Requests库入门、BeautifulSoup解析HTML、抓取新闻标题与正文
各位好,咱们今天正式进入爬虫实战环节。
说实话,很多新手一听到「爬虫」两个字,就觉得是黑客技术。其实没那么玄乎。说白了,爬虫就是帮你去网页上「复制粘贴」的自动化工具。你手动能看到的网页内容,爬虫也能拿到,只是它比你快得多。
我个人习惯把爬虫拆成三步:请求 → 解析 → 存储。今天这一章,咱们就先把前两步搞定。我会用 Requests 库去拿网页数据,再用 BeautifulSoup 去解析 HTML。最后,咱们拿一个真实的新闻网站练练手。
核心知识点速览
- Requests 库:发送 HTTP 请求,获取网页源代码
- BeautifulSoup:解析 HTML,提取你想要的元素
- 实战案例:抓取新闻标题与正文
3.1 Requests 库:从零开始拿网页
Requests 是 Python 里最优雅的 HTTP 库。没有之一。我最早用 urllib 的时候,每次都要手动处理编码、拼接参数,烦得很。后来换了 Requests,感觉整个世界都清净了。
安装很简单,一行命令搞定:
pip install requests
咱们直接上手。拿一个新闻网站试试:
import requests
url = "https://news.sina.com.cn/"
response = requests.get(url)
# 检查状态码
print(response.status_code) # 200 表示成功
# 打印前500个字符看看
print(response.text[:500])
嗯,这里要注意。很多新手一上来就打印全部内容,结果控制台直接卡死。我建议你先打印前几百个字符,确认拿到的是 HTML 而不是错误页面。
我的小习惯:每次请求后,我都会先检查 response.status_code。如果是 403 或 404,就别往下解析了,省得浪费时间。
为什么会遇到 403?因为有些网站会检查请求头。你想想看,一个正常的浏览器访问网页,会带上 User-Agent、Referer 等信息。而你的爬虫默认啥都没有,服务器一看就知道是机器在访问。
解决办法很简单,加个请求头:
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
response = requests.get(url, headers=headers)
我在项目中遇到过好几次,不加请求头直接返回空数据。加了之后,数据就正常了。所以这个习惯一定要养成。
3.2 BeautifulSoup:把 HTML 变成可操作的数据
拿到网页源代码之后,下一步就是解析。BeautifulSoup 能把杂乱的 HTML 变成一棵清晰的树,你可以像在文件夹里找文件一样,找到你想要的标签。
安装:
pip install beautifulsoup4
解析器我推荐用 lxml,速度比默认的 Python 解析器快很多:
pip install lxml
来看一个简单的例子:
from bs4 import BeautifulSoup
html = "<h1>今日头条</h1><p class='content'>这是一条新闻正文</p>"
soup = BeautifulSoup(html, "lxml")
# 提取 h1 标签
title = soup.find("h1").text
print(title) # 输出:今日头条
# 提取 class 为 content 的 p 标签
content = soup.find("p", class_="content").text
print(content) # 输出:这是一条新闻正文
这里有个细节:class_ 后面带了个下划线。因为 class 是 Python 的关键字,所以 BeautifulSoup 用了 class_ 来区分。我第一次用的时候也踩过这个坑,写成了 class,结果报错半天没反应过来。
避坑指南:我曾经在解析一个新闻列表时,发现 find() 只返回了第一条数据。后来才意识到,应该用 find_all() 来获取所有匹配的标签。记住:find() 返回单个元素,find_all() 返回列表。
3.3 实战:抓取新闻标题与正文
理论说完了,咱们来点真格的。我选一个常见的新闻网站——新浪新闻。咱们的目标是:抓取某条新闻的标题和正文。
先打开浏览器,找到一条新闻的 URL。比如:https://news.sina.com.cn/c/2025-01-15/doc-xxxxx.shtml
然后,用开发者工具(F12)查看页面结构。你会发现标题通常在 <h1 class="main-title"> 里,正文在 <div class="article"> 里。
完整代码:
import requests
from bs4 import BeautifulSoup
url = "https://news.sina.com.cn/c/2025-01-15/doc-xxxxx.shtml"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
response = requests.get(url, headers=headers)
response.encoding = "utf-8" # 避免中文乱码
soup = BeautifulSoup(response.text, "lxml")
# 提取标题
title_tag = soup.find("h1", class_="main-title")
title = title_tag.text.strip() if title_tag else "未找到标题"
# 提取正文
content_div = soup.find("div", class_="article")
if content_div:
paragraphs = content_div.find_all("p")
content = "\n".join([p.text.strip() for p in paragraphs])
else:
content = "未找到正文"
print("标题:", title)
print("正文:", content[:200] + "...") # 只打印前200字
这里我特意加了一行 response.encoding = "utf-8"。为什么?因为有些网站返回的编码不是 UTF-8,直接打印会看到一堆乱码。我建议你每次请求后都手动设置一下编码,省心。
核心要点总结:
- Requests 负责「拿」,BeautifulSoup 负责「拆」
- 请求头里的 User-Agent 是必备项
- 用
find()找单个元素,用find_all()找多个 - 编码问题一定要处理,否则中文全是乱码
3.4 进阶技巧:处理动态加载的内容
你可能会遇到这种情况:用 Requests 拿到的 HTML 里,新闻标题是空的。为什么?因为有些网站的内容是通过 JavaScript 动态加载的。说白了,你看到的页面是浏览器渲染之后的,而 Requests 拿到的只是原始 HTML 骨架。
遇到这种情况怎么办?有两个思路:
- 找接口:打开开发者工具的 Network 面板,看看有没有 JSON 数据接口。很多新闻网站其实是通过 Ajax 加载内容的,直接请求那个接口就行。
- 用 Selenium:如果实在找不到接口,就用 Selenium 模拟浏览器。这个咱们后面章节会详细讲。
我个人更倾向于找接口。因为 Selenium 太慢了,而且容易出各种环境问题。你想想看,一个接口请求 0.1 秒,Selenium 可能要 3 秒,差距太大了。
一个小技巧:在浏览器里按 F12 → Network → XHR,刷新页面,看看有没有返回 JSON 的请求。如果有,直接复制那个 URL 用 Requests 请求,效率最高。
3.5 数据存储:先存到本地再说
抓下来的数据,总不能每次都打印到控制台吧?我习惯先存到本地文件里,方便后续处理。
# 保存为文本文件
with open("news.txt", "w", encoding="utf-8") as f:
f.write(f"标题:{title}\n")
f.write(f"正文:{content}\n")
print("数据已保存到 news.txt")
如果你抓的是多条新闻,可以考虑存成 CSV 或 JSON。这个咱们后面章节会展开讲。
好了,这一章的内容就到这儿。Requests 和 BeautifulSoup 的组合,能解决 80% 的静态网页抓取需求。剩下的 20%,咱们后面慢慢攻克。
公众号:蓝海资料掘金营,微信deep3321