Python 抓取网页入门
1280
很多 Python 初学者学完基础语法之后,都会很自然地遇到一个问题: 怎么能把网页里那些看起来零零散散的内容,给“薅”下来,变成自己能处理的数据呢? 比如: 抓取文章标题 提取商品名称和价格 收集招聘信息 批量整理博客链接 分析网页中的表格和列表 这时候,BeautifulSoup 往往就是最适合
很多 Python 初学者学完基础语法之后,都会很自然地遇到一个问题:

怎么能把网页里那些看起来零零散散的内容,给“薅”下来,变成自己能处理的数据呢?
比如:
这时候,BeautifulSoup 往往就是最适合入门的那把“瑞士军刀”。它不像那些大型爬虫框架,一上来就甩给你一堆工程化的概念,也不像正则表达式那样,写出来像天书,自己都看不懂。它做的事情很纯粹,也很优雅:
帮你解析 HTML,然后从中提取出你真正想要的数据。
如果你现在正在学习 Python,又对网页数据抓取跃跃欲试,这篇文章就是为你量身定做的。我们会从 0 开始,把以下这些问题彻底讲清楚:
requests 是怎么分工的?find()、find_all()、select() 这些核心方法精准锁定数据?BeautifulSoup 是一个专门用来解析 HTML / XML 文档的 Python 库。
你可以把它想象成一个“网页内容整理员”。网页源码本质上就是一大段字符串,里面各种标签混杂在一起,比如:
Python 入门
查看详情
如果你直接对着这段字符串用切片、写正则去抠,那代码会脆弱得跟纸糊的一样,页面结构稍微一改,你的代码就废了。
而 BeautifulSoup 的厉害之处在于,它先把这段混乱的 HTML 解析成一个结构化的对象。之后,你就像查一棵树一样,可以很优雅地找到:
这也是它名字里 Soup 的由来 —— 再乱的“网页汤”,它都能帮你整理得清清爽爽,让你轻松“舀”出想要的内容。
这几乎是每个新手都会混淆的问题。其实它们的职责非常清晰,可以说是“最佳拍档”:
requests:负责“跑腿”。去向网站发请求,把网页的内容整个下载回来。BeautifulSoup:负责“拆包”。把你拿回来的 HTML 内容,解析成好用的结构,然后从中提取数据。所以它们经常成对出现,标准流程如下:
requests.get() 把 HTML 拿到手。BeautifulSoup() 把这个 HTML 解析成一个可操作的对象。一句话就能记住:
requests 负责“下载网页”,BeautifulSoup 负责“拆解网页”。
安装 BeautifulSoup 很简单:
pip install beautifulsoup4
实际抓取网页时,通常需要跟 requests 搭配使用:
pip install requests beautifulsoup4
如果你希望解析速度更快一些,可以考虑安装 lxml 解析器:
pip install lxml
不过对于入门阶段,用 Python 自带的 html.parser 完全够用,没必要一上来就折腾这些。
先别急着去抓真实网站,那样容易碰一鼻子灰。最好的方法是先用一段本地的 HTML 练手,把原理搞明白。下面这段代码,可以说是 BeautifulSoup 的“Hello World”:
from bs4 import BeautifulSoup
html = """
Python 学习笔记
这是一个 BeautifulSoup 示例页面
第一篇文章
第二篇文章
"""
soup = BeautifulSoup(html, "html.parser")
print(soup.h1.get_text())
print(soup.find("p", class_="desc").get_text())
这段代码里最关键的一行是:
soup = BeautifulSoup(html, "html.parser")
这行代码的意思是把字符串形式的 HTML 喂给 BeautifulSoup,并告诉它用 Python 自带的 html.parser 来“消化”它。之后,你就可以通过 soup.h1、find()、select() 这些方式去拿数据了。
BeautifulSoup 的 API 不算少,但对新手来说,真正核心、用得最多的,就下面这几个。
title = soup.find("h1")
print(title.get_text())
如果页面里有多个 h1 标签,它只会返回第一个找到的。你也可以通过属性来精确匹配:
desc = soup.find("p", class_="desc")
注意,这里用的是 class_,后面有个下划线,因为 class 是 Python 的保留关键字,不能直接拿来用。
links = soup.find_all("a")
for link in links:
print(link.get_text(), link.get("href"))
这个方法非常适合提取列表类数据,比如:
如果你有前端基础,你会爱上这个方法的。它允许你用写 CSS 的方式来找元素。
items = soup.select("a")
desc = soup.select_one("p.desc")
常见写法示例:
div:选择所有 div 标签.card:选择 class 为 card 的所有元素#main:选择 id 为 main 的元素.article-list a:选择 article-list 这个区域下的所有 a 标签在实际项目中,select() 和 select_one() 用起来往往比 find() 更顺手,也更灵活。
提取文本:
text = title.get_text(strip=True)
提取属性:
href = link.get("href")
这两个方法的区别必须搞清楚:
get_text():拿的是标签“里面”的文字内容。get("href"):拿的是标签“上面”的属性值,比如链接地址。下面这个示例,会更接近真实项目的样子。我把完整的代码整理了一下,方便你本地直接跑起来验证。假设我们有这样一个 HTML 结构:
beautifulsoup_web_scraping_demo.py
代码如下:
from __future__ import annotations
from bs4 import BeautifulSoup
import requests
SAMPLE_HTML = """
BeautifulSoup Demo
"""
def parse_local_html() -> list[dict[str, str]]:
soup = BeautifulSoup(SAMPLE_HTML, "html.parser")
articles: list[dict[str, str]] = []
for card in soup.select(".article-card"):
link = card.select_one(".title a")
author = card.select_one(".author")
views = card.select_one(".views")
if link is None or author is None or views is None:
continue
articles.append(
{
"id": card.get("data-id", ""),
"title": link.get_text(strip=True),
"url": link.get("href", ""),
"author": author.get_text(strip=True),
"views": views.get_text(strip=True),
}
)
return articles
def fetch_page_title(url: str) -> str:
headers = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/124.0 Safari/537.36"
)
}
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
if soup.title and soup.title.string:
return soup.title.string.strip()
return "页面没有 title"
def main() -> None:
print("本地 HTML 解析结果:")
for item in parse_local_html():
print(item)
# 真实抓取时,把这里替换成你自己的目标网页。
# 使用前请先确认目标站点允许抓取,并控制请求频率。
# title = fetch_page_title("https://example.com")
# print("页面标题:", title)
if __name__ == "__main__":
main()
这个示例故意分成了两部分,建议你也这么练:
parse_local_html():让你先专注理解 BeautifulSoup 的解析过程本身,不受网络环境影响。fetch_page_title():告诉你如何把真实网页抓下来,然后无缝对接到 BeautifulSoup 上。学习这类东西,记住一个诀窍:先会“解析”,再会“抓取”,最后再把两者组合起来,就水到渠成了。
别看网站千变万化,但绝大部分抓取逻辑,都可以拆解成下面这五个标准步骤,这是一个固定的套路:
import requests response = requests.get(url, timeout=10) html = response.text
from bs4 import BeautifulSoup soup = BeautifulSoup(html, "html.parser")
cards = soup.select(".article-card")
for card in cards:
title = card.select_one(".title").get_text(strip=True)
link = card.select_one("a").get("href")
data.append({
"title": title,
"url": link,
})
所以,BeautifulSoup 真正的核心工作,本质上就是:
先找到“每条数据的边界”(比如一个商品卡片、一篇文章块),再从每块边界里拆出具体的字段(标题、作者、价格等)。
这也是写任何抓取脚本时,最重要的思维方式。别想着一次把所有东西都抓出来,而是先分块,再精耕细作。
很多新手上来就喜欢对着整个页面用 soup.find_all("a"),以为这样就能拿到所有文章的链接。
结果当然能找到一堆链接,但里面往往混杂着:
最后拿到的数据会很乱,你需要浪费大量时间在“清洗”上。
更好的做法是,先从“结构”入手:
div.article-list。div.article-card。card 里,提取标题、链接、作者这些具体信息。所以,尽量从 soup.select(".article-card") 这种“按块定位”的方式入手,而不是在整个页面里“大海捞针”。
创建 BeautifulSoup 对象时,第二个参数就是解析器。
BeautifulSoup(html, "html.parser")
常见的有三个选择:
html.parser:Python 自带,无需额外安装,最省事。lxml:速度更快、容错性也强一些,是很多项目的首选,但需要安装。html5lib:容错性最强,能处理一些极其不规范的页面,但速度最慢,也最重。给新手的建议非常明确:
html.parser 就足够了,不要浪费时间在“选哪个解析器”上。lxml 来提升性能。先跑通流程,远比一开始就纠结“哪个性能更好”重要得多。
这是 BeautifulSoup 初学者最常遇到的一个坑,让人抓狂。你明明在浏览器里看到了内容,但用 requests.get() 拿回来的 HTML 里却没有。
绝大多数情况下,原因只有一个:
这个页面的关键数据是通过 Ja vaScript 动态加载的。
什么意思呢?就是浏览器打开页面后,它还会去执行 JS 代码,再向后台的接口请求数据,最后把内容“渲染”出来给你看。而 requests 拿到的,只是那个“空壳”页面最初的 HTML。
这时候,BeautifulSoup 本身没问题,问题在于你给它“吃”的输入源就是残缺的。
遇到这种情况,通常有两个思路:
记住一个核心原则:
BeautifulSoup 擅长解析 HTML,但它绝不会替你执行任何前端 Ja vaScript 代码。
这部分内容,往往比语法本身更重要,很多坑都是在这里。
真正的抓取工作,不是看到标签就往上怼代码。正确的做法是先打开“开发者工具”,冷静地观察页面结构:
只有先分析清楚结构,BeautifulSoup 才能真正为你所用。否则你就是在瞎撞。
很多网站对于“非浏览器”的请求是带有戒心的,最简单也最有效的方法就是带上一个常见的 User-Agent,假装自己是谷歌浏览器。
headers = {
"User-Agent": "Mozilla/5.0 ..."
}
response = requests.get(url, headers=headers, timeout=10)
千万别默认所有网络请求都会成功。网络波动、服务器报错都是家常便饭。务必要加上:
response.raise_for_status()
这句代码会帮你把 HTTP 的错误(比如404,500)暴露出来,否则你很可能在那对着一个报错页面拼命解析,还以为是自己的选择器写错了。
如果你需要抓取多页内容,务必在每次请求之间添加延时(比如 time.sleep(1))。用极高频率连续请求,不仅容易触发网站的反爬机制导致被封 IP,也会给目标网站服务器带来不必要的压力,这是一种很不专业的行为。
这一点需要时刻牢记。在动手之前,最好先看一眼目标网站的 robots.txt 和它的使用条款。技术上能做,不代表你就应该做。做个有职业道德的爬虫开发者。
BeautifulSoup 的特性决定了它特别适合以下这些场景:
比如下面这些任务,它都是完美人选:
你的目标只是先把网页数据拿下来,为后续的分析和处理做铺垫,那么 BeautifulSoup 是一个非常好的起点。
这几乎是每个走到这一步的人都会问的问题。它们不是竞争关系,而是适用于不同阶段。
简单来说:
requests + BeautifulSoup,它更轻、更直接,学习成本也低。所以,别把 BeautifulSoup 看作是“低配版 Scrapy”。它在自己擅长的领域里(快速开发、入门学习、轻量任务)就是最佳选择。
如果你想真正掌握 BeautifulSoup,而不是仅仅停留在“会几个 API”的阶段,建议你遵循这个学习路径:
find()、find_all()、select() 这几个核心方法,确保概念清晰。requests.get() 随便抓一个结构简单的静态网页下来。你会发现,真正的核心能力不在于背了多少 API,而在于:
看到一个网页,能快速判断它属于哪种结构,从哪里切入提取数据最省事。
BeautifulSoup 是 Python 生态里非常经典、也非常适合新手入门的网页解析库。它最大的价值不在于语法多高级,而在于它把“从网页里提取信息”这件事变得直观了太多。
最后,再帮大家回顾一下这套组合最核心的分工:
requests:负责“下载”网页。BeautifulSoup:负责“拆解”网页。如果你正在学习 Python,又希望尽快做出一些能解决实际问题的“小玩具”来提升成就感,那么 BeautifulSoup 绝对值得你亲手敲一遍。先从本地 HTML 开始,跑通选择器,再去挑战真实的网页,你的进步会快很多。
Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。
极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。