在本教程中,我们将看看 Python Requests 库,它是 urllib 的一个更强大和用户友好的替代品。Python Requests 简化并改进了内置的 urllib 模块。Python Requests 是一个功能全面的库,它的功能比我们在这里所能涵盖的要多,但我们将看一下最重要的那些功能。与 urllib 不同,Requests 不随标准的 Python 发行版打包。由于我们熟悉 PIP 和 python 虚拟环境,安装Requests将非常容易,这样我们就可以测试它的功能了。Requests的API是用户友好的,并提供了与所有可用的HTTP操作一起工作的能力。每个HTTP操作实际上都映射到Requests API的同一个方法名。通过Requests,可以处理发送数据参数、标头,并将尝试为你自动解码网络响应。如果返回的数据是JSON格式的,这一点尤其好用。
安装Requests
为了让Requests库安装在我们的Python虚拟环境中,我们可以输入pip install requests。

当你输入pip install requests时,你会看到pip软件包管理器会继续下载Requests和任何可能需要的支持依赖。在下载完成后键入pip freeze,我们可以看到,除了 requests 之外,certifi、chardet、idna 和 urllib3 包也被安装。
制作一个简单的请求
GET请求是最简单的请求类型,你可以使用该库。要做到这一点,你需要使用 **get**方法,并传递你想获取数据的URL。下面的语法代表了一个简单的GET请求,表格中包含了一些你可以在每个请求中使用的常用参数。
response = requests.get(url)
| 参数 | 将在查询字符串中发送的键值对 |
| 头信息 | 将与请求一起发送的头文件的字典 |
| auth | 认证元组,用于启用不同形式的认证 |
| 超时 | 等待服务器响应的秒值 |
测试请求
在我们的Pycharm沙盒中,我们可以添加一个新文件来测试Requests库的一些代码。

制作一个GET请求
requests_tutorial.py
import requests
def printResponse(resp):
print(f'Response Code: +----- {resp.status_code} -----+')
print('n')
print('Headers: +----------------------+')
print(resp.headers)
print('n')
print('Returned data: +----------------------+')
print(resp.text)
# Use requests to issue an HTTP GET request
url = 'http://httpbin.org/xml'
resp = requests.get(url)
printResponse(resp)
Response Code: +----- 200 -----+
Headers: +----------------------+
{'Date': 'Wed, 11 Mar 2020 18:03:20 GMT', 'Content-Type': 'application/xml', 'Content-Length': '522', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true'}
Returned data: +----------------------+
<?xml version='1.0' encoding='us-ascii'?>
<!-- A SAMPLE set of slides -->
<slideshow
title="Sample Slide Show"
date="Date of publication"
author="Yours Truly"
>
<!-- TITLE SLIDE -->
<slide type="all">
<title>Wake up to WonderWidgets!</title>
</slide>
<!-- OVERVIEW -->
<slide type="all">
<title>Overview</title>
<item>Why <em>WonderWidgets</em> are great</item>
<item/>
<item>Who <em>buys</em> WonderWidgets</item>
</slide>
</slideshow>
Process finished with exit code 0
在我们的测试代码中,我们使用了一个python函数printResponse(),它封装了打印响应代码、头信息和返回数据的逻辑。这些可以在响应对象上使用status_code,headers, 和text属性来访问。
包括参数
在这段代码中,我们可以将一些参数与请求一起发送。首先,我们要把我们使用的URL[从http://httpbin.org/xml 改为http://httpbin.org/get。httpbin的GET端点会以JSON格式回传获取请求的内容。为了添加参数,我们定义了一个保存简单键值对的字典,并给它命名为payload。然后我们用request.get(url, params=payload)来发出请求。这不需要像使用urllib 库那样进行编码。
import requests
def printResponse(resp):
print(f'Response Code: +----- {resp.status_code} -----+')
print('n')
print('Headers: +----------------------+')
print(resp.headers)
print('n')
print('Returned data: +----------------------+')
print(resp.text)
# Send some parameters to the URL via a GET request
# Requests handles this for you, no manual encoding
payload = {'Size': 'Large', 'Cream': True, 'Sugar': False}
url = 'http://httpbin.org/get'
resp = requests.get(url, params=payload)
printResponse(resp)
Response Code: +----- 200 -----+
Headers: +----------------------+
{'Date': 'Wed, 11 Mar 2020 18:13:37 GMT', 'Content-Type': 'application/json', 'Content-Length': '410', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true'}
Returned data: +----------------------+
{
"args": {
"Cream": "True",
"Size": "Large",
"Sugar": "False"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.23.0",
"X-Amzn-Trace-Id": "Root=1-5e692a51-71b500ab1d13d674526bc5d0"
},
"origin": "192.168.10.1",
"url": "http://httpbin.org/get?Size=Large&Cream=True&Sugar=False"
}
Process finished with exit code 0
发出一个POST请求
现在,我们想测试一下使用请求库做一个POST请求。同样的有效载荷将被用来发送请求,我们将看到使用POST和GET时的区别。为了发出一个POST请求,我们可以使用requests类的.post()方法。注意,post()的第二个参数是 **data**的第二个参数,而不是 **params**而不是像GET请求那样。requests库的方法名称直接映射到标准的Http动词。
import requests
def printResponse(resp):
print(f'Response Code: +----- {resp.status_code} -----+')
print('n')
print('Headers: +----------------------+')
print(resp.headers)
print('n')
print('Returned data: +----------------------+')
print(resp.text)
# Send some parameters to the URL via a GET request
# Requests handles this for you, no manual encoding
payload = {'Size': 'Large', 'Cream': True, 'Sugar': False}
url = 'http://httpbin.org/post'
resp = requests.post(url, data=payload)
printResponse(resp)
Response Code: +----- 200 -----+
Headers: +----------------------+
{'Date': 'Wed, 11 Mar 2020 20:23:51 GMT', 'Content-Type': 'application/json', 'Content-Length': '526', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true'}
Returned data: +----------------------+
{
"args": {},
"data": "",
"files": {},
"form": {
"Cream": "True",
"Size": "Large",
"Sugar": "False"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "33",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.23.0",
"X-Amzn-Trace-Id": "Root=1-5e6948d7-4b5b42c85acf7660e4e2c1a8"
},
"json": null,
"origin": "10.10.10.10",
"url": "http://httpbin.org/post"
}
Process finished with exit code 0
发送自定义头信息
为了测试发送自定义头信息,让我们回到 httpbin.org/get 端点并删除数据有效载荷。我们设置了一个customHeader变量,并分配了一个保存键值对的字典。在这个字典中,我们可以指定User-Agent,它经常被用来识别自定义的Web应用程序。
import requests
def printResponse(resp):
print(f'Response Code: +----- {resp.status_code} -----+')
print('n')
print('Headers: +----------------------+')
print(resp.headers)
print('n')
print('Returned data: +----------------------+')
print(resp.text)
# Pass a custom header to the server
url = "http://httpbin.org/get"
customHeader = {'User-Agent': 'Gardens-Delight-App / 1.0.1'}
resp = requests.get(url, headers=customHeader)
printResponse(resp)
Response Code: +----- 200 -----+
Headers: +----------------------+
{'Date': 'Wed, 11 Mar 2020 20:46:31 GMT', 'Content-Type': 'application/json', 'Content-Length': '312', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true'}
Returned data: +----------------------+
{
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "Gardens-Delight-App / 1.0.1",
"X-Amzn-Trace-Id": "Root=1-5e694e27-6ade43401b07635c60af1748"
},
"origin": "1.2.3.4",
"url": "http://httpbin.org/get"
}
Process finished with exit code 0
用HTTPError处理错误
当你与互联网上的远程服务器进行通信时,事情有时会出错。一个服务器可能被关闭,或者一个用户输入错误的URL,或者连接只是简单地超时。Python 代码需要能够对这些类型的情况做出反应。为了测试错误状态,httpbin 提供了几个不同的端点来模拟问题。首先,我们来测试一下404端点。
import requests
from requests.exceptions import HTTPError, Timeout
def printResponse(resp):
print(f'Response Code: +----- {resp.status_code} -----+')
print('n')
print('Headers: +----------------------+')
print(resp.headers)
print('n')
print('Returned data: +----------------------+')
print(resp.text)
try:
url = 'http://httpbin.org/status/404'
resp = requests.get(url)
resp.raise_for_status()
printResponse(resp)
except HTTPError as error:
print(f'Http Error: {error}')
except Timeout as error:
print(f'Request timed out: {error}')
Http Error: 404 Client Error: NOT FOUND for url: http://httpbin.org/status/404
Process finished with exit code 0
处理超时
import requests
from requests.exceptions import HTTPError, Timeout
def printResponse(resp):
print(f'Response Code: +----- {resp.status_code} -----+')
print('n')
print('Headers: +----------------------+')
print(resp.headers)
print('n')
print('Returned data: +----------------------+')
print(resp.text)
try:
url = 'http://httpbin.org/delay/5'
resp = requests.get(url, timeout=3)
resp.raise_for_status()
printResponse(resp)
except HTTPError as error:
print(f'Http Error: {error}')
except Timeout as error:
print(f'Request timed out: {error}')
Request timed out: HTTPConnectionPool(host='httpbin.org', port=80): Read timed out. (read timeout=3)
Process finished with exit code 0
请求中的认证
在Http请求中使用认证是一项常见的任务。Python Requests库支持基于Web的认证,形式包括Basic Auth、Digest凭证和Oauth。我们可以使用 httpbin 网站来测试一些认证请求。

为了测试基本认证,我们首先需要在 httpbin 网站上指定要授权的凭证。

在httpbin,我们现在有一个端点设置,我们可以用来测试。该端点是根据我们上面设置的凭证httpbin.org/basic-auth/…
import requests
from requests.auth import HTTPBasicAuth
def printResponse(resp):
print(f'Response Code: +----- {resp.status_code} -----+')
print('n')
print('Headers: +----------------------+')
print(resp.headers)
print('n')
print('Returned data: +----------------------+')
print(resp.text)
# Access a URL that requires authentication - the format of this
# URL is that you provide the username/password to auth against
url = 'https://httpbin.org/basic-auth/vegibit/secret'
# Create a credentials object using HTTPBasicAuth
credentials = HTTPBasicAuth('vegibit', 'secret')
# Issue the request with the authentication credentials
resp = requests.get(url, auth=credentials)
printResponse(resp)
Response Code: +----- 200 -----+
Headers: +----------------------+
{'Date': 'Thu, 12 Mar 2020 14:36:41 GMT', 'Content-Type': 'application/json', 'Content-Length': '50', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true'}
Returned data: +----------------------+
{
"authenticated": true,
"user": "vegibit"
}
Process finished with exit code 0
在上面的测试中,我们在Pycharm中运行了这个,我们可以看到结果。JSON反馈显示,我们的认证状态为true,用户为vegibit。如果我们提供错误的密码并再次发送请求,我们现在得到一些不同的反馈。一个401未授权的消息被返回,表明根据所提供的凭证,我们没有访问权。此外,在返回的数据区域,我们可以看到没有任何数据。
Response Code: +----- 401 -----+
Headers: +----------------------+
{'Date': 'Thu, 12 Mar 2020 14:41:42 GMT', 'Content-Length': '0', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'WWW-Authenticate': 'Basic realm="Fake Realm"', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true'}
Returned data: +----------------------+
Process finished with exit code 0
这让我们对基本认证如何使用Python Requests库有了一个很好的概念。
Python请求库总结
在本教程中,我们了解了Python Requests库。Requests建立在Python标准库中默认的urllib包所提供的功能之上。urllib需要的一些手动任务,如数据参数的编码,在Requests中会自动为你完成。此外,Requests将尝试根据返回的响应类型自动解码。它有一个简单的API,每个方法的名称都与可用的Http动词相匹配。开发人员可以根据需要加入参数、标头和cookies,并支持所有常见的认证类型。
- 简单的API - 每个HTTP动词都是一个方法名
- 使得参数、标头和cookies的使用更加容易
- 自动对返回的内容进行解码
- 当检测到JSON内容时自动解析
- 处理重定向、超时和错误
- 支持认证和会话
请求示例
result = requests.get('http://example.com')
result = requests.put('http://example.com/put', data = {'key':'value'})
result = requests.delete('http://example.com/delete')
result = requests.head('http://example.com/head')
result = requests.options('http://example.com/options')