Python凭借简洁的语法和丰富的第三方库生态,成为编写网络爬虫的首选语言。所谓爬虫,本质上就是模拟浏览器向服务器发送HTTP请求,获取返回的HTML页面,再从中提取出我们需要的数据。整个过程可以拆解为三个步骤:请求网页、解析内容、保存数据。本文将围绕这三步展开,从最基础的requests加BeautifulSoup组合讲起,逐步深入到动态页面抓取与反爬应对,带你完整走一遍Python爬取网站数据的流程。

一、环境准备与爬虫基本原理
在写代码之前,先要理解爬虫的工作原理。当我们在浏览器里打开一个网页时,浏览器向服务器发送了一个HTTP请求,服务器返回HTML文档,浏览器再将其渲染成我们看到的页面。爬虫做的事情和浏览器类似,只是不渲染页面,而是直接分析返回的HTML源码,从中定位并抽取目标数据。
环境准备非常简单,只需要安装两个核心库:requests负责发送网络请求,BeautifulSoup负责解析HTML。在命令行执行以下命令即可完成安装:
pip install requests pip install beautifulsoup4 pip install lxml
这里额外安装了lxml,它是C语言实现的解析器,速度比Python自带的html.parser快很多,BeautifulSoup可以指定使用它。装好这三样,一个基础的爬虫环境就搭建完成了。
二、用requests获取网页源码
requests是Python中最流行的HTTP库,几行代码就能拿到网页源码。下面是一个最简单的例子:
import requests
url = "https://ipipp.com/news"
# 设置请求头,伪装成浏览器访问
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
}
response = requests.get(url, headers=headers, timeout=10)
# 指定编码,避免中文乱码
response.encoding = "utf-8"
if response.status_code == 200:
html = response.text
print(html[:500])
else:
print("请求失败,状态码:", response.status_code)这段代码有几个关键点。第一是User-Agent请求头,很多网站会检查这个字段,如果没有设置或者值是Python默认的,服务器可能直接拒绝返回内容,所以伪装成浏览器是爬虫的基本操作。第二是timeout参数,设置超时时间可以避免程序在网络异常时无限等待。第三是response.encoding,部分网站编码不是UTF-8,不手动指定容易出现中文乱码,可以通过response.apparent_encoding自动检测编码。
如果目标数据是通过POST请求提交的,比如登录表单或查询接口,则改用requests.post(),把参数放在data字典中传入。对于需要保持登录状态的场景,可以使用requests.Session(),它会自动保存并携带Cookie,模拟一个持续的会话过程。
三、用BeautifulSoup解析和提取数据
拿到HTML源码后,下一步就是解析。BeautifulSoup提供了非常友好的API,支持按标签名、class、id、CSS选择器等多种方式定位元素。下面的例子演示了如何提取一个新闻列表页的标题和链接:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "lxml")
# 方式一:find_all查找所有class为news-item的div
items = soup.find_all("div", class_="news-item")
for item in items:
title = item.find("h2").get_text(strip=True)
link = item.find("a").get("href")
print(title, link)
# 方式二:CSS选择器,写法更接近前端习惯
for a in soup.select("div.news-list ul li a.title"):
print(a.get_text(strip=True), a["href"])
# 获取标签属性和文本
first = soup.find("a")
print(first["href"]) # 等价于 first.get("href")
print(first.get_text()) # 获取标签内所有文字BeautifulSoup的find返回第一个匹配的节点,find_all返回所有匹配节点的列表,select则支持完整的CSS选择器语法。对于属性,用get()或字典取值;对于文本内容,用get_text()并加上strip=True去掉多余空白。
除了BeautifulSoup,常用的解析方式还有XPath和正则表达式。XPath配合lxml库使用,表达式灵活,适合复杂的层级定位;正则表达式则适合提取结构不规则的碎片信息,比如页面里嵌套的JSON数据。三者对比:BeautifulSoup上手最容易,XPath定位能力强,正则最通用但可读性差。实际项目中经常混用,比如用BeautifulSoup定位到大区块,再用正则抽数据细节。
四、处理分页、动态页面与反爬机制
真实网站的爬取往往没这么顺利,会遇到分页、动态加载和反爬三类问题。对于分页,最直接的办法是观察URL规律,比如第二页是?page=2,第三页是?page=3,然后用循环构造URL批量抓取,每次请求之间加time.sleep()控制频率,既减轻服务器压力,也降低被封的风险。
对于JavaScript动态渲染的页面,requests拿到的源码里可能没有目标数据,因为数据是浏览器执行JS后才插入的。这种情况有两种解决思路:一是打开浏览器开发者工具的Network面板,找到页面背后真正返回数据的XHR或Fetch接口,直接请求该接口,通常拿到的是干净的JSON数据,这是效率最高的方式;二是使用Selenium或Playwright驱动真实浏览器渲染页面,再提取渲染后的HTML,适合接口加密严重的场景,缺点是速度慢、资源占用高。
反爬机制方面,常见的有IP频率限制、验证码、Cookie校验等。应对策略包括:使用代理IP池轮换出口IP、随机更换User-Agent、控制请求频率、带上完整的请求头等。但更重要的是遵守爬虫礼仪:查看网站根目录下的robots.txt协议,不抓取明确禁止的内容,不高频请求影响网站正常运行,不抓取和传播涉及个人隐私的数据。爬虫技术本身是中性的,合规使用才能走得长远。
五、完整实战:爬取并保存数据到CSV
最后把前面的知识点串起来,写一个完整的小爬虫,抓取列表数据并保存为CSV文件,方便后续用Excel或pandas分析:
import csv
import time
import requests
from bs4 import BeautifulSoup
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
results = []
for page in range(1, 6): # 抓取前5页
url = f"https://ipipp.com/news?page={page}"
resp = requests.get(url, headers=headers, timeout=10)
resp.encoding = "utf-8"
soup = BeautifulSoup(resp.text, "lxml")
for item in soup.select("div.news-item"):
title = item.select_one("h2").get_text(strip=True)
link = item.select_one("a").get("href", "")
results.append([title, link])
time.sleep(2) # 每页间隔2秒,控制请求频率
# 写入CSV文件
with open("news.csv", "w", newline="", encoding="utf-8-sig") as f:
writer = csv.writer(f)
writer.writerow(["标题", "链接"])
writer.writerows(results)
print(f"共抓取 {len(results)} 条数据,已保存到 news.csv")这个例子体现了爬虫的标准结构:构造URL循环、请求、解析、汇总、持久化。编码写成utf-8-sig是为了让Excel正确识别中文。如果数据量大,还可以换用pandas的to_csv,或者存入SQLite、MySQL数据库。掌握了这套流程后,无论是商品价格监控、新闻聚合还是数据统计分析,都可以用同样的套路去实现,剩下要做的只是针对不同网站调整解析规则和应对策略。
python爬虫requestsBeautifulSoup修改时间:2026-08-31 01:12:45