当前位置: 首页 > 工具软件 > Requests > 使用案例 >

Python3: http/https请求模块 - requests 模块

曾鸿振
2023-12-01

本文链接: https://blog.csdn.net/xietansheng/article/details/115558046

Python3 学习笔记(目录)

requests 模块用于 HTTP 网络请求,在内置模块的基础上进行了高度的封装,从而使 HTTP 网络请求变的更加人性化,比系统自带的 urllib 模块更加好用。requests 支持 Cookie 保持会话、自动响应内容编码、自动解码 gzip 和 deflate 等多种功能。

下面的说明来自 requests 用户文档 首页,可见 requests 的魅力所在(可惜目前版本不支持 HTTP/2,期待以后的更新):

Requests: 让 HTTP 服务人类

Requests 唯一的一个非转基因的 Python HTTP 库,人类可以安全享用。

警告:非专业使用其他 HTTP 库会导致危险的副作用,包括:安全缺陷症、
     冗余代码症、重新发明轮子症、啃文档症、抑郁、头疼、甚至死亡。

拓展:同时支持 HTTP/2、同步、异步的 HTTP 客户端 HTTPX

requests 相关文档:

HTTP 请求测试用地址: http://httpbin.orghttps://httpbin.org

requests 是第三方模块,使用前需要先安装:

pip3 install requests

1. requests 中的请求方法

HTTP 请求方法:

requests.get(url, params=None, **kwargs)                # GET 请求
requests.post(url, data=None, json=None, **kwargs)      # POST 请求
requests.put(url, data=None, **kwargs)                  # PUT 请求
requests.patch(url, data=None, **kwargs)                # PATCH 请求
requests.head(url, **kwargs)                            # HEAD 请求
requests.options(url, **kwargs)                         # OPTIONS 请求
requests.delete(url, **kwargs)                          # DELETE 请求

# 以上所有请求均返回一个 requests.Response 对象

以上各请求,最终发给统一的请求方法:

requests.request(method, url, **kwargs)

# 参数说明:
#
# method: 
#       请求方法: "GET", "POST", "PUT", "PATCH", "HEAD", "OPTIONS", or "DELETE"
#
# url:
#       请求链接
#
# params:
#       URL查询参数, 拼接到 URL Query String 中, 一般用于 GET 请求,
#       类型: 字典{name1:value1, ...}、
#            元祖列表[(name1, value1), ...]、
#            bytes/str([b]"name1=value1&name2=value2")。
#       拼接后结果如: http://httpbin.org/get?name1=value1&name2=value2
#
# data:
#       发送到请求 Body 中的数据, 一般用于 POST/PUT 请求,
#       类型: 字典{name1:value1, ...}, 元祖列表[(name1, value1), ...], bytes/str 或 文件流对象。
#
#       如果是 字典/元祖列表, 则按照 form 表单格式拼接后发送到请求 Body 中, 
#       如: "name1=value1&name2=value2", 并且自动添加请求头:
#       "Content-Type": "application/x-www-form-urlencoded"
#
#       如果是 bytes/str, 则直接将内容发送到请求 Body 中, 并且不添加 Content-Type 请求头。
#
#       如果是 文件流对象, 则把文件内容当做 bytes 直接发送到请求 Body 中, 发送完后需手动关闭文件流。
#
# json:
#       一个可被序列化为 JSON 字符串的 Python 对象(如 字典), 一般用于 POST 请求,
#       序列化后的 JSON 字符串发送到请求 Body 中, 并自动添加请求头:
#       "Content-Type": "application/json"
#
# headers:
#       HTTP 请求头, 字典类型, 如: {"Header1": "Value1", "Header2": "Value2"}, 会覆盖现有的请求头。
#
# cookies:
#       添加到请求头中的 Cookies, 类型: 字典{name1:value1, ...} 或 CookieJar对象。
#       如果传递的是 CookieJar 对象, 则从中提取适合该 URL 请求的 Cookie 添加到请求头中。
#       添加的 Cookie 请求头示例:
#       "Cookie": "name1=value1; name2=value2"
#       响应中返回的 CookieJar 对象为 requests.cookies.RequestsCookieJar,
#       继承自 requests.cookies.cookielib.CookieJar == http.cookiejar.CookieJar。
#
# files:
#       上传文件, 字典类型。
#       一般作为 POST 提交 "multipart/form-data; boundary=xxx" 多部分编码 form 表单中的文件字段,
#       可结合 data 参数同时上传 form 表单的 普通字段 和 文件字段。
#
#       使用了该参数, 自动添加请求头:
#           "Content-Type": "multipart/form-data; boundary=xxx"
#
#       参数传值格式:
#           {"field_name": file-like-objects}
#           {"field_name": ("filename", fileobj)}
#           {"field_name": ("filename", fileobj, "content_type")}
#           {"field_name": ("filename", fileobj, "content_type", custom_headers)}
#       说明: 
#           其中 fileobj 可以用 str/bytes 来代替要上传的文件内容;
#           "filename"     表示显式地设置 该文件字段的 文件名;
#           "content_type" 表示显式地设置 该文件字段的 文件类型;
#           custom_headers 表示显式地设置 该文件字段的 请求头, 值为字典类型;
#           可同时上传多个文件;
#           打开的文件流需要手动关闭。
#
#       参数传值示例:
#           {"f1": open("aa.jpg", "rb")} 提交后表单字段值为: name=f1, filename=aa.jpg
#           {"f1": open("aa.jpg", "rb"), "f2": open("bb.png", "rb")} 同时上传多个文件
#           {"f1": ("bb.jpg", open("aa.jpg", "rb"))} 提交后表单字段值为: name=f1, filename=bb.jpg
#
# auth:
#       身份认证, 传递一个认证对象或元祖, 支持 Basic/Digest/Custom HTTP Auth。
#       参数值传递格式:
#           Basic Auth:  auth=requests.auth.HTTPBasicAuth("user", "pass")
#                        或 
#                        auth=("user", "pass")
#           Digest Auth: auth=requests.auth.HTTPDigestAuth("user", "pass")
#
#       使用示例:
#       resp = requests.get("https://httpbin.org/basic-auth/user/pass", auth=("user", "pass"))
#
# timeout:
#       超时时间, 单位为秒。类型为 float 或 元祖。
#       如果传递一个 float 参数, 则表示服务器在 timeout 秒内没有应答, 则抛出超时异常。
#       也可以传递一个包含 连接超时 和 读取超时 的元祖: (connect timeout, read timeout)
#
# allow_redirects:
#       是否允许重定向。类型为 bool 类型, 默认为 True。
#
# proxies:
#       URL 代理。类型为字典。使用示例: 
#       proxies = {
#           "http": "http://10.10.1.10:3128",
#           "https": "http://10.10.1.10:1080"
#       }
#       requests.get("http://example.org", proxies=proxies)
#
# verify:
#       是否验证证书。类型为 bool 或 str, 默认为 True。
#       bool类型: 表示是否验证服务端的 TLS 证书。
#       str 类型: CA_BUNDLE 文件的路径, 或者包含可信任 CA 证书文件的文件夹路径。
#
# stream:
#       响应内容是否是流数据, 类型为 bool。如果是 False, 响应内容将被立即下载。
#
# cert:
#       客户端证书。类型为 str 或 tuple。
#       str  类型: 指定一个本地证书文件(包含密钥和证书)用作客户端证书, 如 cert="client.pem"
#       tuple类型: 一个包含两个文件路径的元组, 如 cert=("client.cert", "client.key")

1.1 GET 请求示例

import requests

resp = requests.get("http://httpbin.org/get")

print(resp.status_code)                         # HTTP 状态码
print(resp.headers)                             # 响应头
print(resp.cookies)                             # 响应的 cookies
print(resp.content.decode("utf-8"))             # 响应内容

1.2 POST 请求示例

import requests

resp = requests.post("http://httpbin.org/post", data=b"Hello World")

print(resp.status_code)
print(resp.content.decode("utf-8"))

1.3 提交 form 表单示例

import requests

file1 = open("aa.txt", "rb")

resp = requests.post("http://httpbin.org/post", data={"key1": "value1"}, files={"file_key1": file1})

print(resp.content.decode("utf-8"))

file1.close()

2. 响应对象: requests.Response

发出请求后,将返回一个 requests.Response 对象,包含了服务端对 HTTP 请求的响应。

requests.Response API 文档: requests.Response

Response 类的常用方法和字段:

close()
    # 释放链接, 放回连接池。调用该方法后, raw 对象将不能访问。
    # Note: 通常不需要显式地调用该方法。



status_code = None
    # HTTP 响应状态码, 如: 200, 302, 404, 500
    # 可以使用内置的状态码常量, 如: requests.codes.OK, requests.codes.NOT_FOUND

reason = None
    # HTTP 响应状态吗对应的名称, 如: "OK", "Not Found"

ok
    # 如果 status_code 小于 400, 则返回 True

raise_for_status()
    # 抛出的 HTTPError, 如果发生 HTTPError, 将被存储。

url = None
    # 响应的最终 URL 位置

headers = None
    # 不区分大小写的响应头的字典。获取指定响应头的值: headers["header_name"]
    # 例如 headers["content-encoding"] 和 headers["Content-Encoding"],
    # 均返回 Content-Encoding 响应头对应的值

cookies = None
    # 服务端响应中返回的 CookieJar 对象, 类型为 requests.cookies.RequestsCookieJar,
    # 继承自 requests.cookies.cookielib.CookieJar == http.cookiejar.CookieJar
    # 获取指定 cookie 的值: cookies.get("name") 或 cookies["name"]
    # 获取所有 cookie 的值: cookies.items(), 返回 [(name, value), ...]

apparent_encoding
    # 响应内容的表观编码, 由 chardet 库提供



content
    # 字节类型的响应内容

text
    # Unicode 表示的响应内容。
    # 如果 Response.encoding 为 None, 将使用猜到的 chardet 解码。

json(**kwargs)
    # 返回响应的 JSON 编码内容(如果有)



raw = None
    # 响应的文件流对象(用于高级用法), 使用该字段需要在请求时传递参数: stream=True

iter_content(chunk_size=1, decode_unicode=False)
    # 遍历响应数据。需要在请求时添加参数 stream=True, 该方法可避免将较大的响应立即读取到内存中。
    # chunk_size 为本次应该读取的最大字节数, 最后一次可能达不到该数量。
    # 
    # chunk_size 必须为 int 或 None 类型。
    #
    # chunk_size 为 None 时。如果 stream=True, 将以达到接收到的块的大小读取数据。
    # 如果 stream=False, 则将数据作为单个块返回。
    #
    # 如果 decode_unicode=True, 则将基于响应使用最佳的可以用编码对内容进行解码。

iter_lines(chunk_size=512, decode_unicode=None, delimiter=None)
    # 遍历响应数据, 一次读取一行。需要在请求时添加参数 stream=True, 
    # 该方法可避免将较大的响应立即读取到内存中。
    # Note: 此方法不是可重入的安全方法。



is_redirect
    # 此响应是一个格式正确的 HTTP 重定向, 并且可能已经被自动处理, 则为 True

is_permanent_redirect
    # 如果此响应是重定向的永久版本之一, 则为 True

history = None
    # 请求的历史响应对象列表。任何重定向都将在此处结束。该列表从最早的请求到最新的请求进行排序。

next
    # 如果有重定向请求, 则 next 为下一个请求返回的 PreparedRequest 对象



request = None
    # 作为响应的 PreparedRequest 对象

links
    # 返回响应的已解析头链接(如果有)

elapsed = None
    # 从发送请求到响应到达之间经过的时间(以时间增量为单位, 如 0:00:00.306239)
    # 类型为 <class 'datetime.timedelta'>
    # 此属性专门用于测试发送请求到第一个字节与头解析之间所需要的时间。
    # 此属性不会因为使用响应内容或 stream 参数值而受影响。

encoding = None
    # 当访问 r.txt 时用于解码的编码格式

2.1 GET 请求示例

import requests

resp = requests.get("http://httpbin.org/get")

# 响应内容编码
print(resp.apparent_encoding)

# 解码字节类型的响应内容
print(resp.content.decode(resp.apparent_encoding))

# 直接使用已解码的响应内容
print(resp.text)

2.2 下载大文件示例

import requests

# 文件保存位置
file = open("aa.jpg", "wb")

# 发出请求
resp = requests.get("http://example/aa.jpg", stream=True)

# 逐块读取响应数据
for bs in resp.iter_content(1024):
    # 数据写入文件
    file.write(bs)

# 关闭文件
file.close()

3. Cookie处理: requests.cookies.RequestsCookieJar

requests.cookies.RequestsCookieJar 用于处理 rquests 模块请求/响应的 cookies, 继承自 requests.cookies.cookielib.CookieJar(即http.cookiejar.CookieJar)。

RequestsCookieJar API文档: requests.cookies.RequestsCookieJar

3.1 RequestsCookieJar 常用方法

# RequestsCookieJar 构造方法
class requests.cookies.RequestsCookieJar(policy=None)


# 获取一个 cookie 的值
def get(name, default=None, domain=None, path=None)

# 获取符合 domain 和 path 规则的所有 cookie, 返回一个字典
def get_dict(domain=None, path=None)


# 返回所有 Cookie 的 name 和 value 元祖组成的列表, 
# 例如: [(name1, value1), (name2, value2), ...]
def items()

# 返回所有 Cookie 的 name 组成的列表, 例如: [name1, name2, ...]
def keys()

# 返回所有 Cookie 的 domain 组成的列表, 例如: [domain1, domain2, ...]
def list_domains()


# 设置一个 cookie, 指定名称和值, 还可以设置其他 cookie 参数
# kwargs 参数可选(右边为默认值):
#       version: 0
#       name: name
#       value: value
#       port: None
#       domain: ""
#       path: "/"
#       secure: False
#       expires: None
#       discard: True
#       comment: None
#       comment_url: None
#       rest: {"HttpOnly": None}
#       rfc2109: False
def set(name, value, **kwargs)

# 手动设置一个 Cookie
def set_cookie(cookie: http.cookiejar.Cookie)

# 遍历 Cookie
for cookie in requestsCookieJar:
    # 这里 cookie 的类型为 http.cookiejar.Cookie
    print(cookie.name + "=" + cookie.value)


# 更新 CookieJar, 把 other 更新(覆盖)到 self 中
# other 为 requests.cookies.cookielib.CookieJar对象(即 http.cookiejar.CookieJar)
# 例如, 把从文件中读取到的 FileCookieJar 更新到 RequestsCookieJar 中。
def update(other)


# 清理过期的 Cookie
def clear_expired_cookies()
# 清理一些 Cookie
def clear(domain=None, path=None, name=None)
# 清理会话 Cookie
def clear_session_cookies()

3.2 获取响应中的 Cookies

>>> import requests
>>> 
>>> # 发送请求(响应中将会设置一个cookie: hello=world)
>>> resp = requests.get("http://httpbin.org/cookies/set/hello/world", allow_redirects=False)
>>> 
>>> # 响应的 resp.cookies 为 RequestsCookieJar 类型
>>> resp.cookies.get("hello")
'world'
>>> resp.cookies["hello"]
'world'
>>> resp.cookies.items()
[('hello', 'world')]
>>> resp.cookies.keys()
['hello']

3.3 请求中添加 Cookie

>>> import requests
>>> cookies = {"key1": "value1", "key2": "value2"}
>>> resp = requests.get("http://httpbin.org/cookies", cookies=cookies)
>>> resp.text
'{"cookies": {"key1": "value1", "key2": "value2"}}'

3.4 请求中添加 RequestsCookieJar

>>> import requests
>>> 
>>> cookieJar = requests.cookies.RequestsCookieJar()
>>> cookieJar.set("key1", "value1", domain=".httpbin.org", path="/cookies")
>>> cookieJar.set('key2', 'value2', domain=".httpbin.org", path="/hello")
>>> 
>>> resp = requests.get("http://httpbin.org/cookies", cookies=cookieJar)
>>> resp.text
'{"cookies": {"key1": "value1"}}'

3.5 利用 RequestsCookieJar 手动保持会话

import requests

# 创建一个 CookieJar 管理 Cookies
cookieJar = requests.cookies.RequestsCookieJar()

# 发送请求(响应中将会设置一个cookie: hello=world)
resp = requests.get("http://httpbin.org/cookies/set/hello/world", allow_redirects=False)

# 把响应中的 cookies 更新到 cookieJar 中保存
cookieJar.update(resp.cookies)

# 再次发出请求时, 携带上 cookieJar 将自动添加合适的 Cookies
resp = requests.get("http://httpbin.org/cookies", cookies=cookieJar)
print(resp.text)

# 打印的结果:
"""
{
  "cookies": {
    "hello": "world"
  }
}
"""

这种方式自动重定向的响应 Cookies 无法处理,还是需要使用自动保持会话,参考下面的「自动保持会话: requests.Session」的介绍。

3.6 RequestsCookieJar 的文件保存和读取

import requests
import http.cookiejar


def save_cookies(cookieJar, filename):
    """
    保存 Cookies 到文件, 使用 MozillaCookieJar 保存
    :param cookieJar: CookieJar 对象
    :param filename: 文件路径
    """
    # 创建一个 FileCookieJar 对象
    fileCookieJar = http.cookiejar.MozillaCookieJar()

    # 遍历 CookieJar, 将 Cookie 逐个添加到 fileCookieJar 中
    for cookie in cookieJar:
        fileCookieJar.set_cookie(cookie)

    # 保存到文件中(忽略丢弃)
    fileCookieJar.save(filename, ignore_discard=True)


def load_cookies(filename):
    """
    从 MozillaCookieJar 格式的 Cookies 文件中加载 Cookies, 返回 RequestsCookieJar 对象
    :param filename: 文件路径
    """
    # 创建一个 FileCookieJar 对象
    fileCookieJar = http.cookiejar.MozillaCookieJar()

    # 从文件加载 Cookies(忽略丢弃)
    fileCookieJar.load(filename, ignore_discard=True)

    # 创建 RequestsCookieJar 对象
    requestsCookieJar = requests.cookies.RequestsCookieJar()

    # 将 fileCookieJar 更新到 RequestsCookieJar 中
    requestsCookieJar.update(fileCookieJar)

    # 返回 RequestsCookieJar
    return requestsCookieJar


def main():
    # Cookies 保存文件路径
    filename = "cookies.txt"

    # 创建 RequestsCookieJar 管理 Cookies
    cookieJar = requests.cookies.RequestsCookieJar()

    # 手动设置几个 Cookie
    cookieJar.set("key1", "value1", domain=".httpbin.org", path="/cookies", discard=False)
    cookieJar.set('key2', 'value2', domain=".httpbin.org", path="/hello", discard=False)

    # 发送请求(响应中将会设置一个cookie: hello=world)
    resp = requests.get("http://httpbin.org/cookies/set/hello/world", allow_redirects=False)

    # 把响应的 Cookies 也保存到 cookieJar 中
    cookieJar.update(resp.cookies)

    # 保存 cookieJar 到文件中
    save_cookies(cookieJar, filename)


    # --------------------------------------------------------------------------------------


    # 从文件中加载 Cookies
    cookieJar = load_cookies(filename)

    # 发送请求, 携带上 cookieJar 将自动添加合适的 Cookies
    resp = requests.get("http://httpbin.org/cookies", cookies=cookieJar)
    print(resp.text)

    # 打印的结果
    """
    {
      "cookies": {
        "hello": "world", 
        "key1": "value1"
      }
    }
    """


if __name__ == "__main__":
    main()

4. 自动保持会话: requests.Session

Session 对象能够跨请求保持某些参数(例如: 请求头)。它也会再同一个 Session 实例发出的所有请求之间保持 Cookies(自动保存/添加 Cookies)。Session 请求期间使用 urllib3 的连接池功能,所以向同一个主机发送多个请求,底层的 TCP 链接将被重用,从而达到性能提升的效果。

requests.get()、requests.post()、requests.request() 等所有 request 的请求,实际上也是先创建 Session,然后由 Session 发出请求,请求完毕后再关闭会话。代码如下:

with sessions.Session() as session:
    return session.request(method=method, url=url, **kwargs)

Session 拥有的请求方法与 requests 相同,如: session.get()、session.post()、session.request() 等,其传入的参数格式也相同。

请求添加固定请求头 和 Cookies 保持:

import requests

# 创建会话对象
session = requests.Session()

# session 对象创建后, session.headers 和 session.cookies 均已有值, 直接添加数据即可。
# session.headers 类型为 requests.structures.CaseInsensitiveDict
# session.cookies 类型为 requests.cookies.RequestsCookieJar

# 添加固定请求头
session.headers.update({"User-Agent": "hello/world", "X-Test": "Test-Value"})
# 输出请求头
print(session.headers)

# 手动设置 Cookie 到 session 中
session.cookies.set("key1", "value1", domain="httpbin.org", path="/")

# 发送请求(响应中将会设置一个cookie: hello=world)
resp = session.get("http://httpbin.org/cookies/set/hello/world")
print(resp.text)

# 发出请求(将自动携带 固定请求头 和 Cookies)
resp = session.get("http://httpbin.org/cookies")
print(resp.text)

# 发出请求(将自动携带固定请求头和Cookies)
resp = session.get("http://httpbin.org/get")
print(resp.text)

# 关闭会话
session.close()

PS: Session.cookies 中的类型为 RequestsCookieJar,可以将其保存到文件,也可以从文件中读取 Cookies 后更新到 RequestsCookieJar 中。

 类似资料: