爬虫、网络编程、接口......对于Python工程师来讲都绕不过一个强大的模块---requests,本篇文章就深入详细讲一讲requests模块。同时也先也分享一下开源API网站:Gitee-API文档、JSONPlaceholder API文档、和风天气API文档、Postman Echo API网站,这四个网站都适合入门级的requests库实战操作。
目录
一、requests库简介
使用requests库能快速构建 HTTP 请求,而无需深入了解底层网络协议细节。其API设计直观,使得发送请求就像调用函数一样简单,同时提供了丰富的选项以满足复杂网络交互的需求。这种设计使得无论是初学者还是经验丰富的开发者都能高效地使用 Requests 进行网络编程。
requests的特点如下:
- 全面的 HTTP 支持: 支持所有 HTTP 方法(GET、POST、PUT、DELETE、PATCH 等),以及常见的 HTTP 特性,如 cookies、重定向、压缩、认证、代理、连接池等。
- 自动内容处理: 自动解码响应内容,支持 JSON、HTML、XML 等常见格式,并可通过 .text 和 .content 属性直接访问解码后的文本或原始二进制数据。
- 便捷的请求构建: 可轻松设置请求头、查询参数、请求体、认证信息等,支持多部分表单上传、文件上传、JSON 数据发送等。
- 灵活的会话管理: 提供 Session 对象,用于维护请求之间的状态(如 cookies、headers),并支持连接池复用,提高性能。
- 强大的异常处理: 提供明确的异常层次结构,如 requests.exceptions.RequestException、requests.exceptions.HTTPError,便于捕获和处理网络错误、HTTP 状态码异常等。
- 广泛的兼容性: 支持 Python 2.7 及更高版本的 Python 3.x,与各种操作系统兼容。
Requests 基于 urllib3
模块构建,后者负责底层的网络通信。Requests 采用 Apache2 Licensed 开源协议,这意味着它是一个免费且开放源代码的软件,允许在商业和非商业项目中自由使用、修改和分发。
Requests 的官方文档详尽且易于阅读,提供了丰富的示例和指南,是学习和查阅库功能的首要资源:Requests官方文档
二、安装与导入
安装:
1、PC终端(CMD):
python -m pip install requests
2、PyCharm终端:
pip install requests
导入:
import requests
三、核心组件及其常见属性
1、request
由于requests库主要用于客户端发起HTTP请求,它并不直接暴露一个名为Request的对象供开发者操作,而是提供了requests.Request类作为构建请求的基础,但通常用户更常与requests.Session及其实例方法(如.get()、.post()等)交互。请求构建过程中涉及的属性:
属性名 | 说明 |
method | HTTP方法,如GET、POST、PUT、DELETE、PATCH 等 |
url | 请求的目标URL |
params | 附加到URL的查询参数(querystring)字典,用于构建URL的查询字符串。 |
headers | 请求头字典,包含如User-Agent 、Accept 、Content-Type 等键值对。 |
auth | 指定鉴权方式 |
cookies | 请求携带的Cookie字典 |
data | 请求主体数据,可以是字节串、字符串(通常用于表单数据) |
json | 请求主体数据,可以是字节串、字符串(通常用于JSON对象) |
files | 表单上传文件 |
proxies | proxies使用代理抓包 |
请求方法及其区别:
请求方法 | 功能与语义 | 参数位置 | 缓存 | 幂等性 | 安全性 |
---|---|---|---|---|---|
GET | 从服务器获取指定资源 | 通常放在URL查询字符串中 | 响应通常可被缓存 | 是幂等的 | 相对安全,不改变服务器状态 |
PUT | 更新或替换服务器上的现有资源 | 通常放在请求正文中,包含完整的资源表示 | 响应通常不应被缓存 | 应该是幂等的 | 相对安全,仅用于更新资源。恶意或错误请求可能导致数据被覆盖 |
POST | 向服务器提交数据,用于创建新资源或执行操作 | 通常放在请求正文中,包含完整的资源表示或操作指令及数据 | 响应通常不应被缓存 | 不一定是幂等的,取决于具体操作 | 可能引发副作用,不仅用于创建资源,也可能执行非幂等操作 |
DELETE | 请求服务器删除指定资源 | 通常放在URL路径中 | 响应通常不应被缓存 | 应该是幂等的 | 具有潜在破坏性,应确保只有授权用户能执行 |
PATCH | 局部更新资源 | 通常放在请求正文中,描述资源需要更改的部分 | 响应通常不应被缓存 | 应该是幂等的 | 可能引发副作用,应确保只有授权用户能执行,并且请求体正确描述了期望的更改 |
2、response
当使用requests库收到服务器的响应时,会得到一个requests.Response对象,其常见属性包括:
属性名 | 说明 | 备注 |
status_code | HTTP响应状态码 | 整数如200、404、500等 |
reason | 状态描述 | 字符串 |
headers | 响应头 | 字典包含如 |
cookies | 服务端响应的cookies | 字典,可以传输 |
content | 二进制响应内容 | |
text | 文本响应正文 | |
json() | 将json响应正文转为dict | 是方法不是属性!如果响应内容是JSON格式,可以直接调用此属性解析为Python对象。 |
url | 产生响应的URL | 实际请求的URL(可能经过重定向) |
history | 如果有重定向发生,包含一个响应历史列表 | |
elapsed | 请求耗时 | 大概值,不精确 |
encoding | 编码方式 | 可修改 |
request | 生成响应的request | Request实例对象 |
ok | 请求是否成功,status_code小于400为真 | 布尔值 |
3、session
requests.Session是一个高级接口,用于管理一系列相关的HTTP请求,并且支持会话保持(如自动处理Cookies)。其主要属性和方法包括:
属性名 | 说明 | 备注 |
params | 附加到URL的参(querystring) | |
headers | 自定义请求头(token) | |
auth | 指定鉴权方式 | |
cookies | 添加Cookies | 会话级的CookieJar对象,存储了所有通过此Session发送请求时接收到的Cookies。 |
.get()、**.post()**等方法 | 用于发送HTTP请求 | 与直接使用requests.get()等函数相比,会利用会话级的状态。 |
四、不同HTTP请求示例
1、GET请求
功能与语义:
GET
请求用于从服务器获取指定资源。发送GET
请求相当于询问服务器:“请给我这个资源。”参数位置:
GET
请求的参数通常放在URL的查询字符串中,即URL后面以?
开始的部分,参数之间用&
分隔,每个参数由键值对组成,键与值之间用等号 (=
) 连接。例如:https://example.com/api/resource?param1=value1¶m2=value2
缓存:
GET
请求的响应通常被认为是安全可缓存的。浏览器、代理服务器和其他中间件可能会缓存GET
请求的响应结果,以便在未来相同请求时直接使用缓存,而不是再次向服务器请求。幂等性:
GET
请求是幂等的,即多次执行相同GET
请求(针对同一资源)应始终返回相同的响应结果,不会对服务器状态产生任何影响。安全性: 相对安全,因为它不改变服务器状态。
示例:
import requests url_get='https://postman-echo.com/get?key1=value1&key2=value2' response = requests.get(url_get) print(response.text)
控制台输出如下:
设置查询参数示例:
param={ 'key3':'value3', 'key4':'value4', 'key5':'value5', } response_get_param=requests.get(url_get,params=param) print(response_get_param.url) print(response_get_param.text)
控制台输出如下:
可以看到使用params参数传参,会将参数自动拼接到url上
2、POST请求
功能与语义:
POST
请求用于向服务器提交数据,主要用于创建新的资源或执行某种操作(更新、删除等,具体取决于API设计)。发送POST
请求相当于告诉服务器:“请根据我提供的数据执行某个操作。”参数位置:
POST
请求的数据通常放在请求正文中,可以是完整的资源表示(创建资源)或操作指令及关联数据(执行操作)。请求体的格式取决于Content-Type标头,常见的是application/json
(JSON格式)或application/xml
(XML格式)。缓存:
POST
请求的响应通常不应被缓存,因为它们可能改变了服务器状态。幂等性:
POST
请求不一定是幂等的,即多次执行相同POST
请求可能会产生不同的结果(例如,创建多个新的资源)。但某些情况下,如当POST
用于替换资源或执行幂等操作时,它也可以是幂等的。安全性:
POST
请求可能引发副作用,因为它不仅用于创建资源,也可能执行非幂等操作。
提交请求体表单数据示例:
通过data参数传递表单编码数据,适用于POST、PUT等请求。数据会被编码为application/x-www-form-urlencoded格式
url_post='https://postman-echo.com/post' data={ 'key':'value', 'website':'www.baidu.com' } response_post_data=requests.post(url_post,data=data) print(response_post_data.text)
控制台输出如下:
发送JSON数据示例:
通过json参数直接传递JSON数据,适用于支持JSON格式请求体的POST、PUT等请求。requests会自动将字典转换为JSON字符串,并设置Content-Type为application/json
json_data={ 'key':'value', 'website':'www.baidu.com' } response_post_json=requests.post(url_post,json=json_data) print(response_post_json.text)
控制台输出如下:
我们发现使用参数data、json,传参在请求正文中的位置是不一样的,
- 使用 data 参数时,数据将以 application/x-www-form-urlencoded 格式编码,并以 key=value 形式的字符串放置在请求正文中。
- 使用 json 参数时,数据将以 JSON 文本格式放置在请求正文中,结构清晰,适合传输复杂的数据结构。
因为我们是在pycharm控制台展示,使用的是postman echo api可能效果不明显
3、PUT请求
功能与语义:
PUT
请求用于更新或替换服务器上的现有资源。发送PUT
请求相当于告诉服务器:“请用我提供的数据替换或更新指定资源。”参数位置:
PUT
请求的数据通常放在请求正文中,可以是完整的资源表示。请求体格式同POST请求。缓存:
PUT
请求的响应通常不应被缓存,因为它们可能改变了服务器状态。幂等性:
PUT
请求应该是幂等的,即多次执行相同PUT
请求(携带相同数据)应导致相同的最终资源状态。安全性: 如果API设计合理,
PUT
请求相对安全,因为它仅用于更新资源。然而,恶意或错误的PUT
请求可能导致数据被意外覆盖。
示例:
json_data = { 'key1': 'value1', 'key2': 'value2', 'key3': 'value3', 'key4': 'value4', 'key5': 'value5', 'key6': 'hahaha' } url_put='https://postman-echo.com/put' response_put_json=requests.put(url_put,json=json_data) print(response_put_json.json())
控制台输出如下:
4、DELETE请求
功能与语义:
DELETE
请求用于请求服务器删除指定的资源。发送DELETE
请求相当于告诉服务器:“请删除这个资源。”幂等性:
DELETE
请求应该是幂等的,即多次执行相同DELETE
请求(针对同一资源)应导致相同的最终结果——资源被删除。安全性:
DELETE
请求具有潜在破坏性,因为它会永久删除服务器上的资源。因此,在使用DELETE
请求时应格外小心,并确保只有授权用户才能执行此类操作。参数位置:
DELETE
请求的参数通常放在URL路径中(用于标识要删除的资源),也可以放在请求头或请求体中,具体取决于API设计。不过,实践中通常不推荐在DELETE
请求的请求体中放置数据。
示例:
url_delete='https://postman-echo.com/delete' response_delete=requests.delete(url_delete) print(response_delete.status_code)
一般删除请求返回状态码以及操作提示
5、PATCH请求
功能与语义:
PATCH
请求用于局部更新资源。与PUT
请求不同,PATCH
请求仅需提供资源需要更改的部分,而非整个资源的完整表示。发送PATCH
请求相当于告诉服务器:“请根据我提供的数据对指定资源进行部分更新。”参数位置:
PATCH
请求的数据通常放在请求正文中,描述资源需要更改的部分。请求体格式通常遵循RFC 6902(JSON Patch)或RFC 7396(JSON Merge Patch)规范,但也可能根据API设计采用自定义格式。缓存:
PATCH
请求的响应通常不应被缓存,因为它们可能改变了服务器状态。幂等性:
PATCH
请求应该是幂等的,即多次执行相同PATCH
请求(携带相同数据)应导致相同的最终资源状态。安全性: 可能引发副作用,应确保只有授权用户能执行,并且请求体正确描述了期望的更改。与
PUT
请求类似,恶意或错误的PATCH
请求可能导致数据被意外更改。
示例:
url_patch='https://postman-echo.com/patch' json_data ={ "op": "replace", "path": "/message", "value": "Updated message" } response_patch=requests.patch(url_patch,json=json_data) print(response_patch.text)
控制台输出如下:
6、上传文件
示例:
import requests url_post='https://postman-echo.com/post' file_path='./test.txt' # 构建 multipart/form-data 格式的文件数据 files = {'file': open(file_path, 'rb')} # 发起POST请求,携带文件数据 response = requests.post(url_post, files=files) # 检查响应状态码 if response.status_code == 200: print("文件上传成功,响应内容:") print(response.text) else: print(f"文件上传失败,状态码:{response.status_code}")
控制台输出如下:
五、请求头管理
通过headers参数传递请求头信息,可以自定义或覆盖默认的HTTP头部。
import requests response=requests.get('https://postman-echo.com/headers') print(response.text) headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', 'Cache-Control': 'no-cache', 'Authorization': 'my_access_token', # 若需要API认证,替换为实际的访问令牌 'X-Custom-Header': 'Value-for-custom-header' } response_headers = requests.get('https://postman-echo.com/headers', headers=headers) print(response_headers.text)
- User-Agent: 模拟浏览器标识,这里模拟的是Edg浏览器。
- Accept-Language: 指定接受的语言类型及优先级。
- Cache-Control: 设置不使用缓存。
- Authorization: 提供了API访问所需的Bearer token(如果API需要身份验证的话,请替换为实际的访问令牌)。
- X-Custom-Header: 这是一个示例性的自定义请求头,通常以X-开头,用于向服务器传递特定信息。
需要注意:
1. 请求头必须是键值对(python中的字典)
2. 请求头的内容必须是ascii内容
控制台输出如下:
六、Session实现会话管理
使用requests.Session()创建一个会话对象(session),以便在一系列请求之间保持某些状态,如请求头、公共参数、cookies、认证信息、连接池等。以下是使用session对象的示例:
1、通过Session对象设置全局请求头及全局参数
import requests # 创建一个Session对象 session = requests.Session() # 设置全局请求头(适用于所有通过此Session发出的请求) session.headers.update({ 'User-Agent': 'MyApp/1.0', 'X-Api-Key': 'your_api_key' }) # 设置共享公共参数 session.params = { 'param1': 'value1', 'param2': 'value2' } # 使用Session对象发起GET请求 response = session.get('https://postman-echo.com/get') # 检查响应状态码 if response.status_code == 200: print("GET请求成功,响应内容:") print(response.json()) else: print(f"GET请求失败,状态码:{response.status_code}") # 使用Session对象发起POST请求,携带JSON数据 post_data = { "key1": "value1", "key2": "value2" } response = session.post('https://postman-echo.com/post', json=post_data) # 检查响应状态码 if response.status_code == 200: print("POST请求成功,响应内容:") print(response.json()) else: print(f"POST请求失败,状态码:{response.status_code}")
控制台输出如下:
可以明显发现,使用Session()对象设置的全局请求头以及全局参数都实现了
2、通过Session对象管理cookie:
import requests session = requests.Session() # 使用Session对象发起GET请求,获取一个带Set-Cookie响应头的响应 response = session.get('https://postman-echo.com/cookies/set?foo=bar&baz=qux') # 检查响应状态码 if response.status_code == 200: print("GET请求成功,响应内容:") print(response.json()) # 使用Session对象再次发起GET请求,此时Session会自动附上之前接收到的cookies response = session.get('https://postman-echo.com/cookies') # 检查响应状态码 if response.status_code == 200: print("\nCookies检查请求成功,响应内容:") print(response.json()) else: print(f"Cookies检查请求失败,状态码:{response.status_code}") # 关闭Session(可选,释放资源) session.close()
在这个示例中:
- 首先创建了一个requests.Session()对象,用于管理一系列相关的HTTP请求。
- 通过session.headers.update()方法设置了全局请求头。这些头信息将自动应用到通过该Session发出的所有请求上,无需在每次请求时单独设置。
- 使用Session对象的get()方法发起一个GET请求,并检查响应状态码。如果状态码为200,说明请求成功,打印响应内容。
- 使用Session对象的post()方法发起一个POST请求,携带JSON数据。同样检查响应状态码,如果状态码为200,说明请求成功,打印响应内容。
- (可选)使用session.close()关闭Session,释放相关资源。在实际使用中,尤其是在长生命周期的程序中,确保及时关闭Session以避免资源泄漏。
控制台输出如下:
在这个示例中:
- 首先创建了一个requests.Session()对象,用于管理一系列相关的HTTP请求。
- 使用Session对象的get()方法向https://postman-echo.com/cookies/set?foo=bar&baz=qux发起一个GET请求。这个端点会设置两个cookies(foo和baz)并在响应中返回它们。检查响应状态码,如果状态码为200,说明请求成功,打印响应内容。
- 使用同一个Session对象的get()方法向https://postman-echo.com/cookies发起另一个GET请求。这个端点会返回当前请求所携带的所有cookies。由于我们使用的是同一个Session,requests库会自动将之前接收到的cookies附加到这次请求中。检查响应状态码,如果状态码为200,说明请求成功,打印响应内容。
- (可选)使用session.close()关闭Session,释放相关资源。
Postman Echo API 的/cookies/set端点用于设置cookies,/cookies端点用于检查当前请求所携带的cookies。通过这个示例,可以看到requests.Session如何自动处理cookies:
- 当首次请求接收到Set-Cookie响应头时,Session对象会自动存储这些cookies。
- 在后续的请求中,Session对象会自动将存储的cookies附带到请求头中,除非我们显式清除或修改它们。
3、通过Session对象显示操作cookie
示例如下:
import requests # 创建一个Session对象 session = requests.Session() # 添加一个初始cookie session.cookies.set('initial_cookie', 'initial_value') # 使用Session对象发起GET请求,获取一个带Set-Cookie响应头的响应 response = session.get('https://postman-echo.com/cookies/set?foo=bar&baz=qux') # 检查响应状态码 if response.status_code == 200: print("GET请求成功,响应内容:") print(response.json()) # 显式删除指定名称的cookie session.cookies.pop('foo', None) response = session.get('https://postman-echo.com/cookies') if response.status_code == 200: print("\n删除cookie后,GET请求成功,响应内容:") print(response.json()) # 显式添加一个新的cookie session.cookies.set('new_cookie', 'new_value') # 显示更新响应中的cookies session.cookies.set('baz', 'updated_value') response = session.get('https://postman-echo.com/cookies') if response.status_code == 200: print("\n添加新cookie以及更新原本接收的旧cookies,GET请求成功,响应内容:") print(response.json()) # 显式清除所有cookies session.cookies.clear() # 再次使用Session对象发起GET请求,此时Session中的cookies已被清除 response = session.get('https://postman-echo.com/cookies') # 检查响应状态码 if response.status_code == 200: print("\nCookies检查请求成功,响应内容:") print(response.json()) else: print(f"Cookies检查请求失败,状态码:{response.status_code}")
控制台输出如下:
在这个示例中,我们在创建Session对象后添加了一个初始cookie。
接着,通过Session对象向Postman Echo API 发送请求,接收并自动存储两个新的cookies。
接着,操作删除了一个自动存储的cookies-- "foo"
再接着,我们添加了新的cookies以及更新了原本自动存储的cookies。
然后,我们调用session.cookies.clear()清除Session中的所有cookies。最后,再次向Postman Echo API 发送请求检查cookies,此时响应中应不再包含任何cookies,证明清除操作成功。
希望以上内容能帮助大家有效理解requests模块,同时也建议大家通过开源api网站去强化练习使用requests,具备编写Python程序与各类Web服务进行交互的能力,为进一步学习网络编程、API开发与集成等技术打下坚实基础。