Python原生请求库:urllib完全指南
什么是urllib?
urllib是Python标准库中的HTTP客户端模块,提供了一系列用于处理URL和进行网络请求的模块。它是Python内置的HTTP请求解决方案,无需安装第三方库即可使用。urllib包含以下几个子模块:
urllib.request
- 打开和读取URLurllib.error
- 包含urllib.request引发的异常urllib.parse
- 解析URLurllib.robotparser
- 解析robots.txt文件
为什么使用urllib?
优势 | 说明 |
---|---|
无需安装 | Python标准库内置,开箱即用 |
轻量级 | 不依赖第三方库,体积小 |
功能全面 | 支持HTTP/HTTPS、FTP等多种协议 |
学习价值 | 理解HTTP请求底层原理 |
兼容性好 | 支持所有Python环境 |
基本HTTP请求
GET请求示例
from urllib.request import urlopen
# 基本GET请求
with urlopen('https://httpbin.org/get') as response:
print(response.status) # 200
print(response.read().decode('utf-8')) # 响应内容
代码解释:
urlopen()
是最简单的发起请求的方法- 返回的对象类似文件对象,可以使用
read()
方法读取内容 - 需要手动解码响应内容(通常为UTF-8)
- 使用
with
语句确保连接正确关闭
带参数的GET请求
from urllib.request import urlopen
from urllib.parse import urlencode
# 构造查询参数
params = {'key1': 'value1', 'key2': 'value2'}
query_string = urlencode(params)
url = f'https://httpbin.org/get?{query_string}'
# 发送请求
with urlopen(url) as response:
print(response.url) # 完整URL
print(response.read().decode('utf-8'))
代码解释:
urlencode()
将字典转换为URL查询字符串- 手动拼接URL和查询参数
- 适用于简单的GET请求
POST请求
表单数据POST
from urllib.request import Request, urlopen
from urllib.parse import urlencode
# 准备表单数据
data = urlencode({'key1': 'value1', 'key2': 'value2'}).encode('utf-8')
# 创建请求对象
request = Request(
url='https://httpbin.org/post',
data=data,
method='POST'
)
# 发送请求
with urlopen(request) as response:
print(response.status) # 200
print(response.read().decode('utf-8'))
代码解释:
Request
类提供更灵活的请求配置- POST数据需要编码为bytes类型
- 设置
method
参数为’POST’ - 表单数据使用
urlencode
编码
JSON数据POST
from urllib.request import Request, urlopen
import json
# 准备JSON数据
data = json.dumps({'name': 'John', 'age': 30}).encode('utf-8')
# 创建请求对象并设置头部
request = Request(
url='https://httpbin.org/post',
data=data,
method='POST',
headers={'Content-Type': 'application/json'}
)
# 发送请求
with urlopen(request) as response:
print(response.read().decode('utf-8'))
代码解释:
- 使用
json.dumps()
将字典转换为JSON字符串 - 必须设置
Content-Type
为application/json
- 数据同样需要编码为bytes类型
高级功能
设置请求头
from urllib.request import Request, urlopen
# 自定义请求头
headers = {
'User-Agent': 'Mozilla/5.0',
'Accept': 'application/json',
'X-Custom-Header': 'Value'
}
request = Request(
url='https://httpbin.org/headers',
headers=headers
)
with urlopen(request) as response:
print(response.read().decode('utf-8'))
代码解释:
- 通过
headers
参数设置自定义请求头 User-Agent
可以伪装成浏览器访问- 服务端可以通过请求头返回不同内容
处理Cookies
from urllib.request import Request, urlopen, build_opener, HTTPCookieProcessor
from http.cookiejar import CookieJar
# 创建Cookie处理器
cookie_jar = CookieJar()
opener = build_opener(HTTPCookieProcessor(cookie_jar))
# 发送请求(自动处理Cookies)
request = Request('https://httpbin.org/cookies/set/sessioncookie/123456789')
response = opener.open(request)
# 查看Cookies
print([cookie.name for cookie in cookie_jar])
代码解释:
CookieJar
用于存储CookiesHTTPCookieProcessor
自动处理Cookiesbuild_opener
创建自定义opener- 适用于需要保持会话的场景
设置代理
from urllib.request import ProxyHandler, build_opener
# 设置代理
proxy_handler = ProxyHandler({
'http': 'http://proxy.example.com:8080',
'https': 'https://proxy.example.com:8080'
})
opener = build_opener(proxy_handler)
# 使用代理发送请求
response = opener.open('http://httpbin.org/ip')
print(response.read().decode('utf-8'))
代码解释:
ProxyHandler
配置代理服务器- 支持HTTP和HTTPS代理
- 需要构建自定义opener使用代理
错误处理
常见异常
异常 | 描述 |
---|---|
URLError | URL相关错误的基类 |
HTTPError | HTTP错误响应(如404, 500) |
ContentTooShortError | 下载内容不完整 |
错误处理示例
from urllib.request import urlopen
from urllib.error import URLError, HTTPError
try:
response = urlopen('https://example.com/nonexistent')
print(response.read().decode('utf-8'))
except HTTPError as e:
print(f'HTTP错误: {e.code} {e.reason}')
except URLError as e:
print(f'URL错误: {e.reason}')
except Exception as e:
print(f'其他错误: {e}')
代码解释:
HTTPError
处理HTTP状态码错误URLError
处理网络连接等问题- 建议对不同类型错误分别处理
实用工具
URL解析
from urllib.parse import urlparse, urlunparse, urljoin
# 解析URL
result = urlparse('https://example.com/path;params?query=arg#frag')
print(result.scheme) # https
print(result.netloc) # example.com
print(result.path) # /path
print(result.params) # params
print(result.query) # query=arg
print(result.fragment) # frag
# 拼接URL
print(urljoin('https://example.com/path', 'subpath')) # https://example.com/subpath
代码解释:
urlparse
分解URL为6个组成部分urlunparse
执行反向操作urljoin
智能拼接URL
编码与解码
from urllib.parse import quote, unquote, quote_plus, unquote_plus
# URL编码
print(quote('上海')) # %E4%B8%8A%E6%B5%B7
print(quote_plus('a b')) # a+b
# URL解码
print(unquote('%E4%B8%8A%E6%B5%B7')) # 上海
print(unquote_plus('a+b')) # a b
代码解释:
quote
对URL进行编码quote_plus
用+代替空格unquote
和unquote_plus
执行反向操作
性能优化
复用连接
from urllib.request import OpenerDirector, HTTPHandler
# 创建自定义opener
opener = OpenerDirector()
opener.add_handler(HTTPHandler())
# 复用连接发送多个请求
for i in range(3):
with opener.open('https://httpbin.org/get') as response:
print(f'请求{i+1}:', response.status)
代码解释:
OpenerDirector
管理多个处理器HTTPHandler
处理HTTP请求- 复用opener可以保持连接
总结
Python的urllib模块提供了完整的HTTP客户端功能,虽然不如第三方库如Requests简洁,但在以下场景特别有用:
- 无第三方依赖:受限环境无法安装第三方库
- 学习HTTP原理:理解底层HTTP通信机制
- 轻量级需求:简单请求不想引入额外依赖
- 标准库兼容:确保代码在所有Python环境运行
关键要点
urlopen
适合简单请求Request
类提供更多控制- 使用
urllib.parse
处理URL - 自定义
OpenerDirector
实现高级功能 - 注意错误处理和资源清理
与Requests对比
特性 | urllib | Requests |
---|---|---|
安装 | 内置 | 需安装 |
易用性 | 较低 | 高 |
功能 | 基础 | 丰富 |
性能 | 较好 | 优秀 |
社区支持 | 一般 | 强大 |
进一步学习
- 官方文档:https://docs.python.org/3/library/urllib.html
- 进阶教程:https://docs.python.org/3/howto/urllib2.html
- 最佳实践:https://realpython.com/python-urllib-request/