杰瑞科技汇

Python urllib如何发送HTTP请求?

Python HTTP 请求终极指南:从零开始精通 urllib(附实战案例)

Meta 描述:

还在为 Python 发送 HTTP 请求而烦恼吗?本文是一份超详细的 Python urllib 教程,从 urllib.request 到 urllib.parse,手把手带你掌握 Python 内置 HTTP 客户端库,包含 GET/POST 请求、处理响应、处理参数、处理 Cookie 等实战案例,助你轻松应对网络爬虫和 API 调用,是 Python 程序员必备的速查宝典。

Python urllib如何发送HTTP请求?-图1
(图片来源网络,侵删)

(正文开始)

引言:为什么我们离不开 HTTP 请求?

在当今的互联网时代,几乎所有的数据和服务都通过网络进行交互,作为 Python 开发者,无论是编写网络爬虫抓取公开数据,还是调用第三方 API 集成服务,亦或是实现自动化测试,发送 HTTP 请求都是一项绕不开的核心技能。

提到 Python 的 HTTP 请求库,你可能会立刻想到 requests,它确实强大且易用,但今天,我们要回归 Python 的“原生力量”——urllib,作为 Python 标准库的一部分,urllib 无需安装,稳定可靠,深入理解它不仅能让你在无网络环境或受限环境中游刃有余,更能帮助你打下坚实网络编程基础,本文将带你全面、系统地掌握 urllib 的使用方法。


初识 urllib:Python 的“瑞士军刀”

urllib 并不是一个单一的模块,而是由几个处理 URL 的子模块组成的“工具包”,在 Python 3 中,它主要包含以下四个模块:

Python urllib如何发送HTTP请求?-图2
(图片来源网络,侵删)
  • urllib.request核心模块,用于打开和读取 URL。
  • urllib.error:包含 urllib.request 抛出的异常类。
  • urllib.parse:用于解析 URL,拆分或合并 URL 组件。
  • urllib.robotparser:用于解析 robots.txt 文件,判断网站爬取规则。

本文将重点讲解最常用的 urllib.requesturllib.parse


核心实战:urllib.request 的七十二变

urllib.request 是我们执行 HTTP 请求的主力,让我们从最简单的 GET 请求开始,逐步深入。

1 发送一个最简单的 GET 请求

想象一下,你想获取百度首页的 HTML 内容,代码非常直观:

from urllib.request import urlopen
# 目标 URL
url = 'http://www.baidu.com'
# 使用 urlopen() 打开 URL,返回一个文件类对象
response = urlopen(url)
# 读取响应内容(字节流)
html_bytes = response.read()
# 将字节流解码为字符串
html_content = html_bytes.decode('utf-8')
# 打印前 500 个字符
print(html_content[:500])
# 记得关闭响应对象,释放资源
response.close()

代码解读:

Python urllib如何发送HTTP请求?-图3
(图片来源网络,侵删)
  1. from urllib.request import urlopen:导入核心函数 urlopen
  2. urlopen(url):这是最简单的请求方式,它会发起一个 GET 请求,并返回一个 http.client.HTTPResponse 对象,我们可以像操作文件一样操作它。
  3. response.read():读取响应体的全部内容。
  4. response.close()重要! 关闭连接,这是良好的编程习惯。

更优雅的写法:使用 with 语句

为了避免忘记 close(),推荐使用 with 语句,它会在代码块执行完毕后自动关闭资源。

from urllib.request import urlopen
url = 'http://www.baidu.com'
with urlopen(url) as response:
    html_content = response.read().decode('utf-8')
print(html_content[:500])

2 获取更多响应信息

响应对象 response 不仅仅是数据的载体,它还包含了丰富的元信息,就像 HTTP 响应头一样。

from urllib.request import urlopen
url = 'http://www.baidu.com'
with urlopen(url) as response:
    print(f"状态码: {response.status}")  # HTTP 状态码,如 200
    print(f"响应头信息:")
    print(response.headers) # 输出所有响应头
    print(f"Content-Type: {response.getheader('Content-Type')}") # 获取指定响应头
    print(f"服务器信息: {response.getheader('Server')}")

通过这些信息,你可以判断请求是否成功、内容类型、编码方式等。

3 处理 URL 参数(GET 请求)

当需要向 URL 添加查询参数时,直接拼接字符串很容易出错,这时,urllib.parse 模块就派上用场了。

from urllib.request import urlopen
from urllib.parse import urlencode
# API 基础 URL
base_url = 'https://httpbin.org/get'
# 要传递的参数(字典格式)
params = {
    'name': '张三',
    'age': 25,
    'city': '北京'
}
# 使用 urlencode 将字典转换为查询字符串(如 name=张三&age=25...)
query_string = urlencode(params)
# 将查询字符串拼接到 URL 后面
# 注意:需要手动添加 '?' 分隔符
final_url = f"{base_url}?{query_string}"
print(f"最终请求 URL: {final_url}")
with urlopen(final_url) as response:
    result = response.read().decode('utf-8')
    print(result)

urlencode 的作用: 自动将字典键值对进行 URL 编码,确保特殊字符(如空格、中文)被正确处理,避免因格式错误导致请求失败。

4 发送 POST 请求

POST 请求通常用于向服务器提交数据,与 GET 请求不同,POST 数据需要作为请求体(data 参数)传递给 urlopen

from urllib.request import urlopen, Request
from urllib.parse import urlencode
# 目标 URL(httpbin.org 是一个测试 HTTP 服务的网站)
url = 'https://httpbin.org/post'
# POST 请求的数据(字典格式)
post_data = {
    'username': 'python_dev',
    'password': '123456'
}
# 将数据编码为字节流,urllib 要求 data 参数是 bytes 类型
data_bytes = urlencode(post_data).encode('utf-8')
# 创建一个 Request 对象,并指定 data
# 注意:当 data 参数存在时,urlopen 会自动使用 POST 方法
request = Request(url, data=data_bytes)
with urlopen(request) as response:
    result = response.read().decode('utf-8')
    print(result)

代码解读:

  1. 我们创建了一个 Request 对象,而不是直接使用 urlopenRequest 对象允许我们更精细地控制请求。
  2. data 参数必须是 bytes 类型,我们先用 urlencode 将字典转为字符串,再用 .encode('utf-8') 转为字节流。
  3. urlopen 接收到带有 data 参数的 Request 对象时,它会自动将请求方法设置为 POST

5 添加请求头

很多网站会检查请求头(User-Agent)来判断请求是否来自浏览器,模拟浏览器行为是爬虫的基本操作。

from urllib.request import Request, urlopen
url = 'http://www.baidu.com'
# 自定义请求头
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'
}
# 创建 Request 对象,并传入 headers
request = Request(url, headers=headers)
with urlopen(request) as response:
    html_content = response.read().decode('utf-8')
    print(html_content[:500])

关键点: 通过 Request 对象的 headers 参数,我们可以轻松添加、修改或删除任何请求头。

6 处理异常

网络世界充满不确定性:服务器宕机、网络超时、URL 不存在……urllib.error 模块为我们提供了处理这些异常的工具。

from urllib.request import urlopen, Request
from urllib.error import URLError, HTTPError
url = 'http://www.example.com/non-existent-page'
try:
    with urlopen(url, timeout=5) as response: # 设置超时时间
        print(response.read().decode('utf-8'))
except HTTPError as e:
    # 处理 HTTP 错误(如 404 Not Found, 500 Server Error)
    print(f"HTTP 错误: {e.code} - {e.reason}")
except URLError as e:
    # 处理 URL 错误(如域名不存在)
    print(f"URL 错误: {e.reason}")
except Exception as e:
    # 处理其他未知错误
    print(f"发生未知错误: {e}")
  • HTTPError:是 URLError 的子类,专门处理 HTTP 协议层面的错误(4xx, 5xx)。
  • URLError:处理更广泛的 URL 相关错误,如连接超时、找不到服务器等。
  • 设置 timeout 参数可以有效防止程序因网络问题而无限等待。

进阶技巧:Cookie、代理与超时

1 处理 Cookie

登录后的网站通常依赖 Cookie 来维持会话状态。urllib 提供了 HTTPCookieProcessor 来处理 Cookie。

from urllib.request import Request, build_opener, urlopen
from urllib.parse import urlencode
from http.cookiejar import CookieJar
# 1. 创建一个 CookieJar 对象来存储 Cookie
cookie_jar = CookieJar()
# 2. 使用 HTTPCookieProcessor 创建一个 OpenerDirector 对象
#    它会自动处理 Cookie
opener = build_opener(HTTPCookieProcessor(cookie_jar))
# 3. 模拟登录(假设有一个登录接口)
login_url = 'https://httpbin.org/post'
login_data = {'username': 'test', 'password': 'test'}
data_bytes = urlencode(login_data).encode('utf-8')
# 使用 opener 发送登录请求,Cookie 会被自动保存
login_request = Request(login_url, data=data_bytes)
opener.open(login_request)
# 4. 访问需要登录的页面
profile_url = 'https://httpbin.org/cookies/set/freeform/hello' # 这是一个设置 Cookie 的测试 URL
# 再次使用 opener 发送请求,它会带上之前保存的 Cookie
profile_request = Request(profile_url)
response = opener.open(profile_request)
print(response.read().decode('utf-8'))
print("\n已保存的 Cookie:")
for cookie in cookie_jar:
    print(cookie)

流程: 创建 CookieJar -> 用 HTTPCookieProcessor 包装成 opener -> 用 opener 发送请求 -> Cookie 自动处理。

2 使用代理

为了隐藏真实 IP 或突破访问限制,可以使用代理服务器。

from urllib.request import ProxyHandler, build_opener, urlopen
# 代理地址(请替换为可用的代理)
proxy_address = 'http://127.0.0.1:8080' # http://user:pass@host:port
# 创建代理处理器
proxy_handler = ProxyHandler({
    'http': proxy_address,
    'https': proxy_address
})
# 使用代理处理器创建 opener
opener = build_opener(proxy_handler)
try:
    response = opener.open('http://www.baidu.com')
    print(response.read().decode('utf-8')[:500])
except Exception as e:
    print(f"代理请求失败: {e}")

urllib vs. requests:我该如何选择?

特性 urllib (标准库) requests (第三方库)
安装 无需安装,开箱即用 需要手动 pip install requests
API 风格 底层,面向对象,函数式混合 高度封装,简洁直观
易用性 较低,如 POST 请求需手动编码 data 极高,支持 JSON、Session、文件上传等
功能 功能齐全,但需更多代码实现 功能强大,如 SessionCookiesHooks
性能 作为标准库,性能稳定 性能同样出色,社区优化好
学习曲线 陡峭,适合理解底层原理 平缓,适合快速开发

总结建议:

  • 新手入门/快速开发: 首选 requests,它能让你用最少的代码实现最多的功能,让你专注于业务逻辑。
  • 环境受限/追求稳定/学习底层: 深入学习 urllib,当你在一个不能安装第三方包的受限环境(如某些服务器、嵌入式设备)中工作时,urllib 是你的唯一选择,掌握它也能让你对 HTTP 协议有更深刻的理解。

总结与展望

恭喜你!你已经从零开始,系统地学习了 Python 的 urllib 库,从简单的 GET 请求,到复杂的 POST 请求、参数处理、异常捕获、Cookie 管理和代理使用,你已经具备了使用 urllib 应付大多数 HTTP 场景的能力。

urllib 就像一位内功深厚的武林高手,虽然招式不如 requests 那样华丽,但根基扎实,威力无穷,希望本文能成为你 Python 网络编程之旅中一份有价值的参考。

下一步,你可以尝试:

  1. urllib 写一个简单的网页爬虫,抓取某个网站的标题和链接。
  2. 尝试调用一个你感兴趣的公开 API(如天气 API),并用 urllib 发送请求获取数据。
  3. urllib 的知识与 requests 进行对比,感受两者在易用性上的差异。

持续实践,你将真正成为 Python 网络编程的专家!


(正文结束)

分享:
扫描分享到社交APP
上一篇
下一篇