项目二 动态网页数据采集
用 urllib 与 requests 抓取“新闻动态”“浪潮云说”页面:请求参数、请求头、编码、异常处理。
本项目学习目标
- 能用 urllib.request 发 GET 请求并读取网页
- 能用 requests 设置 params、headers、timeout、编码
- 能处理 403/404/超时/编码乱码等常见问题
- 能把网页内容保存成本地文件
本项目任务导览
动态网页数据采集
使用 Urllib 模块采集"新闻动态"、使用 Requests 库采集"浪潮云说",掌握 Python 中最常用的两类 HTTP 数据采集方式。
- 项目导言与学习目标
- 任务 2-1 使用 Urllib 模块采集"新闻动态"
- 任务 2-2 使用 Requests 库采集"浪潮云说"
- 知识拓展与实例案例(3 例)
动态网页数据采集是数据链路的起点。
本项目将通过两个任务,分别使用 Python 标准库 Urllib 与第三方库 Requests 完成网页数据的采集,实现从网页中获取新闻动态与指定平台数据的完整过程,为后续的数据解析与处理做准备。
掌握 Urllib 模块中 request、error、parse 子模块的常用方法; 掌握 Requests 库的安装与请求方法; 掌握 Response 响应对象与常用状态码; 熟悉 Requests 的高级使用(会话、上传、超时、异常、代理)。
能够使用 Urllib 完成网页数据采集; 能够使用 Requests 完成网页数据采集; 能够处理采集过程中的异常与状态码。
任务 2-1 使用 Urllib 模块采集"新闻动态"
Urllib 是 Python 标准库,无需安装即可使用,包含 request、error、parse 等子模块。
一、request 模块
request 模块用于构造和发起 HTTP 请求,是 Urllib 采集数据的核心。
用于打开一个 URL,向服务器发送请求并返回响应对象。
| 参数 | 说明 |
|---|---|
| url | 请求的 URL 地址 |
| data | 请求数据,默认为 None。设置该参数后请求方式变为 POST |
| timeout | 请求超时时间,单位为秒 |
| 方法 | 说明 |
|---|---|
| read() | 读取响应内容(字节) |
| readline() | 读取一行响应内容 |
| readlines() | 按行读取所有响应内容 |
| getcode() | 获取响应状态码 |
| geturl() | 获取请求的 URL |
| decode() | 对响应内容进行解码 |
| getheaders() | 获取响应头信息 |
用于构造一个完整的请求对象,可携带请求头、请求方法等信息。
| 参数 | 说明 |
|---|---|
| url | 请求的 URL 地址 |
| data | 请求数据,默认为 None |
| headers | 请求头信息,常用 User-Agent、accept、Accept-Encoding、Accept-Language 等 |
| origin_req_host | 请求方的主机 IP 或主机名 |
| unverifiable | 请求是否无法验证,默认为 False |
| method | 请求方法,如 GET / POST / HEAD / PUT / DELETE |
用于将 URL 指向的文件(如网页、图片、视频等)直接下载保存到本地文件。
# 将网页文件下载保存到本地
urlretrieve(url, filename)二、error 模块
用于处理请求过程中出现的异常。
| 异常类 | 说明 |
|---|---|
| URLError | URLError 的基类,由网络问题(无法连接、网络不可达等)引起。 |
| HTTPError | URLError 的子类,服务器返回错误状态码时抛出,具有 code(状态码)、reason(原因)、headers(响应头)等属性。 |
三、parse 模块
用于 URL 的解析、拼接与编码处理。
| 方法 | 说明 |
|---|---|
| urlparse() | 解析 URL,返回 6 部分:scheme(协议)、netloc(域名)、path(路径)、params(参数)、query(查询)、fragment(片段) |
| urljoin() | 拼接 URL:以第一个参数为基础,与第二个参数进行拼接 |
| quote() | 将中文等特殊字符编码为 URL 安全格式(编码) |
| unquote() | 对 URL 编码内容进行解码 |
# urlparse 解析示例:http://www.example.com/path?a=1#frag
# 结果:scheme=http, netloc=www.example.com, path=/path, query=a=1, fragment=frag四、任务实施(共 7 步)
- 打开新闻动态网页,使用浏览器开发者工具查看网页结构;
- 在 PyCharm 中新建 Python 项目与文件;
- 导入 urllib.request 模块,编写代码请求网页;
- 设置 Request 请求头(User-Agent 等)模拟浏览器;
- 调用 urlopen() 获取响应,使用 read().decode() 解码页面内容;
- 将获取到的页面数据保存到本地文件;
- 运行程序,查看采集结果并验证数据完整性。
任务 2-2 使用 Requests 库采集"浪潮云说"
Requests 是优雅、简单的 Python HTTP 请求库,比 Urllib 更易用。
一、Requests 简介及安装
Requests 是一个简单易用的第三方 HTTP 库,基于 urllib3 开发,API 设计人性化,是当前 Python 网页数据采集最常用的库之一。
- 打开 cmd 命令窗口;
- 执行 pip install requests 命令(或下载 wheel 文件安装);
- 等待依赖包自动下载安装完成;
- 进入 Python 交互式命令行,通过 import requests 验证安装。
二、HTTP 请求类型
| 请求类型 | 说明 |
|---|---|
| GET | 请求指定的页面信息,返回响应实体 |
| POST | 向指定资源提交数据进行处理(如表单提交) |
| HEAD | 类似 GET,但只返回响应头,不返回响应体 |
| PUT | 向指定资源位置上传最新内容 |
| PATCH | 对资源进行局部修改 |
| DELETE | 请求服务器删除指定资源 |
三、请求方法
get(url, params=None, **kwargs) —— 发送 GET 请求,返回 Response 对象。
| 参数 | 说明 |
|---|---|
| url | 请求的 URL |
| params | URL 中的查询参数(字典),会自动拼接到 URL 末尾 |
| **kwargs | 其他可选参数,见下表 |
| 参数 | 说明 |
|---|---|
| data | 请求体数据(表单),POST 时常用 |
| json | JSON 格式的请求体数据 |
| headers | 请求头(字典) |
| cookies | 请求携带的 Cookie |
| auth | 认证信息(如 HTTPBasicAuth) |
| files | 文件上传参数(字典) |
| timeout | 请求超时时间(秒或元组) |
| proxies | 代理设置(字典) |
| allow_redirects | 是否允许自动重定向,默认 True |
| stream | 是否流式获取响应内容,默认 False |
| verify | 是否验证 SSL 证书,默认 True |
| cert | 本地 SSL 证书路径 |
四、Response 对象常用属性
| 属性 | 说明 |
|---|---|
| status_code | 响应状态码(如 200、404) |
| text | 响应内容(字符串形式,自动解码) |
| content | 响应内容(字节形式) |
| encoding | 响应内容的编码方式 |
| apparent_encoding | 从内容中推测出的编码方式 |
| cookies | 响应中的 Cookie |
| url | 最终请求的 URL |
| headers | 响应头信息 |
# 使用示例
response = requests.get(url)
# 获取文本内容,若乱码可指定编码
response.encoding = response.apparent_encoding
print(response.text)五、常用状态码
| 状态码 | 含义 |
|---|---|
| 200 | 请求成功 |
| 301 | 永久重定向(资源已被永久移动到新 URL) |
| 400 | 客户端请求有语法错误,服务器无法理解 |
| 401 | 请求未经授权(需要认证) |
| 403 | 服务器拒绝执行请求(无权限访问) |
| 404 | 请求的资源不存在 |
| 500 | 服务器内部错误 |
| 503 | 服务器暂时不可用(过载或维护) |
六、高级使用
Session 对象可在多次请求之间保持 Cookie 等状态,适合需要登录后采集的场景。
通过 files 参数以字典形式上传文件: files = {'file': open('a.txt','rb')}
通过 timeout 参数设置等待时间,避免请求长时间挂起: timeout=(连接超时, 读取超时)
通过 verify 参数控制 SSL 证书验证;自定义证书可传 cert 参数。
通过 proxies 参数设置代理: proxies = {'http': 'http://ip:port'}
| 异常类 | 说明 |
|---|---|
| ConnectionError | 连接错误(网络问题、连接被拒绝) |
| HTTPError | HTTP 错误响应 |
| URLRequired | 缺少有效 URL |
| TooManyRedirects | 重定向次数过多 |
| ConnectTimeout | 连接服务器超时 |
| Timeout | 请求超时 |
# 异常处理示例
import requests
try:
r = requests.get(url, timeout=10)
r.raise_for_status()
print(r.text)
except requests.exceptions.Timeout:
print("请求超时")
except requests.exceptions.ConnectionError:
print("连接错误")
except requests.exceptions.HTTPError:
print("HTTP 错误")七、任务实施(共 7 步)
- 分析"浪潮云说"页面结构,确定数据所在位置;
- 安装 Requests 库并验证;
- 使用 get() 方法请求目标页面;
- 设置请求头(User-Agent)模拟浏览器访问;
- 处理响应内容(指定编码、解析文本);
- 将采集的数据保存到本地文件;
- 运行验证,检查数据完整性。
知识拓展与实例案例
课堂讲解用:3 个可运行实例 + 知识拓展卡片。
知识拓展
实例 1:urllib 伪装浏览器爬取网页并保存
目标:用 urllib 请求百度首页,设置 User-Agent 伪装浏览器,把 HTML 保存到本地文件。
# urllib_demo.py
import urllib.request
url = "https://www.baidu.com"
# 构造请求并添加请求头
req = urllib.request.Request(url)
req.add_header("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/120.0 Safari/537.36")
# 发起请求,获取响应对象
resp = urllib.request.urlopen(req, timeout=10)
html = resp.read().decode("utf-8")
# 保存到本地
with open("baidu.html", "w", encoding="utf-8") as f:
f.write(html)
print("抓取成功,HTML 长度:", len(html))
print("状态码:", resp.status)抓取成功,HTML 长度: 182413
状态码: 200| 代码 | 白话解释 |
|---|---|
| import urllib.request | 把 Python 自带的"网络请求"工具包导入进来,后面才能用它访问网页。urllib 是标准库,不需要安装。 |
| req = urllib.request.Request(url) | 把"要访问的网址"包装成一个"请求对象" req,相当于写好一张访问申请单。 |
| req.add_header("User-Agent", ...) | 给申请单加上"浏览器身份说明"。很多网站只允许浏览器访问,不加这行容易被拒绝(返回 403)。 |
| resp = urllib.request.urlopen(req, timeout=10) | 真正把申请单发出去,把网站的"回复"存进 resp。timeout=10 表示最多等 10 秒,防止网络卡住时程序一直等。 |
| html = resp.read().decode("utf-8") | 把回复的原始字节翻译成文字(按 utf-8 编码解码),得到网页源代码。 |
| with open("baidu.html", "w") as f: f.write(html) | 打开(或创建)baidu.html 文件,把网页源代码写进去保存。"with ... as" 会自动关闭文件,是推荐写法。 |
实例 2:Requests 携带参数请求接口并解析 JSON
目标:向天气接口发送 GET 请求,携带查询参数,把返回的 JSON 解析为 Python 字典并提取数据。
# requests_json.py
import requests
# 参数通过 params 传入,自动完成 URL 编码
params = {"city": "济南", "key": "your_api_key"}
resp = requests.get("https://api.example.com/weather", params=params,
timeout=10)
resp.raise_for_status() # 状态码非 200 时抛出异常
data = resp.json() # JSON 字符串 → 字典
print("城市:", data["city"])
print("温度:", data["temperature"], "℃")
print("天气:", data["weather"])城市: 济南
温度: 23
天气: 多云| 代码 | 白话解释 |
|---|---|
| import requests | 导入第三方库 requests。它不是 Python 自带的,需要先 pip install requests 安装。 |
| params = {"city": "济南", "key": "..."} | 把要传给服务器的参数装进字典:城市和密钥。Requests 会把它们自动拼到网址后面(如 ?city=济南&key=...)。 |
| resp = requests.get(url, params=params, timeout=10) | 向 url 发起 GET 请求,附带参数,返回的响应对象存进 resp。timeout=10 限时 10 秒。 |
| resp.raise_for_status() | 检查状态码:如果是 200 就什么也不做;如果不是 200(比如 404),主动抛出异常,方便我们发现问题。 |
| data = resp.json() | 把服务器返回的 JSON 字符串({"city": "济南", ...})解析成 Python 字典,之后就能用 data["城市"] 取数。 |
| print("温度:", data["temperature"]) | 从字典里按"键"取出温度值并打印。这就是"半结构化数据 → Python 数据结构"的落地。 |
实例 3:Requests 下载图片并处理异常
目标:下载一张网络图片到本地,演示异常捕获(连接错误、HTTP 错误、超时)的完整写法。
# requests_download.py
import requests
img_url = "https://www.example.com/images/logo.png"
try:
resp = requests.get(img_url, timeout=10)
resp.raise_for_status()
with open("logo.png", "wb") as f:
f.write(resp.content) # 二进制内容用 resp.content
print("图片下载成功,大小:", len(resp.content), "字节")
except requests.exceptions.ConnectionError:
print("连接错误,请检查网络")
except requests.exceptions.Timeout:
print("请求超时")
except requests.exceptions.HTTPError:
print("HTTP 错误:", resp.status_code)图片下载成功,大小: 24831 字节| 代码 | 白话解释 |
|---|---|
| img_url = "https://..." | 定义要下载的图片地址。实际项目中,这个地址往往来自上一步解析出来的 @href 或 img 的 src。 |
| try: | 开启"尝试"区域:把可能出错的代码放进来,出错时程序不会直接崩溃,而是跳到 except。 |
| resp = requests.get(img_url, timeout=10) | 请求图片地址。图片也是数据,网络请求和请求网页一样。 |
| resp.raise_for_status() | 检查状态码,非 200 主动抛异常,进入对应的 except 分支。 |
| with open("logo.png", "wb") as f: f.write(resp.content) | "wb" 表示"以二进制写入"模式打开文件(图片必须用二进制);resp.content 是图片的原始字节内容,写进文件即下载完成。 |
| except requests.exceptions.ConnectionError: | 捕获"连不上服务器"类错误:网络断了、域名解析失败等,打印提示而不是崩溃。 |
| except requests.exceptions.Timeout: | 捕获"超时"错误:10 秒没响应就进来,避免程序无限等待。 |
| except requests.exceptions.HTTPError: | 捕获"HTTP 状态码错误":比如 404 文件不存在,打印具体状态码方便排查。 |