pin_drop当前位置:知识文库 ❯ 图文

Python urllib详解 - HTTP请求标准库实战教程

一、urllib 概述

urllib 是 Python 标准库中用于处理 URL 的模块集合。它是 Python 内置的 HTTP 客户端,无需额外安装任何第三方包即可发起网络请求。

urllib 包含多个子模块:

  • urllib.request:用于打开和读取 URL

  • urllib.parse:用于解析 URL

  • urllib.error:包含请求可能抛出的异常

  • urllib.robotparser:用于解析 robots.txt 文件

小贴士

虽然 requests 库在第三方库中更为流行,但 urllib 作为标准库无需安装,在一些受限环境(如无法使用 pip 的服务器)中非常有用。Python 3 中将 urllib2 合并到了 urllib 模块中。

二、urlopen 基本用法

最简单的 GET 请求

urllib.request.urlopen() 是发起 HTTP 请求的核心函数,它支持 URL 字符串或 Request 对象作为参数:

代码示例

from urllib.request import urlopen

# 最简单的 GET 请求
response = urlopen('https://httpbin.org/get')

# 读取响应内容(返回 bytes)
html = response.read()
print(html.decode('utf-8'))

# 查看状态码
print(f'状态码: {response.status}')

# 查看响应头
print(f'Content-Type: {response.headers["Content-Type"]}')

# 关闭响应
response.close()

使用 with 语句管理响应

代码示例

from urllib.request import urlopen

# 推荐:使用 with 语句自动关闭响应
with urlopen('https://httpbin.org/get') as response:
    data = response.read()
    print(f'状态码: {response.status}')
    print(data.decode('utf-8'))

读取响应内容

代码示例

from urllib.request import urlopen
import json

with urlopen('https://httpbin.org/get') as response:
    # 方式1:一次性读取全部内容
    all_content = response.read()
    
    # 方式2:逐行读取
    response2 = urlopen('https://httpbin.org/get')
    for line in response2:
        print(line.decode('utf-8').strip())
    response2.close()
    
    # 方式3:读取指定字节数
    response3 = urlopen('https://httpbin.org/get')
    chunk = response3.read(1024)  # 只读取前 1024 字节
    response3.close()
    
    # 解析 JSON 响应
    response4 = urlopen('https://httpbin.org/get')
    json_data = json.loads(response4.read().decode('utf-8'))
    print(json_data['url'])
    response4.close()

设置超时时间

代码示例

from urllib.request import urlopen
import socket

# 设置超时时间为 10 秒
try:
    response = urlopen('https://httpbin.org/delay/5', timeout=10)
    print(response.read().decode('utf-8'))
except socket.timeout:
    print('请求超时!')

三、Request 对象

当需要自定义请求头、请求方法或传递数据时,应使用urllib.request.Request对象:

代码示例

from urllib.request import Request, urlopen

# 创建 Request 对象
url = 'https://httpbin.org/get'
req = Request(url)

# 发送请求
with urlopen(req) as response:
    print(response.read().decode('utf-8'))

使用 parse.urlencode 构建查询参数

代码示例

from urllib.request import urlopen
from urllib.parse import urlencode

# 构建查询参数
params = {
    'q': 'Python教程',
    'page': 1,
    'type': 'article'
}

# urlencode 将字典转换为 URL 编码的查询字符串
# 结果:q=Python%E6%95%99%E7%A8%8B&page=1&type=article
query_string = urlencode(params)

url = f'https://httpbin.org/get?{query_string}'
print(f'完整URL: {url}')

with urlopen(url) as response:
    data = response.read().decode('utf-8')
    print(data)

四、添加请求头

许多网站会检查请求头来判断是否为浏览器请求。通过设置 User-Agent 等请求头可以模拟浏览器访问:

代码示例

from urllib.request import Request, urlopen

url = 'https://httpbin.org/headers'

# 创建请求并添加请求头
req = Request(url)
req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')
req.add_header('Accept', 'application/json')
req.add_header('Accept-Language', 'zh-CN,zh;q=0.9')

# 或者在创建时直接指定 headers 参数
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
    'Accept': 'application/json',
    'Referer': 'https://www.example.com/'
}
req2 = Request(url, headers=headers)

with urlopen(req2) as response:
    print(response.read().decode('utf-8'))

动态添加/修改请求头

代码示例

from urllib.request import Request, urlopen

req = Request('https://httpbin.org/headers')

# 添加请求头
req.add_header('X-Custom-Header', 'MyValue')

# 查看已设置的请求头
print(req.headers)

# 修改 User-Agent
req.add_header('User-Agent', 'MyApp/1.0')

with urlopen(req) as response:
    print(response.read().decode('utf-8'))

五、POST 请求

发送表单数据

发起 POST 请求时,需要将数据编码为字节串并传递给 Request 对象的data参数:

代码示例

from urllib.request import Request, urlopen
from urllib.parse import urlencode

url = 'https://httpbin.org/post'

# 表单数据
form_data = {
    'username': 'test_user',
    'password': 'secret123',
    'action': 'login'
}

# 将字典编码为 application/x-www-form-urlencoded 格式
encoded_data = urlencode(form_data).encode('utf-8')

# 创建 POST 请求(传入 data 参数即为 POST)
req = Request(url, data=encoded_data)

# 发送请求
with urlopen(req) as response:
    result = response.read().decode('utf-8')
    print(result)

发送 JSON 数据

代码示例

from urllib.request import Request, urlopen
import json

url = 'https://httpbin.org/post'

# JSON 数据
json_data = {
    'name': '张三',
    'age': 28,
    'email': 'zhangsan@example.com'
}

# 将 JSON 数据编码为字节串
json_bytes = json.dumps(json_data).encode('utf-8')

# 创建请求并设置 Content-Type
req = Request(
    url,
    data=json_bytes,
    headers={
        'Content-Type': 'application/json',
        'User-Agent': 'Mozilla/5.0'
    }
)

with urlopen(req) as response:
    result = json.loads(response.read().decode('utf-8'))
    print(f'提交的数据: {result["json"]}')
    print(f'Content-Type: {result["headers"]["Content-Type"]}')

指定请求方法

代码示例

from urllib.request import Request, urlopen

# 使用 method 参数指定 HTTP 方法
req = Request('https://httpbin.org/delete', method='DELETE')
with urlopen(req) as response:
    print(f'DELETE 状态码: {response.status}')

# PUT 请求
put_data = b'{"key": "value"}'
req_put = Request(
    'https://httpbin.org/put',
    data=put_data,
    headers={'Content-Type': 'application/json'},
    method='PUT'
)
with urlopen(req_put) as response:
    print(f'PUT 状态码: {response.status}')

六、异常处理

网络请求过程中可能会遇到各种异常,如网络断开、服务器错误、URL 无效等。urllib 提供了完善的异常体系:

代码示例

from urllib.request import urlopen
from urllib.error import URLError, HTTPError
import socket

url = 'https://httpbin.org/status/404'

try:
    with urlopen(url, timeout=5) as response:
        print(f'状态码: {response.status}')
        print(response.read().decode('utf-8'))

except HTTPError as e:
    # HTTP 错误(4xx, 5xx)
    print(f'HTTP 错误: {e.code} - {e.reason}')
    # HTTPError 也有 read() 方法,可以读取错误响应体
    error_body = e.read().decode('utf-8')
    print(f'错误详情: {error_body}')

except URLError as e:
    # URL 错误(网络不可达、DNS 解析失败等)
    print(f'URL 错误: {e.reason}')

except socket.timeout:
    # 超时错误
    print('请求超时,请检查网络连接')

except Exception as e:
    # 其他未知错误
    print(f'未知错误: {e}')

完整封装的 GET 请求函数

代码示例

from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
import socket
import json

def safe_get(url, headers=None, timeout=10):
    """安全的 GET 请求封装"""
    try:
        req = Request(url, headers=headers or {})
        with urlopen(req, timeout=timeout) as response:
            return {
                'status': response.status,
                'headers': dict(response.headers),
                'body': response.read().decode('utf-8')
            }
    except HTTPError as e:
        return {'error': f'HTTP {e.code}: {e.reason}'}
    except URLError as e:
        return {'error': f'URL Error: {e.reason}'}
    except socket.timeout:
        return {'error': '请求超时'}
    except Exception as e:
        return {'error': str(e)}

# 使用示例
result = safe_get('https://httpbin.org/get')
if 'error' in result:
    print(f'请求失败: {result["error"]}')
else:
    print(f'请求成功,状态码: {result["status"]}')

七、urllib 与 requests 对比

urllib 和 requests 是 Python 中发起 HTTP 请求的两种常用方式。它们各有优缺点,适用于不同的场景:

对比项 urllib requests
安装方式 Python 标准库,无需安装 第三方库,需 pip install requests
API 简洁度 较繁琐,需要手动编码数据 简洁直观,一行代码完成请求
Cookie 处理 需要手动使用 http.cookiejar 自动处理,Session 对象内置
JSON 处理 需要 json.loads() 手动解析 response.json() 自动解析
连接池 无内置连接池 内置连接池,复用 TCP 连接
文件上传 需要手动构建 multipart 数据 files 参数一行搞定
适用场景 简单请求、受限环境 复杂项目、频繁请求

八、注意事项

注意1:始终设置 timeout 参数,防止程序在网络异常时永久阻塞。urlopen 默认没有超时限制。

注意2:POST 请求的 data 参数必须是 bytes 类型,使用.encode('utf-8')进行编码。

注意3:使用 with 语句管理 urlopen 返回的响应对象,确保连接正确释放。也可以显式调用response.close()

注意4:处理中文 URL 参数时,务必使用urllib.parse.urlencode()quote()进行 URL 编码,否则可能导致请求失败。

九、小结与练习题

核心要点回顾

  • urlopen:发起 HTTP 请求的核心函数,支持 GET 和 POST

  • Request 对象:用于自定义请求头、请求方法和数据

  • urlencode:将字典编码为 URL 查询字符串或表单数据

  • 异常处理:使用 HTTPError 和 URLError 捕获不同类型的错误

  • 始终设置超时:防止程序在网络异常时无限等待

练习1

编写一个函数fetch_webpage(url),使用 urllib 获取指定网页的 HTML 内容。要求:设置 User-Agent 请求头、10 秒超时,并处理可能出现的 HTTPError 和 URLError。

练习2

编写一个工具函数post_json(url, data),使用 urllib 发送 JSON 格式的 POST 请求。函数应自动设置 Content-Type 为 application/json,并返回解析后的 JSON 响应或错误信息。

常见问题

urllib 和 requests 哪个更好用?

如果项目允许安装第三方库,requests 是更好的选择,API 更简洁、功能更完善。如果无法安装第三方库(如受限服务器环境),urllib 作为标准库是唯一选择。对于简单的 GET/POST 请求,urllib 完全够用;对于复杂的会话管理、文件上传等场景,requests 更加便捷。

如何处理中文 URL 参数?

使用urllib.parse.urlencode()自动处理中文编码。例如:urlencode({'q': 'Python教程'})会返回'q=Python%E6%95%99%E7%A8%8B'

urllib 如何保持 Cookie?

需要使用http.cookiejar模块。创建 CookieJar 对象,配合urllib.request.HTTPCookieProcessor构建 opener,后续请求会自动携带 Cookie。或者使用 requests 的 Session 对象,自动管理 Cookie 更加方便。

urlopen 返回的是什么类型?

urlopen 返回一个http.client.HTTPResponse对象。它支持read()readline()readlines()等方法,以及statusheadersgeturl()等属性。read() 返回的是 bytes 类型,需要 decode() 转换为字符串。

标签: urllib HTTP请求 urlopen 网络编程 Python标准库 GET请求 POST请求

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: Python UDP编程详解 - 广播与多播实战教程 下一篇: Python requests库详解 - HTTP请求实战教程

poll相关推荐