1 pip —— 第三方库的「安装管家」
是什么?为什么学?
pip 是 Python 自带的包管理工具,从 PyPI(Python Package Index,Python 官方软件仓库,全球开发者共享代码的地方)下载并安装第三方库。标准库之外的好东西——网页请求、数据分析、图像处理——几乎都靠 pip install 装进环境。标准库是「自带工具箱」,而第三方库是全世界开发者分享的「超级工具箱」。
底层原理
pip install requests 做的事情:① 在 PyPI 仓库里查找名为 requests 的包(同时解析它的依赖,比如它依赖的 urllib3、certifi);② 下载对应你 Python 版本的文件(通常是 .whl 轮子格式,即预编译好的安装包);③ 解压到当前环境的 site-packages 目录。关键点:pip 装到「哪个环境」,取决于你用哪个 python 命令——所以稳妥写法是 python -m pip(用当前 python 解释器去调 pip,保证装进同一个环境)。
生活类比
pip 像手机应用商店:PyPI 是商店,pip install 是「点击安装」,pip list 是「已装应用列表」,pip uninstall 是「卸载」。python -m pip 相当于「先确认是这台手机再安装」——避免装错设备。
注意事项总结
1 查看 pip 版本与已安装列表:
python -m pip --version
python -m pip list
运行结果(版本号以实际为准):
pip 25.3 from C:\...\site-packages\pip (python 3.14)
Package Version
------------- ---------
beautifulsoup4 4.15.0 / requests 2.34.2
python -m pip --version 打印 pip 版本(**python -m 保证用的是当前解释器**);pip list 列出当前环境所有已装包。
2 安装 / 查看详情 / 卸载:
python -m pip install requests beautifulsoup4 # 安装
python -m pip show requests # 查看详情
python -m pip uninstall requests # 卸载(会二次确认)
运行结果(安装成功的典型输出片段):
Collecting requests ... Successfully installed requests-2.32.3
3 国内网络慢加镜像源:python -m pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple。
易错点
- 错误写法:直接敲
pip install requests→ 问题:多个 Python 时可能装进别的版本,import依然报错 → 正确写法:用python -m pip install绑定当前解释器。 - 错误写法:
import requests报ModuleNotFoundError却不去装 → 问题:第三方库必须显式安装,不像标准库自带 → 正确写法:先python -m pip install requests。
记忆口诀:pip 是管家,PyPI 是仓库;python -m pip 最稳妥,装完 import 才不慌。
2 虚拟环境 venv —— 每个项目一个「独立房间」
是什么?为什么学?
虚拟环境(virtual environment)是 Python 为每个项目创建的一套独立隔离的解释器 + 库目录。项目 A 需要 requests 2.x、项目 B 需要 requests 1.x,全装全局会互相打架;虚拟环境让每个项目有自己的库,互不影响。团队开发、部署上线时,这是标准操作。
底层原理
python -m venv venv 在当前目录生成 venv 文件夹:一份解释器入口(Windows 是 venv\Scripts\python.exe)+ 独立的 site-packages 目录。激活(venv\Scripts\activate)的本质是修改环境变量 PATH,让 python / pip 优先指向这个文件夹;退出(deactivate)则恢复 PATH。隔离的真相:路径指向不同,装的库各归各家。
生活类比
虚拟环境像酒店房间:每个项目住一间,房内物品(依赖库)只属于这间房;退房(deactivate)后互不影响。全局环境像大宿舍,谁都能往里放东西,互相串味。
注意事项总结
1 创建 + 激活 + 退出:
python -m venv venv # 1. 创建虚拟环境(生成 venv 文件夹)
venv\Scripts\activate # 2. 激活(Windows;macOS/Linux 用 source venv/bin/activate)
pip list # 3. 激活后看到的是这个环境自己的包
deactivate # 4. 退出环境
运行效果(激活后提示符前出现 (venv)):
(venv) C:\project> pip list
Package Version
--------- -------
pip 25.3
python -m venv venv 创建隔离环境(只需一次);venv\Scripts\activate 激活后,**提示符前面出现 (venv)**,此时 pip install 装的库只属于这个项目;deactivate 退出回到全局。
2 不激活也能用——直接调 venv 里的 python:
venv\Scripts\python.exe -m pip --version
运行结果:pip 25.3 from C:\project\venv\Lib\site-packages\pip (python 3.14)
注意路径里的 venv\Lib\site-packages——这个 pip 属于 venv 自己的目录。不激活时,直接用 venv\Scripts\python.exe 也能享受隔离环境,脚本自动化(定时任务)常用这招。
易错点
- 错误写法:忘激活就直接
pip install→ 问题:装进了全局环境,项目里 import 不到 → 正确写法:先venv\Scripts\activate看到(venv)再装。 - 错误写法:把
venv文件夹提交到 git / 发给别人 → 问题:体积大且含本机绝对路径,换电脑就废 → 正确写法:只提交requirements.txt,别人pip install -r重建。
记忆口诀:一个项目一间房,venv 建好再装库;提示符带 (venv),deactivate 退房。
3 requests —— 用几行代码「访问」网页
是什么?为什么学?
requests 是 Python 最流行的 HTTP 请求库,封装了网络协议细节,让「访问一个网址」变成一行 requests.get(url)。抓网页、调 API(天气、地图、翻译接口)都是发 HTTP 请求,requests 是标配。自己用标准库 urllib 写要处理编码、重定向、超时等一堆细节,requests 全部代劳。
底层原理
requests.get(url) 内部发一次 HTTP GET 请求:建立连接(基于 urllib3)→ 发送请求头 → 服务器返回响应 → 封装成 Response 对象。对象里有:status_code(200 成功、404 不存在、403 拒绝)、text(网页文本)、headers(响应头)、encoding(编码)。关键点:网络请求可能失败(断网、超时、被反爬),要用 try/except 包住,别让程序因一次网络抖动崩溃。
生活类比
requests 像打电话:requests.get(url) 是「拨号 + 问一句话」,Response 是「对方答复」——先听语气(200 是「好的」,404 是「没这人」),再听内容(resp.text)。
注意事项总结
1 请求网页,看状态码和内容(需要联网):
import requests
resp = requests.get("https://example.com")
print("状态码:", resp.status_code)
print("编码:", resp.encoding)
print("网页文本前 120 字符:")
print(resp.text[:120])
示例输出(联网运行时):
状态码: 200
编码: ISO-8859-1
网页文本前 120 字符: <!doctype html><html lang="en"><head><title>Example Domain...
requests.get(...) 发请求返回响应对象;resp.status_code 判断成功与否;resp.text[:120] 取网页源码前 120 字符——这就是 HTML 字符串,下一步交给 BeautifulSoup 解析。
2 带浏览器标识 + 异常处理(断网也不崩溃)(需要联网):
import requests
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
try:
resp = requests.get("https://example.com", headers=headers, timeout=10)
resp.raise_for_status() # 状态码非 200 时抛出异常
print("请求成功,状态码:", resp.status_code)
except requests.RequestException as e:
print("请求失败:", e)
headers 带上浏览器标识(User-Agent)减少被拒概率;timeout=10 设超时防止无限等待;raise_for_status() 在状态码非 200 时抛异常;except requests.RequestException 接住所有请求类异常(断网、超时、404 都算)——网络不可控,必须兜底。
3 中文乱码先查编码:resp.encoding = "utf-8" 或 resp.encoding = resp.apparent_encoding(自动推断)。
易错点
- 错误写法:不写
timeout→ 问题:服务器不响应时程序无限卡住 → 正确写法:requests.get(url, timeout=10)。 - 错误写法:不写
try/except→ 问题:断网或超时直接抛异常崩溃 → 正确写法:用except requests.RequestException兜底。 - 错误写法:URL 忘了
https://→ 问题:报InvalidURL/MissingSchema→ 正确写法:URL 写全:https://example.com。
记忆口诀:get 是打电话,resp 是答复;200 是成功,404 没人接;超时兜底别忘 try。
4 BeautifulSoup —— 把 HTML 变成「对象树」
是什么?为什么学?
beautifulsoup4(bs4)是解析 HTML/XML 的库。网页源码是一大坨字符串,直接 find / 切片提取非常痛苦;BeautifulSoup 把 HTML 解析成一棵树(标签嵌套结构),然后就能用「找标签」的方式取内容。配合 requests 就是完整的「抓取 + 解析」链路。
底层原理
BeautifulSoup(html, "html.parser") 用解析器把 HTML 字符串变成一棵对象树:每个标签是一个 Tag 对象,标签之间是父子/兄弟关系。然后:soup.h1 取第一个 h1、soup.find("p", class_="temp") 按标签 + 属性找、soup.find_all("a") 找所有 a、tag.text 取文本、tag["href"] 取属性、soup.select(".news h2") 用 CSS 选择器。**注意 class 是 Python 关键字,所以用 class_**。
生活类比
BeautifulSoup 像档案管理员:HTML 是一堆杂乱的纸(字符串),管理员按目录整理成档案柜(对象树)——找「所有标题」查 find_all("h2"),找「正文第一段」查 find("p"),几秒搞定。
注意事项总结
1 解析本地 HTML 字符串,提取标题/段落/链接(离线可跑):
from bs4 import BeautifulSoup
html = """
<html><body>
<h1>今日天气</h1>
<p class="temp">28 度</p>
<p class="desc">多云转晴</p>
<a href="/detail">查看详情</a>
</body></html>
"""
soup = BeautifulSoup(html, "html.parser")
print("h1 文本:", soup.h1.text)
print("temp:", soup.find("p", class_="temp").text)
print("链接:", soup.a["href"], "|", soup.a.text)
运行结果(离线可复现):
h1 文本: 今日天气
temp: 28 度
链接: /detail | 查看详情
BeautifulSoup(html, "html.parser") 把字符串解析成对象树;soup.h1.text 取第一个 h1 的文本;soup.find("p", class_="temp") 按标签和 class 找(**class_ 带下划线**);soup.a["href"] 取 a 的 href 属性。
2 find_all 批量提取 + CSS 选择器 + 嵌套表格(离线可跑):
from bs4 import BeautifulSoup
html = """
<ul>
<li>苹果</li>
<li>香蕉</li>
<li>梨</li>
</ul>
<table>
<tr><th>水果</th><th>价格</th></tr>
<tr><td>苹果</td><td>5.5</td></tr>
<tr><td>香蕉</td><td>3.0</td></tr>
</table>
"""
soup = BeautifulSoup(html, "html.parser")
items = [li.text for li in soup.find_all("li")] # 列表推导式批量取文本
print("水果:", items)
rows = []
for tr in soup.find_all("tr")[1:]: # 跳过表头行
rows.append([td.text for td in tr.find_all("td")])
print("表格:", rows)
print("CSS 选择器:", [h.text for h in soup.select("th")])
运行结果(离线可复现):
水果: ['苹果', '香蕉', '梨']
表格: [['苹果', '5.5'], ['香蕉', '3.0']]
CSS 选择器: ['水果', '价格']
soup.find_all("li") 配合列表推导式一次取全部文本——「批量提取」就是 find_all + 推导式;soup.find_all("tr")[1:] 跳过表头再逐行取 td,这是解析表格的标准套路(先取行再取格)。
3 requests + bs4 组合——完整「抓取 + 解析」链路(需要联网):
import requests
from bs4 import BeautifulSoup
resp = requests.get("https://example.com")
soup = BeautifulSoup(resp.text, "html.parser")
print("页面标题:", soup.title.string)
for a in soup.find_all("a"):
print(" ", a.get("href"), "->", a.text)
易错点
- 错误写法:
soup.find("p", class="temp")→ 问题:class是 Python 关键字,语法报错 → 正确写法:用class_="temp"。 - 错误写法:
soup.find(...)没找到就直接.text→ 问题:返回None,None.text报AttributeError→ 正确写法:先判断if tag is not None:。 - 错误写法:忘了
html.parser参数:BeautifulSoup(html)→ 问题:告警「未指定解析器」,行为不确定 → 正确写法:显式写BeautifulSoup(html, "html.parser")。
记忆口诀:BeautifulSoup 建档案,find 一个 find_all 一堆;class 加下划线,text 取文本,None 要先判断。
5 动手实践:请求并解析一个网页
做一个「网页信息提取器」:请求 example.com,提取标题、正文第一段、所有链接,并把链接整理后打印出来。
# page_parser.py —— 请求并解析一个网页
import requests
from bs4 import BeautifulSoup
def fetch_page(url):
"""请求网页,返回 BeautifulSoup 对象;失败返回 None"""
try:
resp = requests.get(url, timeout=10)
resp.raise_for_status() # 状态码非 200 时抛异常
resp.encoding = "utf-8"
return BeautifulSoup(resp.text, "html.parser")
except requests.RequestException as e:
print("请求失败:", e)
return None
def show_page_info(url):
soup = fetch_page(url)
if soup is None:
return
print("=== 页面标题 ===")
print(soup.title.string if soup.title else "(无标题)")
print("\n=== 正文第一段 ===")
p = soup.find("p")
print(p.text if p else "(无段落)")
print("\n=== 页面里的链接 ===")
links = soup.find_all("a")
for i, a in enumerate(links, 1):
href = a.get("href")
text = a.text.strip()
print(f"{i}. {href} -> {text}")
print(f"\n共找到 {len(links)} 个链接")
if __name__ == "__main__":
show_page_info("https://example.com")
示例输出(需要联网运行;页面内容如有微调不影响理解结构):
=== 页面标题 ===
Example Domain
=== 正文第一段 ===
This domain is for use in documentation examples without needing permission.
=== 页面里的链接 ===
1. https://iana.org/domains/example -> Learn more
共找到 1 个链接
example.com 是 IANA 提供的稳定测试页面,内容几乎不变,最适合拿来练习。
升级挑战:把提取结果保存到 page_info.txt 文件(用到 Day 13 学的文件写入);再试试请求一个你常逛的公开网页,把标题和所有链接提取出来。注意别频繁请求别人网站,练习用 example.com 最合适。
今日总结
python -m pip install 装库,pip list / show / uninstall 管理,镜像源加速;python -m pip 最稳妥
虚拟环境:python -m venv venv + 激活((venv) 提示符)+ deactivate,项目独立房间
requests.get() 返回 Response:status_code / text / encoding / headers
网络三件套:headers 带 User-Agent、timeout 设超时、try/except 兜底
BeautifulSoup 对象树:soup.h1 / find / find_all / tag.text / tag["href"] / select
解析套路:批量提取 = find_all + 推导式;表格 = 先取行再取格;完整链路 = requests 抓 → bs4 解析
区分联网示例与离线示例:解析类用本地 HTML 字符串离线跑,抓取类才需联网
| 报错 | 原因 | 修复 |
|---|---|---|
ModuleNotFoundError: No module named 'requests' | 库没安装,或装到了别的环境 | 先 pip install requests beautifulsoup4,并确认在正确的虚拟环境里 |
requests.exceptions.ConnectionError | 网络不通或网址拼错 | 检查网络,确认 URL 完整(含 https://) |
404 Client Error / 403 Client Error | 页面不存在,或服务器拒绝访问 | 检查 URL;加上 headers={"User-Agent": "Mozilla/5.0 ..."} 再试 |
ValueError: Invalid URL | URL 写错了 | 补全协议头,如 https://example.com |
AttributeError: 'NoneType' object has no attribute 'text' | find / soup.a 没找到元素,返回了 None | 先判断 if tag is not None,或改用 find_all 确认选择器是否正确 |
| 页面中文乱码 | 编码判断错误 | 设置 resp.encoding = "utf-8" 或 resp.encoding = resp.apparent_encoding |