当前位置: 首页 > article >正文

Python爬虫(二)- Requests 高级使用教程

文章目录

  • 前言
  • 一、Session 对象
    • 1. 简介
    • 2. 跨请求保持 Cookie
    • 3. 设置缺省数据
    • 4. 方法级别参数不被跨请求保持
    • 5. 会话作为上下文管理器
    • 6. 移除字典参数中的值
  • 二、请求与响应
    • 1. 请求与响应对象
      • 1.1 获取响应头信息
      • 1.2 获取发送到服务器的请求头信息
  • 三、SSL 证书验证
    • 1. 忽略 SSL 证书验证
  • 四、流式上传和请求
    • 1. 流式上传
    • 2. 流式请求
      • 2.1 流式请求和普通请求的区别
      • 2.2 示例
        • 2.2.1 iter_lines() 使用
        • 2.2.2 iter_content() 使用
  • 五、代理
    • 1. 获取免费代理地址
    • 2. 使用代理配置单个请求
    • 3. 使用代理池
    • 4. 使用 HTTP Basic Auth 的代理
    • 5. 针对特定主机或连接方式设置代理
  • 六、编码方式
    • 1. 编码方式处理
      • 1.1 自动检测编码
      • 1.2 手动设置编码
      • 1.3 使用原始字节数据
  • 七、身份认证
    • 1. 基本身份认证 (HTTP Basic Auth)


前言

在现代网络应用中,HTTP 请求和响应的处理是至关重要的。Python 的 requests 库以其简洁易用的接口,成为了开发者进行网络请求的首选工具。无论是简单的 GET 请求,还是复杂的身份认证、会话管理、代理设置,requests 都能轻松应对。本文将深入探讨 requests 库的各个方面,包括 Session 对象的使用、请求与响应的处理、SSL 证书验证、流式上传和请求、代理配置、编码方式处理以及身份认证等。


一、Session 对象

1. 简介

Session 对象允许跨多个请求保持某些参数不变。它在同一个 Session 实例发出的所有请求之间保持 cookie,并利用 urllib3 的连接池功能来重用底层的 TCP 连接,从而为向同一主机发送的多个请求提供显著的性能提升。

主要特性:

  • 所有 Requests API 方法:Session 对象拥有主要的 Requests API 的所有方法。
  • 持久性 Cookie 和 Headers:可以跨请求保持某些数据,如认证信息和自定义头部。
  • 连接池复用:对于同一主机的多次请求,能够复用TCP连接,提高效率。

2. 跨请求保持 Cookie

import requests

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

# 设置 Cookie:通过会话发送 GET 请求,设置一个名为 sessioncookie 的 cookie,值为 123456789。
session.get('http://httpbin.org/cookies/set/sessioncookie/123456789')

# 获取 Cookie:再次使用同一个会话发送 GET 请求,获取当前会话中的所有 cookies。
response = session.get("http://httpbin.org/cookies")

# 打印服务器返回的 cookie 信息
print(response.text)

打印的结果为:

{
  "cookies": {
    "sessioncookie": "123456789"
  }
}

3. 设置缺省数据

通过为 Session 对象的属性提供数据,可以为请求方法提供缺省数据,例如认证信息或头部信息。

import requests

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

# 设置会话的认证信息,用户名为 'user',密码为 'pass'
session.auth = ('user', 'pass')

# 更新会话头部信息,添加自定义头 'x-test',其值为 'true'
session.headers.update({'x-test': 'true'})

# 发送 GET 请求到 http://httpbin.org/headers,同时在此请求中添加另一个自定义头 'x-test2'
response = session.get('http://httpbin.org/headers', headers={'x-test2': 'true'})

# 打印服务器返回的响应内容,以查看请求头和其他信息
print(response.text)

打印的结果为:

在这里插入图片描述

任何传递给请求方法的字典都会与已设置会话层数据合并,方法层的参数覆盖会话的参数。

4. 方法级别参数不被跨请求保持

就算使用了 Session,方法级别的参数也不会被跨请求保持。

import requests

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

# 只有第一个请求发送 cookie
response = session.get('http://httpbin.org/cookies', cookies={'from-my': 'browser'})
print(response.text)

# 第二个请求没有 cookie
response = session.get('http://httpbin.org/cookies')
print(response.text)

打印的结果为:

{
  "cookies": {
    "from-my": "browser"
  }
}

{
  "cookies": {}
}

从打印的结果可以看出,重复对同一个地址发起访问,第一个请求设置的 cookie 并没有被保存,所以第二个请求中没有 cookie,也就是说就算使用了 Session,方法级别的参数也不会被跨请求保持。

5. 会话作为上下文管理器

为了确保会话在完成后能被正确关闭,可以使用它作为上下文管理器。这样就能确保 with 区块退出后会话能被关闭,即使发生了异常也一样。

import requests

with requests.session() as session:
    response = session.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
    print(response.text)

打印的结果为:

{
  "cookies": {
    "sessioncookie": "123456789"
  }
}

6. 移除字典参数中的值

可以通过在方法级别的参数中将键的值设置为 None 来移除会话层字典参数中的某个键,从而让该键不会被发送。


二、请求与响应

1. 请求与响应对象

任何时候当你调用 requests.get() 或其他类似方法时,实际上你在执行两个主要操作:构建一个 Request 对象以向服务器请求或查询资源;以及接收一个从服务器返回的 Response 对象。这个 Response 对象包含了来自服务器的所有信息,并且也包含了你最初创建的 Request 对象。

1.1 获取响应头信息

import requests

url = 'http://www.baidu.com'

response = requests.get(url)

print(response.headers)

打印的结果为:

在这里插入图片描述

1.2 获取发送到服务器的请求头信息

import requests

url = 'http://www.baidu.com'

response = requests.get(url)

print(response.request.headers)

打印的结果为:

{'User-Agent': 'python-requests/2.31.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}

三、SSL 证书验证

Requests 可以为 HTTPS 请求验证 SSL 证书,就像 web 浏览器一样。SSL 验证默认是开启的,如果证书验证失败,Requests 会抛出 SSLError

1. 忽略 SSL 证书验证

在某些特殊情况下,比如在测试环境中或者你信任但证书不受信任的情况下,你可能想要忽略 SSL 证书验证。

import requests
from urllib3.exceptions import InsecureRequestWarning

url = 'https://example.com'

# 禁用不安全请求警告
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)

# 忽略 SSL 证书验证
response = requests.get(url, verify=False)
print(response.status_code)

四、流式上传和请求

1. 流式上传

Requests支持流式上传,这允许你发送大的数据流或文件而无需先把它们读入内存。要使用流式上传,仅需为你的请求体提供一个类文件对象即可。

with open('massive-body', 'rb') as f:
    requests.post('http://some.url/streamed', data=f)

data=f:这里将文件对象 f 直接赋值给了 data 参数。这意味着 requests 将会逐块读取文件内容,并通过 HTTP 请求进行流式传输。这样做的好处是,即使文件非常大,也不会占用过多的内存,因为数据是一部分一部分地发送出去的。

2. 流式请求

2.1 流式请求和普通请求的区别

流式请求(Streaming Requests)和普通请求(Non-streaming Requests)是使用 requests 库进行 HTTP 请求的两种不同方式,它们在处理响应内容时有着显著的区别。下面我们将详细介绍这两种请求类型,并说明其适用场景。

普通请求

  • 一次性读取:当发起一个普通的 GET 或 POST 请求时,requests 会立即将整个响应体下载到内存中。这意味着如果响应体很大,可能会占用大量的内存。

  • 简单易用:对于小文件或轻量级的数据交换,这种方式非常方便,因为它不需要额外的配置就可以直接获取完整的响应内容。

流式请求

  • 逐块读取:通过设置参数 stream=True,你可以告诉 requests 不要立即下载整个响应体。相反,它会在需要时逐步从网络流中读取数据。这允许你处理超大文件或长时间运行的数据流,而不会一次性占用大量内存。

  • 节省资源:流式请求非常适合于处理大型文件、长连接 API 响应或者实时数据流,因为你可以一边接收数据一边处理,从而有效管理资源。

  • 更复杂的逻辑:由于数据是分块到达的,你需要编写额外的代码来处理这些数据块,例如将它们写入文件或进行增量处理。

流式请求迭代器方法

  • iter_content():以字节为单位返回响应内容的迭代器。可以指定 chunk_size 参数来控制每次读取的大小。

  • iter_lines():以行为单位返回响应内容的迭代器,适用于按行处理的文本响应。

2.2 示例

2.2.1 iter_lines() 使用
import json
import requests

# 发送 GET 请求到指定的 URL,使用 stream=True 以便逐行读取响应内容
response = requests.get('http://httpbin.org/stream/20', stream=True)

# 检查响应的编码,如果未设置,则将其设置为 'utf-8'
if response.encoding is None:
    response.encoding = 'utf-8'

# 逐行迭代响应内容,使用 decode_unicode=True 将内容解码为字符串
for line in response.iter_lines(decode_unicode=True):
    # 检查当前行是否非空
    if line:
        # 将 JSON 格式的字符串解析为 Python 对象并打印
        print(json.loads(line))

iter_lines 不保证重进入时的安全性。多次调用该方法 会导致部分收到的数据丢失。如果要在多处调用它,应该使用生成的迭代器对象。

import json
import requests

# 发送 GET 请求到指定的 URL,使用 stream=True 以便逐行读取响应内容
response = requests.get('http://httpbin.org/stream/20', stream=True)

# 检查响应的编码,如果未设置,则将其设置为 'utf-8'
if response.encoding is None:
    response.encoding = 'utf-8'

# 使用 iter_lines() 方法创建一个可迭代的行生成器
lines = response.iter_lines()

# 使用 next() 函数获取并跳过第一行,first_line 存储的是第一行的内容
first_line = next(lines)

# 逐行处理剩余的响应内容
for line in lines:
    # 打印当前行的内容
    print(json.loads(line))
2.2.2 iter_content() 使用
import requests

# 定义要请求的 URL
url = 'https://api.github.com/events'

# 发送 GET 请求到指定的 URL,使用 stream=True 以便逐块下载内容
response = requests.get(url=url, stream=True)

# 打开一个文件以写入二进制数据,路径为 'D:\\demo.txt'
with open('D:\\demo.txt', 'wb') as fd:
    # 遍历响应内容,按块读取数据,块大小为 8192 字节
    for chunk in response.iter_content(chunk_size=8192):
        # 将读取的块写入文件
        fd.write(chunk)

五、代理

1. 获取免费代理地址

点击连接访问快代理网站:https://www.kuaidaili.com/free/inha/

如下图所示,可以获取免费的代理。

在这里插入图片描述

2. 使用代理配置单个请求

如果需要使用代理,可以通过为任意请求方法提供 proxies 参数来配置单个请求。

import requests

url = 'http://www.baidu.com'

proxies = {
    "http": "47.119.22.92:8008"
}

# 发送 GET 请求,并使用指定的代理
response = requests.get(url=url, proxies=proxies)

print(response.status_code)

打印的结果为:

200

3. 使用代理池

在进行网络请求时,特别是当你需要频繁地访问某个网站或希望隐藏自己的真实 IP 地址时,使用代理池可以提高请求的成功率和匿名性。通过每次发送请求时从多个代理服务器中随机选择一个来发送,可以分散请求源,减少被目标网站封禁的风险。

import random

import requests

url = 'http://www.baidu.com'

# 使用代理池
proxies_pool = [
    {'http': '47.122.65.254:8080'},
    {'http': '8.130.34.44:8800'},
    {'http': '47.121.183.107:8443'},
    {'http': '111.1.61.50:3128'},
    {'http': '47.119.164.33:3128'}
]

proxies = random.choice(proxies_pool)

# 发送 GET 请求,并使用指定的代理
response = requests.get(url=url, proxies=proxies)

print(response.status_code)

打印的结果为:

200

4. 使用 HTTP Basic Auth 的代理

如果代理需要使用 HTTP Basic Auth,可以使用 username:password@host 的语法来配置代理。

# 定义代理字典,包含用户名和密码
proxies = {
    "http": "username:password@10.10.1.10:3128",
}

5. 针对特定主机或连接方式设置代理

要为某个特定的连接方式或主机设置代理,可以使用 scheme://hostname 作为键。这种方式将针对指定的主机和连接方式进行匹配。

import requests

url = 'http://www.baidu.com'

# 针对特定主机设置代理
proxies = {
    "http://127.0.0.1": "http://47.121.183.107:8443"
}

# 发送 GET 请求,并使用指定的代理
response = requests.get(url=url, proxies=proxies)

print(response.status_code)

打印的结果为:

200

六、编码方式

1. 编码方式处理

当你收到一个 HTTP 响应时,requests 库会猜测响应内容的编码方式,以便在你调用 Response.text 方法时能够正确解码响应内容。以下是 requests 处理编码方式的具体机制。

1.1 自动检测编码

  1. 优先检查 HTTP 头部requests 首先会在 HTTP 响应头部查找 Content-Type 字段中的字符集声明。如果存在明确指定的字符集(例如 charset=UTF-8),则使用该字符集进行解码。

  2. 使用 charade 猜测编码:如果 HTTP 头部没有明确指定字符集,并且 Content-Type 包含 text 类型,则 requests 会使用内置的 chardet 库(原名为 charade)来推测最可能的编码方式。

  3. 默认编码:根据 RFC 2616 的规定,当 Content-Typetext 类型但没有指定字符集时,默认字符集应该是 ISO-8859-1requests 遵循这一规范并默认采用 ISO-8859-1 进行解码。

1.2 手动设置编码

如果你知道正确的编码方式并且希望覆盖 requests 的自动检测结果,可以通过直接设置 Response.encoding 属性来实现。

import requests

url = 'https://api.github.com/events'

response = requests.get(url=url)

# 查看推测的文本编码
print("自动推测的编码方式:" + response.encoding)

# 手动指定编码为 ISO-8859-1
response.encoding = 'ISO-8859-1'
# 打印编码方式
print("手动指定的编码方式:" + response.encoding)

打印的结果为:

自动推测的编码方式:utf-8
手动指定的编码方式:ISO-8859-1

1.3 使用原始字节数据

如果你不确定编码或者不想依赖于 requests 的自动解码功能,可以直接访问 Response.content 属性以获取未经解码的原始字节数据。然后根据需要自行解码。

import requests

url = 'https://api.github.com/events'

response = requests.get(url=url)

# 获取未经解码的原始字节数据,返回的是服务器返回的二进制内容
raw_data = response.content

# 使用 UTF-8 编码方式对原始字节数据进行解码,转换为字符串
decoded_text = raw_data.decode('utf-8')
print(decoded_text)

七、身份认证

1. 基本身份认证 (HTTP Basic Auth)

HTTP Basic Authentication 是一种简单的认证机制,广泛用于需要认证的 Web 服务中。requests 库对这种认证方式提供了直接的支持。

可以通过导入 HTTPBasicAuth 类来使用 HTTP Basic Auth。

import requests
from requests.auth import HTTPBasicAuth

url = 'https://api.github.com/user'
auth = HTTPBasicAuth('user', 'pass')
# 发送带有基本身份认证的 GET 请求
response = requests.get(url=url, auth=auth)

print(response.status_code)

简写形式:由于 HTTP Basic Auth 非常常见,requests 提供了一种更为简洁的方式来传递认证信息——直接在 auth 参数中提供一个元组。

import requests

url = 'https://api.github.com/user'
# 发送带有基本身份认证的 GET 请求
response = requests.get(url=url, auth=('user', 'pass'))

print(response.status_code)

参考链接:

  • requests 官方文档:http://cn.python-requests.org/zh_CN/latest/

http://www.kler.cn/a/459543.html

相关文章:

  • 【AI编辑器】Cursor与DeepSeek模型的集成:提升开发效率的新选择
  • 《量子比特大阅兵:不同类型量子比特在人工智能领域的优劣势剖析》
  • Python深度学习GRU、LSTM 、BiLSTM-CNN神经网络空气质量指数AQI时间序列预测及机器学习分析|数据分享...
  • 2501d,jingo优化
  • ES6中定义私有属性详解
  • SMTP发送邮件的过程
  • 25 go语言(golang) - 内存分配机制原理
  • 鱼眼相机模型与去畸变实现
  • MySQL数据导出导出的三种办法(1316)
  • JAVA毕业设计205—基于Java+Springboot+vue3的民宿酒店管理系统(源代码+数据库)
  • 基于FPGA的RLC电阻电容电感测试仪设计(论文+源码)
  • XDMA IP
  • React 性能优化十大总结
  • springboot511基于SpringBoot视频点播系统的设计与实现(论文+源码)_kaic
  • php 静态变量
  • linux 配置端口转发
  • 前端Python应用指南(四)Django实战:创建一个简单的博客系统
  • Java的SpringMVC
  • 嵌入式硬件杂谈(八)电源的“纹波”到底是什么?
  • Linux 信号集与信号掩码
  • uniapp小程序使用rich-text富文本图片溢出问题
  • ZYNQ7000双核AMP文档解读
  • 爬虫的工作原理
  • 百度热力图数据处理流程Arcgis PRO篇,Arcgis,QGIS见链接其他文章
  • 互联网全景消息(8)之RabbitMQ进阶介绍
  • 【机器学习】概述