【Python基础】requests库

requests 是一个非常流行的 Python HTTP 第三方库,它允许你发送各种 HTTP 请求,处理 cookies、会话、连接池、重定向、多种认证方式等,使得处理 HTTP 请求变得非常便捷。

安装 Requests 库

首先,确保你已经安装了 requests 库。如果没有,可以通过 pip 安装:

pip install requests

导入 Requests 模块

在使用前需要先导入 requests 模块:

import requests

一、HTTP请求概览

▶ 常用方法

requests 库提供了一个简单易用的 API 来发送 HTTP 请求。以下是一些基本的请求方法:

  • get(url, **kwargs): 发送一个GET请求。
  • post(url, data=None, **kwargs): 发送一个POST请求,data可以是字典、字节或文件对象。
  • put(url, data=None, **kwargs): 发送一个PUT请求。
  • delete(url, **kwargs): 发送一个DELETE请求。
  • head(url, **kwargs): 发送一个HEAD请求,只获取页面的HTTP头信息。
  • options(url, **kwargs): 发送一个OPTIONS请求,获取服务器支持的HTTP方法。
  • patch(url, data=None, **kwargs): 发送一个PATCH请求。
    import requests  # 引入requests库
    
    payload = {'key1': 'value1', 'key2': 'value2'}
    
    response = requests.get('http://example.com')
    response = requests.post('http://example.com/submit', data=payload)
    response = requests.put('http://example.com/put', data={'key': 'value'})
    response = requests.delete('http://example.com/delete')
    response = requests.head('http://example.com/get')
    

▶ 常用参数

使用 requests 库时,除了必填的 url 参数,你可以选填其他参数来自定义请求:

  1. headers: 字典,用于自定义HTTP请求头。
  2. cookies: 字典,或 RequestsCookieJar 对象,包含 cookies。
  3. auth: 元组,用于HTTP认证的凭据。第一个元素是用户名,第二个元素是密码。
  4. params: 字典,用于将表单数据附加到URL的查询字符串中(GET、POST请求)。
  5. data: 字典或类似字典的对象,用于表单数据的提交。(POST、PUT请求)
  6. json: 字典或类似字典的对象,用于发送JSON数据。(POST、PUT请求)
  7. files: 字典{'表单字段名': ('文件名', 文件对象)},用于上传文件。(POST请求)
  8. stream: 布尔值,用于流式下载。默认值False,为True逐块读取响应体减少内存使用。
  9. timeout: 浮点数或元组,用于指定请求的超时时间(秒)。默认无限期地等待。
  10. verify: 布尔值,或到CA证书包的路径。默认值True,为False不验证服务器SSL证书。
  11. cert: 字符串或元组,用于传递客户端证书文件的路径,或者证书和私钥文件的路径。
  12. allow_redirects: 布尔值,是否允许重定向。默认为True允许重定向。
  13. proxies: 字典,用于配置代理。

▶ 其他功能

除了这些基本的HTTP方法,requests库还提供了以下功能:

  • Session对象:允许你跨请求保持某些参数,例如cookies。
  • Response对象:包含服务器响应的所有信息,如状态码、文本内容、headers等。
  • RequestException:当请求遇到问题时抛出的异常。
  • Timeout:用于设置请求的超时时间。
  • TooManyRedirects:当请求重定向次数超过设定值时抛出的异常。
  • Request:用于创建一个请求对象,可以自定义请求的各个方面。

二、请求参数示例

  1. headers:
  • 字典,用于自定义HTTP请求头。
    headers = {'User-Agent': 'Mozilla/5.0 (compatible; YourBot/0.1)'}
    response = requests.get('http://example.com', headers=headers)
    
  1. cookies:
  • 字典,或 RequestsCookieJar 对象,包含 cookies。
    cookies = {'session_token': '123456789'}
    response = requests.get('http://example.com', cookies=cookies)
    
  1. auth:
  • 元组,用于HTTP认证的凭据。第一个元素是用户名,第二个元素是密码。requests 库会自动将这些认证信息编码并附加到请求的 HTTP 头中。
    注意事项
    ▋ 确保在发送认证信息时使用安全的连接(HTTPS),以避免认证信息在传输过程中被截获。
    ▋ 某些服务器可能不支持所有类型的 HTTP 认证,因此在使用前应确认服务器支持的认证方式。
    ⑴ 基本认证(Basic Auth)
    # 定义认证信息
    username, password = 'user', 'pass'
    # 使用基本认证发起 GET 请求
    auth = (username, password)
    response = requests.get('http://example.com', auth=auth)
    
    ⑵ 摘要认证(Digest Auth)
    from requests.auth import HTTPDigestAuth
    
    username, password = 'user', 'pass'
    # 使用摘要认证发起 GET 请求
    auth = HTTPDigestAuth(username, password)
    response = requests.get('http://example.com', auth=auth)
    
    ⑶ 令牌认证(Token Auth)
    # 定义令牌
    token = 'your_access_token'
    # 定义请求头,包含令牌
    headers = {'Authorization': f'Token {token}'}
    # 使用令牌认证发起 GET 请求
    response = requests.get('http://example.com/protected', headers=headers)
    
  1. params:
  • 字典或类似字典的对象,用于将表单数据附加到URL的查询字符串中(GET、POST请求)。
    requests库会自动对params进行URL编码,确保参数值中的空格、特殊字符等被正确处理,并附加到 URL 上。
    params = {
        # 字典的值为列表
        'key1': ['value1', 'value2'],  # 如果需要为一个键传递多个值,可以在字典中使用列表
        # 字典的值为字典列表
        'key3': [{'subkey1': 'subvalue1'}, {'subkey2': 'subvalue2'}],
        # 字典的键值是元组
        ('key4','key5'): ('subvalue4','subvalue5'),
        'key6': 'value6'
    }
    
    response = requests.get('https://httpbin.org/get', params=params)
    # 查看响应内容
    print(response.text)
    
    ''' 打印响应对象的文本内容url的值如下:
    "url": "https://httpbin.org/get?key1=value1&key1=value2&key3=subkey1&key3=subkey2
    &('key4'%2C+'key5')=subvalue4&('key4'%2C+'key5')=subvalue5&key6=value6"
    '''
    
  1. data:
  • 字典或类似字典的对象,用于表单数据的提交。(POST、PUT请求)
    requests库会自动设置Content-Typeapplication/x-www-form-urlencoded。如果指定了headers中的Content-Typeapplication/json,则data将被序列化为JSON格式。
    ⑴ 使用表单数据发送POST请求
     # 定义表单数据
     data = {
         'key1': 'value1',
         'key2': ['value2', 'value3']
     }
    response_form = requests.post('https://httpbin.org/post', data=data)
    
    ⑵ 使用json数据发送POST请求
    import json
    headers = {'Content-Type': 'application/json'}
     data = {
         'key1': 'value1',
         'key2': ['value2', 'value3']
     }
    # 将字典转换为JSON字符串(需要 import json)
    json_data = json.dumps(data)
    response_json = requests.post('https://httpbin.org/post', headers=headers, data=json_data)
    
    ⑶ 对于大文件,可以使用流式上传文件以节省内存:
    with open('large_file.zip', 'rb') as file:
        response = requests.post('https://httpbin.org/post', data=file)
    
  1. json:
  • 字典或类似字典的对象,用于发送JSON数据。(POST、PUT请求)
    requests库会自动设置 Content-Typeapplication/json
    response = requests.post('https://httpbin.org/post', json={'key1': 'value1'})
    
  1. files:
  • 字典{'表单字段名': ('文件名', 文件对象)},用于上传文件。(POST请求)
    requests库会自动设置Content-Typemultipart/form-data,这是文件上传的标准格式。
    • 键:是是表单字段名,相当于HTML表单中的name属性。
    • 值:是一个元组。第一个元素是文件名(在服务器上保存的名称),第二个元素是文件对象(可以使用open()函数打开文件并获取文件对象)。
      为什么通常不建议省略文件名:
      1. 服务器端处理:服务器端的代码通常依赖于文件名来保存上传的文件。如果没有提供文件名,服务器可能无法正确处理文件,或者会使用默认的文件名,这可能不是你想要的。
      2. 内容识别:文件名可以提供关于文件内容类型的线索,有助于服务器端正确处理文件(例如,根据文件扩展名设置正确的 Content-Type)。
      3. 避免冲突:如果多个文件上传到同一个服务器端路径,明确的文件名可以避免命名冲突。
      4. 如果省略了文件名,服务器接收到的文件名将是文件对象的名称,如report.xls。
    ⑴ 直接在files字典中使用open函数打开文件
    files = {
        'file': open('report.xls', 'rb'),
        'photo': open('image.jpg', 'rb')
    }
    
    try:
        response = requests.post('https://httpbin.org/post', files=files)
    
    finally:  # 无论请求是否成功或是否发生异常,文件对象都会被关闭。
        # 没有使用with语句,文件对象在上传完成后需要手动关闭,否则可能会导致文件泄露。
        for file in files.values():
            file.close()  # 确保每个文件都被关闭
    
    ⑵ 使用with语句来打开文件
    # with语句可以确保在代码块执行完毕后,文件正确关闭,即使在上传过程中发生异常也是如此。
    with open('report.xls', 'rb') as f:
        # files字典的值是一个元组,其中第二个元素是文件对象f
        files = {'file': ('report.xls', f)}
        response = requests.post('https://httpbin.org/post', files=files)
    
  1. stream:
  • 布尔值,用于流式下载。默认值False,立即下载整个响应体数据加载到内存中。
    如果设置为True,则响应内容不会被立即下载,requests会提供一个可迭代的文件类对象,支持逐块读取响应体。适用于处理大文件或流式数据,以减少内存的使用。
    注意:流式上传,通常不需要特别设置stream参数,通过将文件对象传递给data参数来实现。
    # 使用`stream=True`时,使用`with`语句确保在处理完响应后关闭响应对象,以释放底层的TCP连接。
    with requests.get('https://httpbin.org/get', stream=True) as response:
        # 使用 iter_content 方法,逐块处理响应体
        for chunk in response.iter_content(chunk_size=150):  # 每次读取150字节
            # 流式下载不会自动解码响应内容。如果需要处理解码后的文本,需要手动解码每个数据块。
            print("Chunk:", chunk)
            # 将字节数据解码为字符串(假设响应内容是UTF-8编码的文本)
            text = chunk.decode('utf-8', errors='ignore')  # 使用忽略错误的方式解码
            print("Text:", text, "\n")  # 处理每一块数据
    
    流式下载文件:
    with requests.get('https://example.com/largefile.zip', stream=True) as response:
        with open('localfile.zip', 'wb') as out_file:
            for chunk in response.iter_content(chunk_size=8192):
                out_file.write(chunk)
    
  1. timeout
  • 浮点数或元组,用于指定请求的超时时间(秒)。默认无限期地等待。
    可使用try...except块来捕获Timeout异常,以便在请求超时时进行适当的错误处理。
    try:
        response = requests.get('http://example.com', timeout=5)  # 整数,5秒超时
        response = requests.get('http://example.com', timeout=0.5)  # 浮点数,0.5秒超时
        # timeout是元组时,用于指定连接超时时间和读取超时时间 (timeout_connect,timeout_read) 。
        response = requests.get('http://example.com', timeout=(2, 5))  # 元组,2秒连接超时,5秒读取超时
    except requests.exceptions.Timeout:
        print("请求超时")
    
  1. verify
  • 布尔值,或到CA证书包的路径,用于控制是否验证服务器的SSL 证书。默认值True
    如果服务器证书验证失败,requests将抛出一个requests.exceptions.SSLError异常。
    # 验证服务器SSL证书
    response = requests.get('https://example.com', verify=True)
    # 不验证服务器SSL证书(不推荐在生产环境中使用)
    response = requests.get('https://example.com', verify=False)
    # 使用自定义CA证书包验证服务器证书
    response = requests.get('https://example.com', verify='/path/to/cacert.pem')
    
  1. cert:
  • 字符串或元组,用于传递客户端证书和私钥文件的路径。
    通常,certverify参数一起使用,以确保客户端和服务器之间的通信是安全和加密的。
    # 只传递证书文件,字符串:.pem格式的证书文件路径
    response = requests.get('https://example.com', cert='/path/to/cert.pem')
    # 传递证书文件和私钥文件,元组:(.pem格式的证书文件路径,.pem格式的私钥文件路径)
    response = requests.get('https://example.com', cert=('/path/to/cert.pem', '/path/to/key.pem'))
    
  1. allow_redirects
  • 布尔值,是否允许重定向,默认值True允许重定向。
    requests默认允许最多30次重定向,超出限制抛出requests.exceptions.TooManyRedirects异常。
    ⑴ 允许重定向
    requests会自动跟随重定向响应(如301、302、303、307、308状态码)直到最终的响应。
    response = requests.get('https://httpbin.org/redirect/1', allow_redirects=True)
    
    print("【url】", response.url)  # 打印最终的URL
    # 设置allow_redirects=True,重定向历史的第一个对象的请求URL即为原始请求
    if response.history: 
        print("【request.url】", response.history[0].request.url)  # 打印原始请求的URL
    print("【text】", response.text)  # 打印最终响应的文本
    print("【content】", response.content)  # 打印最终响应的原始二进制内容
    print("【history】", response.history)  # 打印重定向历史
    # 打印重定向历史所有对象的请求URL和最终URL
    for redirect in response.history:
        print("【redirect.request.url】", redirect.request.url)
        print("【redirect.url】", redirect.url)
    print("【status_code】", response.status_code)  # 打印最终响应的状态码
    
    ⑵ 不允许重定向
    requests不自动跟随重定向,返回一个包含重定向请求信息的响应对象。
    response = requests.get('https://httpbin.org/redirect/1', allow_redirects=False)
    
    print("【url】", response.url)  # 打印最终的URL
    # 设置allow_redirects=False,无重定向历史,不会打印原始请求
    if response.history: 
        print("【request.url】", response.history[0].request.url)  # 不会打印原始请求的URL
    print("【text】", response.text)  # 打印最终响应的文本
    print("【content】", response.content)  # 打印最终响应的原始二进制内容
    print("【history】", response.history)  # 打印重定向历史
    print("【status_code】", response.status_code)  # 打印最终响应的状态码
    
  1. proxies
  • 字典,用于配置代理。
    proxies = {
        'http': 'http://10.10.1.10:3128',
        'https': 'http://10.10.1.10:1080',
    }
    response = requests.get('http://example.com', proxies=proxies)
    

三、 响应对象(Response)

requests 请求返回的 response 对象包含了服务器响应的所有信息:

  • response.status_code:最终响应的HTTP状态码。
  • response.text:解码后的文本内容(Unicode字符串)。
  • response.content:最终响应的原始字节序列(bytes对象),多用于处理非文本响应。
  • response.json():如果预期响应是 JSON 格式,可以使用该方法直接解析为 JSON 对象。
  • response.url:实际请求的最终 URL(考虑了重定向)。
  • response.headers:响应头。
  • response.cookies:服务器发送的 cookies。
  • response.history:列表,包含所有重定向的响应对象。

注:
1. 编码和解码:将Unicode字符串转换为字节序列称为编码。将字节序列转换回Unicode字符串称为解码。
2. Unicode字符串:表示文本数据,包括但不限于拉丁字母、汉字、阿拉伯字母、梵文等。
3. 字节序列:可以表示文本数据,也可以表示二进制数据,如图片、音频、视频文件等。在Python中用bytes类型表示字节序列。例如b'Hello, \xe4\xb8\x96\xe7\x95\x8c!'表示文本数据'Hello, 世界!'

  # 文本数据(Unicode字符串)
  text = "Hello, 世界!"

  # 采用UTF-8编码后的字节序列
  b = text.encode('utf-8')  
  print("byte sequence:",b)  # 输出: b'Hello, \xe4\xb8\x96\xe7\x95\x8c!'

  # 采用UTF-8解码后的文本数据(Unicode字符串)
  s = b.decode('utf-8')
  print("Unicode string:",s)  # 输出:Hello, 世界!

四、异常处理(RequestException)

使用 requests 发起请求后,应该首先检查响应的状态码以确定请求是否成功。这可能会遇到各种异常,如连接错误、超时等。你可以使用 try-except 语句来捕获这些异常:

def get_soup(url, headers):
    """获取网页内容并返回BeautifulSoup对象"""
    try:
        # 确保URL以http开头
        url = url.replace('https://', 'http://') if url.startswith('https://') else url
        with requests.get(url, headers=headers, timeout=10, verify=False) as response:
            response.raise_for_status()
            return BeautifulSoup(response.content, "html.parser")
    # 响应的状态码不是 200 时抛出
    except requests.exceptions.HTTPError as e:
        print(f"HTTP error: {e.response.status_code} - {e}")
    # 连接问题时抛出
    except requests.exceptions.ConnectionError:
        print("Error connecting to the server.")
    # 请求超时时抛出
    except requests.exceptions.Timeout:
        print("Request timed out.")
    # 所有请求相关的异常的基类
    except requests.exceptions.RequestException as e:
        print(f"Request error: {e}")
    return None

五、会话和持久连接(Session)

Session 对象允许你通过一个持久的连接来发送多个请求,这可以提高性能,因为它减少了重复连接服务器的开销。使用 requests.Session 可以在多个请求之间保持某些参数,如 cookies:

with requests.Session() as session:
    session.headers.update({'x-test': 'true'})
    response = session.get('https://httpbin.org/get', params={'key': 'value'})

以下是 requests.Session() 的详细说明和用法:

基本用法

创建一个 Session 对象:

import requests
session = requests.Session()

使用 Session 对象发起请求:

response = session.get('http://example.com')

会话的用途

  1. 保持参数Session 对象允许你设置一些参数一次,然后对多个请求重用这些参数。
  2. 保持 CookiesSession 会自动处理 Cookies,保持用户会话。
  3. 连接池Session 使用连接池来管理持久连接,这可以显著提高性能。
  4. 会话头部:可以为会话设置自定义头部,这些头部会自动应用于会话中的所有请求。

常用方法和属性

  • session.headers:设置会话级别的请求头部。
  • session.cookies:管理会话中的 Cookies。
  • session.auth:设置会话级别的 HTTP 认证信息。
  • session.proxies:设置会话级别的代理。
  • session.hooks:注册会话级别的请求和响应钩子。
  • session.get(url, **kwargs):发起 GET 请求。
  • session.post(url, data=None, **kwargs):发起 POST 请求。
  • session.put(url, data=None, **kwargs):发起 PUT 请求。
  • session.delete(url, **kwargs):发起 DELETE 请求。
  • session.request(method, url, **kwargs):发起任意类型的请求。
  • session.close():关闭会话,释放资源。

示例

使用会话发起多个请求:

session = requests.Session()
session.headers.update({'User-Agent': 'my-app/0.0.1'})

response1 = session.get('http://example.com/get1')
response2 = session.get('http://example.com/get2')

# 会话中的请求将共享相同的参数,如 headers 和 cookies

使用会话进行文件上传:

with open('report.xls', 'rb') as f:
    files = {'file': f}
    session.post('http://example.com/upload', files=files)

使用会话进行持久连接:

session = requests.Session()
session.mount('http://', requests.adapters.HTTPAdapter(pool_connections=10, pool_maxsize=10))

response = session.get('http://example.com')

在这个例子中,我们使用 mount 方法来挂载一个 HTTP 适配器,该适配器使用连接池来管理持久连接。

注意事项

  • 使用 Session 对象时,确保在完成所有请求后调用 session.close() 来关闭会话,释放资源。
  • Session 对象是线程安全的,可以在多线程环境中使用。

requests.Session() 提供了一个高效的方式来管理多个 HTTP 请求,特别是在需要保持状态(如 Cookies)或重用参数的情况下。通过使用会话,你可以简化代码并提高应用程序的性能。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,076评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,658评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,732评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,493评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,591评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,598评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,601评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,348评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,797评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,114评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,278评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,953评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,585评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,202评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,180评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,139评论 2 352

推荐阅读更多精彩内容