【Python爬虫实战】SSL证书、超时处理、自动重试与代理的最佳实践

  🌈个人主页:https://blog.csdn.net/2401_86688088?type=blog
🔥 系列专栏:https://blog.csdn.net/2401_86688088/category_12797772.html

目录

前言

一、SSL证书问题

(一)跳过 SSL 证书验证

(二)使用自定义的 SSL 证书

(三)使用客户端证书

(四)总结

二、请求超时

(一)设置请求超时时间

(二)处理超时异常

(三)设置合理的超时时间

(四)总结

三、retrying模块的使用

(一)安装 retrying 模块

(二)基本使用方法

(三)设置重试策略

(四)组合多个参数

(五)完整的异常处理

(六)总结

四、发送json格式数据

(一)使用 requests.post() 发送 JSON 数据

(二)使用 requests.put() 发送 JSON 数据

(三)手动设置请求头发送 JSON 数据

(四)总结

五、session会话

(一)创建一个会话

(二)保持 Cookies

(三)共享 Headers 和其他配置

(四)代理和身份验证

(五)关闭会话

(六)总结

六、代理

(一)设置代理

(二)使用带认证的代理

(三)针对特定协议设置代理

(四)不通过代理访问特定 URL

(五)Session 中使用代理

(六)使用 SOCKS 代理

(七)总结

七、总结


前言

在现代的 Web 开发和网络编程中,HTTP 请求和数据交互已经成为必不可少的技术基础。Python 的 requests 模块因其简单易用、功能强大而广受欢迎,能够帮助开发者轻松发起各种网络请求并处理响应。然而,在实际应用中,开发者经常需要处理 SSL 证书验证、请求超时、自动重试以及会话管理等复杂的场景。此外,代理的使用可以帮助开发者绕过网络限制或匿名访问特定资源。本文详细介绍了如何使用 requests 模块处理这些问题,并通过 retrying 模块实现自动重试机制,帮助开发者应对网络不稳定性和临时故障的挑战。


一、SSL证书问题

SSL证书(Secure Sockets Layer Certificate)是一种数字证书,用于在客户端(通常是浏览器)和服务器之间建立安全的加密连接。SSL证书确保数据在传输过程中被加密,以防止未经授权的第三方窃听、篡改或伪造数据。SSL证书也可用于证明服务器的身份,使用户能够确认他们连接的是合法的网站。

使用 requests 模块进行 HTTP 请求时,可能会遇到涉及 SSL 证书的问题。 requests 模块默认会验证 SSL 证书,以确保连接的安全性。但是在某些情况下,例如访问自签名证书的服务器或开发环境中的测试服务器时,你可能需要跳过 SSL 证书验证或者指定自定义的证书。

(一)跳过 SSL 证书验证

如果你想跳过 SSL 证书的验证,可以使用 verify=False 参数。在某些测试场景中,这可能会非常有用。

示例:

import requests

url = 'https://example.com'

# 发起请求,并忽略 SSL 证书验证
response = requests.get(url, verify=False)

# 打印返回内容
print(response.text)

注意:跳过 SSL 验证可能会带来安全风险,仅在你明确知道需要跳过验证的情况下使用。同时,跳过 SSL 验证时,requests 模块会给出警告。你可以通过以下方式关闭这些警告:

import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning

# 禁用 SSL 警告
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

url = 'https://example.com'
response = requests.get(url, verify=False)
print(response.text)

(二)使用自定义的 SSL 证书

如果你有一个自签名证书或其他非标准的证书,可以使用 verify 参数指定证书的路径。

示例:

import requests

url = 'https://example.com'
# 指定证书的路径
response = requests.get(url, verify='/path/to/certfile.pem')

# 打印返回内容
print(response.text)

在这种情况下,requests 模块会使用你指定的证书来进行验证。

(三)使用客户端证书

有时服务器可能需要你提供客户端证书进行身份验证。这种情况下,你可以使用 cert 参数来指定你的证书和私钥文件。

示例:

import requests

url = 'https://example.com'
# 使用客户端证书,cert 参数可以是一个包含证书文件和密钥文件路径的元组
response = requests.get(url, cert=('/path/to/client_cert.pem', '/path/to/client_key.pem'))

# 打印返回内容
print(response.text)

(四)总结

  • 跳过 SSL 验证:verify=False

  • 指定自定义证书文件:verify='/path/to/certfile.pem'

  • 使用客户端证书进行身份验证:cert=('/path/to/client_cert.pem', '/path/to/client_key.pem')


二、请求超时

使用 requests 模块进行网络请求时,可能会遇到网络延迟、服务器响应慢等问题,导致请求超时。为了避免请求长时间挂起,可以使用 timeout 参数来设置请求的超时时间。超时是指在指定时间内没有收到服务器的响应时,抛出超时异常。

(一)设置请求超时时间

requests 模块的 timeout 参数可以用来设置超时时间,单位是秒。可以指定一个总的超时时间,或者分别为连接时间和读取时间设置超时时间。

示例 1:设置总超时时间

import requests

url = 'https://example.com'

try:
    # 设置超时时间为5秒
    response = requests.get(url, timeout=5)
    print(response.text)
except requests.exceptions.Timeout:
    print("请求超时")

在这个例子中,如果在 5 秒内没有收到服务器的响应,程序会抛出 Timeout 异常。

示例 2:分别设置连接和读取的超时时间

你也可以分别为 连接 和 读取 设置不同的超时时间,传入一个元组 (connect_timeout, read_timeout)。

示例:

import requests

url = 'https://example.com'

try:
    # 设置连接超时为3秒,读取超时为5秒
    response = requests.get(url, timeout=(3, 5))
    print(response.text)
except requests.exceptions.Timeout:
    print("请求超时")

在这个例子中:

  • 连接超时:客户端与服务器建立连接的时间限制(3秒)。

  • 读取超时:客户端等待服务器发送数据的时间限制(5秒)。

(二)处理超时异常

当请求超时时,requests 会抛出 requests.exceptions.Timeout 异常。你可以使用 try 和 except 来捕获和处理这个异常,防止程序崩溃。

(三)设置合理的超时时间

  • 短时间请求:如果你期望请求在很短的时间内完成(如API请求),可以设置较短的超时时间,以提高程序的响应性。

  • 长时间请求:如果请求需要长时间处理(如下载大文件或与低速服务器通信),则需要设置一个较长的超时时间。

(四)总结

  • 设置超时时间:使用 timeout 参数为请求设置合理的超时时间。

  • 分别设置连接和读取超时时间:传入元组 (connect_timeout, read_timeout)。

  • 处理超时异常:使用 try-except 块捕获和处理 requests.exceptions.Timeout 异常。


三、retrying模块的使用

retrying 模块用于实现自动重试操作,适用于处理临时失败的任务(如网络请求、文件读写等)。你可以通过配置重试次数、等待时间、异常捕获等来灵活控制重试的行为。以下是详细的使用介绍及示例。

(一)安装 retrying 模块

如果没有安装 retrying 模块,可以通过以下命令进行安装:

pip install retrying

(二)基本使用方法

可以使用 @retry 装饰器来包装需要重试的函数。当函数抛出异常时,retrying 会根据定义的策略自动重试。

示例:

from retrying import retry

@retry
def unreliable_function():
    print("尝试执行...")
    raise Exception("操作失败")

# 调用函数
unreliable_function()

在这个例子中,unreliable_function 会持续重试,因为它每次都会抛出异常。

(三)设置重试策略

1. 限制最大重试次数

可以使用 stop_max_attempt_number 参数限制重试的最大次数。

from retrying import retry

@retry(stop_max_attempt_number=3)  # 最多重试3次
def unreliable_function():
    print("尝试执行...")
    raise Exception("操作失败")

unreliable_function()

这个例子中,函数最多会重试 3 次,如果仍然失败,最终会抛出异常。

2.设置固定等待时间

可以使用 wait_fixed 参数来设置每次重试之间的固定等待时间,单位是毫秒。

from retrying import retry

@retry(wait_fixed=2000)  # 每次重试等待2秒
def unreliable_function():
    print("尝试执行...")
    raise Exception("操作失败")

unreliable_function()

在这个例子中,每次重试之间会等待 2 秒。

3.指数退避策略

retrying 还支持指数退避(exponential backoff)策略,重试的时间间隔会随着重试次数的增加而指数增长。

from retrying import retry

@retry(wait_exponential_multiplier=1000, wait_exponential_max=10000)
def unreliable_function():
    print("尝试执行...")
    raise Exception("操作失败")

unreliable_function()

在这个例子中,重试的时间间隔会从 1 秒开始,每次增长,直到最大等待时间为 10 秒。

4.根据特定异常类型重试

可以使用 retry_on_exception 参数指定特定的异常类型来触发重试。以下示例仅在捕获 IOError 时进行重试。

from retrying import retry

def retry_if_io_error(exception):
    return isinstance(exception, IOError)

@retry(retry_on_exception=retry_if_io_error)
def unreliable_function():
    print("尝试执行...")
    raise IOError("发生了IO错误")

unreliable_function()

这个例子中,函数只会在抛出 IOError 时进行重试。

5.根据返回值进行重试

还可以通过 retry_on_result 参数指定函数返回特定结果时触发重试。例如,以下代码在函数返回 None 时重试。

from retrying import retry

@retry(retry_on_result=lambda result: result is None)
def unreliable_function():
    print("尝试执行...")
    return None  # 如果返回 None,则触发重试

unreliable_function()

在这个例子中,函数每次返回 None 时会进行重试。

(四)组合多个参数

可以将多个参数组合使用来定制更复杂的重试策略。例如,限制重试次数、设置固定的等待时间,并指定特定的异常类型来进行重试。

from retrying import retry

@retry(stop_max_attempt_number=5, wait_fixed=2000, retry_on_exception=lambda e: isinstance(e, IOError))
def unreliable_function():
    print("尝试执行...")
    raise IOError("发生了IO错误")

unreliable_function()

在这个例子中,函数最多会重试 5 次,每次重试之间等待 2 秒,并且只在捕获 IOError 时触发重试。

(五)完整的异常处理

可以使用 try-except 语句捕获 retrying 的重试过程中的异常。

from retrying import retry
import requests

@retry(stop_max_attempt_number=3, wait_fixed=2000)
def unreliable_function():
    print("尝试获取网页内容...")
    response = requests.get("https://example.com")
    return response

try:
    unreliable_function()
except Exception as e:
    print(f"最终失败:{e}")

在这个例子中,如果重试 3 次后仍然失败,except 块会捕获异常并输出错误信息。

(六)总结

retrying 模块为函数的自动重试提供了灵活的控制选项,包括:

  • 最大重试次数 (stop_max_attempt_number)

  • 固定的重试等待时间 (wait_fixed)

  • 指数退避策略 (wait_exponential_multiplierwait_exponential_max)

  • 基于特定异常的重试 (retry_on_exception)

  • 基于函数返回值的重试 (retry_on_result)


四、发送json格式数据

使用 requests 模块发送 JSON 格式的数据非常简单。通过 requests.post() 或 requests.put() 方法,你可以将 Python 字典自动转换为 JSON 格式,并发送给服务器。requests 会在请求头中自动设置 Content-Type 为 application/json,你只需要通过 json 参数传入字典即可。

(一)使用 requests.post() 发送 JSON 数据

import requests

# 目标 URL
url = 'https://example.com/api/endpoint'

# 要发送的 JSON 数据
data = {
    "name": "John Doe",
    "age": 30,
    "email": "johndoe@example.com"
}

# 发送 POST 请求,自动将字典转换为 JSON 格式
response = requests.post(url, json=data)

# 打印响应状态码和内容
print(response.status_code)
print(response.text)

在这个例子中:

  • url 是你要发送请求的目标服务器地址。

  • data 是要发送的 JSON 数据,格式是 Python 字典。

  • requests.post(url, json=data) 会自动将字典转换为 JSON,并发送到指定的 url

(二)使用 requests.put() 发送 JSON 数据

同样,发送 PUT 请求时也可以使用相同的方法:

import requests

# 目标 URL
url = 'https://example.com/api/endpoint'

# 要发送的 JSON 数据
data = {
    "name": "Jane Doe",
    "age": 25,
    "email": "janedoe@example.com"
}

# 发送 PUT 请求
response = requests.put(url, json=data)

# 打印响应状态码和内容
print(response.status_code)
print(response.text)

(三)手动设置请求头发送 JSON 数据

如果想手动设置请求头,也可以这样做:

import requests
import json

# 目标 URL
url = 'https://example.com/api/endpoint'

# 要发送的 JSON 数据
data = {
    "name": "Alice",
    "age": 28,
    "email": "alice@example.com"
}

# 手动设置请求头,并将数据转换为 JSON 字符串
headers = {'Content-Type': 'application/json'}
response = requests.post(url, data=json.dumps(data), headers=headers)

# 打印响应状态码和内容
print(response.status_code)
print(response.text)

(四)总结

  • 使用 requests.post()requests.put() 方法时,可以直接通过 json 参数发送 JSON 数据,requests 会自动设置请求头和转换数据格式。

  • 如果需要手动设置请求头,可以使用 headers 参数,并通过 json.dumps() 将字典转换为 JSON 字符串。


五、session会话

requests.Session 是 Python 的 requests 库中一个非常有用的对象,用来保持会话状态。使用 Session 对象可以在多个请求中共享连接、Cookies、Headers 等信息。它的主要功能是为同一个服务器的多个请求创建一个持久的会话,从而减少重复连接的开销、维护登录状态等。

Session 的优势:

  • 保持 Cookies:会话中可以保存并共享 Cookies,适合需要登录认证的场景。

  • 减少连接开销:同一个会话可以复用底层的 TCP 连接,减少连接建立的耗时。

  • 共享参数:可以在整个会话中共享请求头、认证信息、代理等。

(一)创建一个会话

使用 requests.Session() 创建会话对象。

示例:

import requests

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

# 通过会话发送请求
response = session.get('https://example.com')

# 打印响应内容
print(response.text)

# 关闭会话
session.close()

(二)保持 Cookies

当你使用会话发送请求时,Cookies 会在请求之间保持和共享,适合需要登录状态的操作。

示例:

import requests

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

# 登录的URL
login_url = 'https://example.com/login'

# 假设的登录表单数据
login_data = {
    'username': 'user123',
    'password': 'password'
}

# 登录
login_response = session.post(login_url, data=login_data)
print("登录后的Cookies:", session.cookies.get_dict())

# 登录后访问需要认证的页面
profile_url = 'https://example.com/profile'
profile_response = session.get(profile_url)
print("个人资料页面:", profile_response.text)

# 关闭会话
session.close()

在这个例子中,session 会在登录后保存并共享 Cookies,因此后续的请求不需要再次登录。

(三)共享 Headers 和其他配置

Session 可以设置默认的 Headers,这样所有使用会话的请求都会共享这些 Headers。

import requests

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

# 更新默认的请求头
session.headers.update({
    'User-Agent': 'my-app/0.0.1',
    'Accept': 'application/json'
})

# 使用会话发送请求
response = session.get('https://httpbin.org/get')
print(response.json())

# 关闭会话
session.close()

在这个示例中,所有通过 session 发出的请求都会使用 User-Agent 和 Accept 头信息。

(四)代理和身份验证

会话可以共享代理和身份验证信息,适合处理需要代理或身份验证的请求。

代理示例:

import requests

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

# 设置代理
session.proxies.update({
    'http': 'http://10.10.1.10:3128',
    'https': 'https://10.10.1.10:1080',
})

# 通过代理发送请求
response = session.get('https://httpbin.org/ip')
print(response.json())

# 关闭会话
session.close()

基本身份验证示例:

import requests
from requests.auth import HTTPBasicAuth

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

# 设置基本身份验证
session.auth = HTTPBasicAuth('user', 'password')

# 发送需要身份验证的请求
response = session.get('https://httpbin.org/basic-auth/user/password')
print(response.status_code)

# 关闭会话
session.close()

(五)关闭会话

使用完会话后,应该调用 session.close() 来释放资源。虽然 Python 的垃圾回收机制会自动处理未关闭的会话,但显式关闭会话是一种良好的实践。

(六)总结

  • Session 允许你在多次请求之间共享信息,例如 Cookies 和 Headers,适合处理登录认证、代理等需要保持会话状态的场景。

  • 通过 requests.Session() 创建一个会话,使用 session.get() 或 session.post() 等方法发送请求,并在使用完毕后调用 session.close() 关闭会话。

  • 会话有助于优化性能,减少重复的连接开销,使你的代码更高效。


六、代理

使用 Python 的 requests 模块时,代理(proxies)允许你通过中间服务器发送请求。这在绕过网络限制、匿名浏览或访问某些受限区域的网站时非常有用。你可以为 HTTP 和 HTTPS 请求设置不同的代理。

(一)设置代理

可以通过传递一个包含代理信息的字典给 proxies 参数来设置代理。代理字典的格式如下:

proxies = {
    'http': 'http://proxy.server:port',
    'https': 'https://proxy.server:port',
}

示例:使用 HTTP 和 HTTPS 代理

import requests

# 定义代理
proxies = {
    'http': 'http://10.10.1.10:3128',
    'https': 'https://10.10.1.10:1080',
}

# 发送请求并使用代理
response = requests.get('https://httpbin.org/ip', proxies=proxies)

# 打印响应内容
print(response.text)

在这个示例中,所有通过 requests.get() 发送的请求都会通过你指定的代理服务器路由。

(二)使用带认证的代理

有些代理服务器需要身份验证,你可以在代理 URL 中包含用户名和密码,格式如下:

proxies = {
    'http': 'http://username:password@proxy.server:port',
    'https': 'https://username:password@proxy.server:port',
}

示例:使用需要身份验证的代理

import requests

# 需要身份验证的代理
proxies = {
    'http': 'http://user:pass@10.10.1.10:3128',
    'https': 'https://user:pass@10.10.1.10:1080',
}

# 发送请求
response = requests.get('https://httpbin.org/ip', proxies=proxies)

# 打印响应
print(response.text)

在这种情况下,代理服务器会使用提供的用户名 user 和密码 pass 来进行身份验证。

(三)针对特定协议设置代理

可以只为 HTTP 或 HTTPS 请求单独设置代理,例如仅为 HTTP 设置代理:

proxies = {
    'http': 'http://10.10.1.10:3128',
}

response = requests.get('http://httpbin.org/ip', proxies=proxies)
print(response.text)

(四)不通过代理访问特定 URL

如果你想为某些 URL 禁用代理(即使全局设置了代理),你可以通过 no_proxy 环境变量实现。

import os

# 设置不使用代理的 URL
os.environ["no_proxy"] = "example.com"

# 请求不使用代理的 URL
response = requests.get('http://example.com')
print(response.text)

(五)Session 中使用代理

如果你需要在整个会话中使用代理,可以在 requests.Session 对象中配置代理,这样所有通过该会话发送的请求都会使用代理。

示例:在会话中使用代理

import requests

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

# 为会话设置代理
session.proxies.update({
    'http': 'http://10.10.1.10:3128',
    'https': 'https://10.10.1.10:1080',
})

# 发送请求
response = session.get('https://httpbin.org/ip')
print(response.json())

# 关闭会话
session.close()

(六)使用 SOCKS 代理

如果你需要使用 SOCKS 代理,可以安装 requests[socks] 依赖,并设置代理格式为 socks5:// 或 socks5h://。你需要通过 pip 安装 requests 的 SOCKS 支持:

pip install requests[socks]

然后,你可以这样使用 SOCKS 代理:

import requests

# 设置 SOCKS 代理
proxies = {
    'http': 'socks5://user:pass@10.10.1.10:1080',
    'https': 'socks5://user:pass@10.10.1.10:1080',
}

# 发送请求
response = requests.get('https://httpbin.org/ip', proxies=proxies)

# 打印响应内容
print(response.text)

(七)总结

  • requests 模块支持通过 HTTP、HTTPS 以及 SOCKS 代理发送请求,可以使用 proxies 参数来配置。

  • 代理可以包括身份验证信息,如用户名和密码。

  • 可以在全局范围或 Session 中使用代理,以提高效率。

  • 对于需要特定代理或不使用代理的请求,可以灵活配置请求。


七、总结

通过本文的介绍,我们深入了解了如何使用 requests 模块处理 SSL 证书问题、设置请求超时、发送 JSON 格式数据以及使用代理服务器。同时,还介绍了如何通过 retrying 模块实现自动重试,处理临时性故障。此外,requests.Session 会话管理可以帮助开发者在多个请求中保持状态、共享 Cookies 和连接配置。代理的使用能够帮助开发者解决网络访问中的特殊需求。掌握这些技能,将极大提高你在网络编程中的效率和代码的健壮性,确保应用程序能够应对各种网络请求场景。

评论 75
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值