ZetCode

Python urllib3

最后修改于 2024 年 1 月 29 日

Python urllib3 教程介绍了 Python urllib3 模块。我们将展示如何获取数据、发布数据、流式传输数据、使用 JSON 以及使用重定向。

超文本传输协议 (HTTP) 是一种用于分布式、协作式、超媒体信息系统的应用协议。HTTP 是万维网数据通信的基础。

Python urllib3

urllib3 模块是一个功能强大且易于使用的 Python HTTP 客户端。它支持线程安全、连接池、客户端 SSL/TLS 验证、带有多部分编码的文件上传、用于重试请求和处理 HTTP 重定向的助手、gzip 和 deflate 编码以及 HTTP 和 SOCKS 代理。

$ pip install urllib3

我们使用 pip 安装 urllib3 模块。

Python urllib3 版本

第一个程序打印 urllib3 模块的版本。

version.py
#!/usr/bin/python

import urllib3

print(urllib3.__version__)

该程序打印 urllib3 的版本。

$ ./version.py
1.24.1

这是该示例的示例输出。

Python urllib3 状态

HTTP 响应状态代码指示特定的 HTTP 请求是否已成功完成。响应分为五个类

status.py
#!/usr/bin/python

import urllib3


http = urllib3.PoolManager()

url = 'http://webcode.me'

resp = http.request('GET', url)
print(resp.status)

该示例创建对 webcode.me 的 GET 请求。它打印响应的状态代码。

http = urllib3.PoolManager()

我们创建一个 PoolManager 来生成请求。它处理连接池和线程安全的所有细节。

url = 'http://webcode.me'

这是我们发送请求的 URL。

resp = http.request('GET', url)

使用 request 方法,我们对指定的 URL 发出 GET 请求。

print(resp.status)

我们打印响应的状态代码。

$ status.py
200

200 状态代码表示请求已成功。

Python urllib3 GET 请求

HTTP GET 方法请求指定资源的表示形式。

get_request.py
#!/usr/bin/python

import urllib3


http = urllib3.PoolManager()

url = 'http://webcode.me'

resp = http.request('GET', url)
print(resp.data.decode('utf-8'))

该示例向 webcode.me 网页发送 GET 请求。它返回主页的 HTML 代码。

req = http.request('GET', url)

生成 GET 请求。

print(resp.data.decode('utf-8'))

我们获取数据或响应,并将其解码为文本。

$ ./get_request.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My html page</title>
</head>
<body>

    <p>
        Today is a beautiful day. We go swimming and fishing.
    </p>

    <p>
         Hello there. How are you?
    </p>

</body>

Python urllib3 HEAD 请求

HEAD 请求是没有消息主体的 GET 请求。

head_request.py
#!/usr/bin/python

import urllib3


http = urllib3.PoolManager()

url = 'http://webcode.me'
resp = http.request('HEAD', url)

print(resp.headers['Server'])
print(resp.headers['Date'])
print(resp.headers['Content-Type'])
print(resp.headers['Last-Modified'])

在该示例中,我们创建对 webcode.me 网站的 HEAD 请求。

print(resp.headers['Server'])
print(resp.headers['Date'])
print(resp.headers['Content-Type'])
print(resp.headers['Last-Modified'])

响应对象包含 headers 字典,其中包含各种标头字段,例如 server 和 date。

$ ./head_request.py
nginx/1.6.2
Thu, 20 Feb 2020 14:35:14 GMT
text/html
Sat, 20 Jul 2019 11:49:25 GMT

从输出中我们可以看到该网站的 Web 服务器是 nginx,内容类型是 HTML 代码。

Python urllib3 HTTPS 请求

urllib3 提供客户端 TLS/SSL 验证。为此,我们需要下载 certifi 模块。 它是一个精心策划的根证书集合,用于在验证 TLS 主机的身份时验证 SSL 证书的可信度。 它已从 Requests 项目中提取。

$ pip install certifi

我们安装 certifi

import certifi

print(certifi.where())

要引用已安装的证书颁发机构 (CA) 包,我们使用内置的 where 函数。

status2.py
#!/usr/bin/python

import urllib3
import certifi


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

http = urllib3.PoolManager(ca_certs=certifi.where())
resp = http.request('GET', url)

print(resp.status)

我们创建对 https://httpbin.org/anything 页面的 GET 请求。

http = urllib3.PoolManager(ca_certs=certifi.where())

我们将根 CA 包传递给 PoolManager。 如果没有此 CA 包,该请求将发出以下警告: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised.

Python urllib3 查询参数

查询参数是统一资源定位符 (URL) 的一部分,它为指定的参数分配值。这是将数据发送到目标服务器的一种方式。

http://example.com/api/users?name=John%20Doe&occupation=gardener

查询参数在 ? 字符之后指定。多个字段用 & 分隔。特殊字符,如空格,会被编码。在上面的字符串中,空格被编码为 %20 值。

query_params.py
#!/usr/bin/python

import urllib3
import certifi

http = urllib3.PoolManager(ca_certs=certifi.where())

payload = {'name': 'Peter', 'age': 23}

url = 'https://httpbin.org/get'
req = http.request('GET', url, fields=payload)

print(req.data.decode('utf-8'))

在此示例中,我们使用一些查询参数向 https://httpbin.org/get 发送 GET 请求。 该链接只是将一些数据返回给客户端,包括查询参数。 该站点用于测试 HTTP 请求。

payload = {'name': 'Peter', 'age': 23}

这是要发送的有效负载。

req = http.request('GET', url, fields=payload)

查询参数使用 fields 选项指定。

$ ./query_params.py
{
  "args": {
    "age": "23",
    "name": "Peter"
  },
  "headers": {
    "Accept-Encoding": "identity",
    "Host": "httpbin.org",
    "X-Amzn-Trace-Id": "Root=1-5e4ea45f-c3c9c721c848f8f81a3129d8"
  },
  "origin": "188.167.251.9",
  "url": "https://httpbin.org/get?name=Peter&age=23"
}

httpbin.org 响应了一个 JSON 字符串,其中也包括我们的有效负载。

Python urllib3 POST 请求

HTTP POST 方法将数据发送到服务器。它通常用于上传文件或提交完成的 Web 表单。

post_request.py
#!/usr/bin/python

import urllib3
import certifi


http = urllib3.PoolManager(ca_certs=certifi.where())

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

req = http.request('POST', url, fields={'name': 'John Doe'})
print(req.data.decode('utf-8'))

该示例发送 POST 请求。 数据使用 fields 选项指定。

$ ./post_request.py
{
  "args": {},
  "data": "",
  "files": {},
  "form": {
    "name": "John Doe"
  },
  ...
  "url": "https://httpbin.org/post"
}

Python urllib3 发送 JSON

在诸如 POST 或 PUT 之类的请求中,客户端通过 Content-Type 标头告诉服务器实际发送的数据类型。

send_json.py
#!/usr/bin/python

import urllib3
import certifi
import json


http = urllib3.PoolManager(ca_certs=certifi.where())

payload = {'name': 'John Doe'}
encoded_data = json.dumps(payload).encode('utf-8')

resp = http.request(
     'POST',
     'https://httpbin.org/post',
     body=encoded_data,
     headers={'Content-Type': 'application/json'})

data = json.loads(resp.data.decode('utf-8'))['json']
print(data)

该示例发送 JSON 数据。

payload = {'name': 'John Doe'}
encoded_data = json.dumps(payload).encode('utf-8')

我们将 JSON 数据编码为二进制格式。

resp = http.request(
     'POST',
     'https://httpbin.org/post',
     body=encoded_data,
     headers={'Content-Type': 'application/json'})

我们在请求中指定 Content-Type 标头。

data = json.loads(resp.data.decode('utf-8'))['json']
print(data)

我们将返回的数据解码回文本并将其打印到控制台。

Python urllib3 二进制数据

在以下示例中,我们下载二进制数据。

get_binary.py
#!/usr/bin/python

import urllib3


http = urllib3.PoolManager()

url = 'http://webcode.me/favicon.ico'
req = http.request('GET', url)

with open('favicon.ico', 'wb') as f:
    f.write(req.data)

该示例下载一个小图标。

with open('favicon.ico', 'wb') as f:
    f.write(req.data)

req.data 采用二进制格式,我们可以直接将其写入磁盘。

Python urllib3 流式传输数据

分块传输编码是自 HTTP 1.1 起可用的流式数据传输机制。 在分块传输编码中,数据流被划分为一系列不重叠的

这些块被发送和接收,彼此独立。 每个块前面都有其大小(以字节为单位)。

preload_content 设置为 False 意味着 urllib3 将流式传输响应内容。 stream 方法迭代响应内容的块。 在流式传输时,我们应该调用 release_conn 以将 http 连接释放回连接池,以便可以重复使用。

streaming.py
#!/usr/bin/python

import urllib3
import certifi


url = "https://docs.oracle.com/javase/specs/jls/se8/jls8.pdf"

local_filename = url.split('/')[-1]

http = urllib3.PoolManager(ca_certs=certifi.where())

resp = http.request(
    'GET',
    url,
    preload_content=False)

with open(local_filename, 'wb') as f:

    for chunk in resp.stream(1024):
        f.write(chunk)

resp.release_conn()

在此示例中,我们下载一个 PDF 文件。

resp = http.request(
    'GET',
    url,
    preload_content=False)

使用 preload_content=False,我们启用流式传输。

with open(local_filename, 'wb') as f:

    for chunk in resp.stream(1024):
        f.write(chunk)

我们迭代数据块并将它们保存到文件中。

resp.release_conn()

最后,我们释放连接。

Python urllib3 重定向

重定向会将用户和搜索引擎发送到与他们最初请求的 URL 不同的 URL。 要遵循重定向,我们将 redirect 选项设置为 True

redirect.py
#!/usr/bin/python

import urllib3
import certifi

http = urllib3.PoolManager(ca_certs=certifi.where())


url = 'https://httpbin.org/redirect-to?url=/'
resp = http.request('GET', url, redirect=True)

print(resp.status)
print(resp.geturl())
print(resp.info())

该示例遵循重定向。

$ ./redirect.py
200
/
HTTPHeaderDict({'Date': 'Fri, 21 Feb 2020 12:49:29 GMT', 'Content-Type': 'text/html; 
charset=utf-8', 'Content-Length': '9593', 'Connection': 'keep-alive', 
'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 
'Access-Control-Allow-Credentials': 'true'})

Python urllib3 Flask 示例

在以下示例中,我们向一个小的 Flask Web 应用程序发送请求。 在 Python Flask 教程中了解有关 Flask Web 框架的更多信息。

$ pip install flask

我们需要安装 flask 模块。

app.py
#!/usr/bin/python

from flask import Flask
from flask import request


app = Flask(__name__)

@app.route('/headers')
def hello():

    ua = request.headers.get('user-agent')
    ka = request.headers.get('connection')

    return f'User agent: {ua}; Connection: {ka}'

该应用程序只有一个路由。 它将请求的用户代理和连接标头字段发送给客户端。

send_req.py
#!/usr/bin/python

import urllib3


http = urllib3.PoolManager()

url = 'localhost:5000/headers'

headers = urllib3.make_headers(keep_alive=True, user_agent='Python program')
resp = http.request('GET', url, headers=headers)
print(resp.data.decode('utf-8'))

在此程序中,我们向 Flask 应用程序发送请求。

url = 'localhost:5000/headers'

默认情况下,Flask 在端口 5000 上运行。

headers = urllib3.make_headers(keep_alive=True, user_agent='Python program')

使用 make_headers 辅助方法,我们创建一个标头字典。

resp = http.request('GET', url, headers=headers)

我们向 URL 发送 GET 请求; 我们指定标头字典。

print(resp.data.decode('utf-8'))

我们将响应打印到终端。

$ export FLASK_APP=app.py
$ flask run

我们运行 Flask 应用程序。

$ ./send_req.py
User agent: Python program; Connection: keep-alive

从不同的终端,我们启动 send_req.py 程序。

来源

Python urllib3 文档

在本文中,我们使用了 Python urllib3 模块。

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我撰写了 1,400 多篇文章和 8 本电子书。 我在编程教学方面拥有超过十年的经验。

列出所有 Python 教程