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
参数,你可以选填其他参数来自定义请求:
-
headers
: 字典,用于自定义HTTP请求头。 -
cookies
: 字典,或RequestsCookieJar
对象,包含 cookies。 -
auth
: 元组,用于HTTP认证的凭据。第一个元素是用户名,第二个元素是密码。 -
params
: 字典,用于将表单数据附加到URL的查询字符串中(GET、POST请求)。 -
data
: 字典或类似字典的对象,用于表单数据的提交。(POST、PUT请求) -
json
: 字典或类似字典的对象,用于发送JSON数据。(POST、PUT请求) -
files
: 字典{'表单字段名': ('文件名', 文件对象)}
,用于上传文件。(POST请求) -
stream
: 布尔值,用于流式下载。默认值False
,为True
逐块读取响应体减少内存使用。 -
timeout
: 浮点数或元组,用于指定请求的超时时间(秒)。默认无限期地等待。 -
verify
: 布尔值,或到CA证书包的路径。默认值True
,为False
不验证服务器SSL证书。 -
cert
: 字符串或元组,用于传递客户端证书文件的路径,或者证书和私钥文件的路径。 -
allow_redirects
: 布尔值,是否允许重定向。默认为True
允许重定向。 -
proxies
: 字典,用于配置代理。
▶ 其他功能
除了这些基本的HTTP方法,requests
库还提供了以下功能:
-
Session
对象:允许你跨请求保持某些参数,例如cookies。 -
Response
对象:包含服务器响应的所有信息,如状态码、文本内容、headers等。 -
RequestException
:当请求遇到问题时抛出的异常。 -
Timeout
:用于设置请求的超时时间。 -
TooManyRedirects
:当请求重定向次数超过设定值时抛出的异常。 -
Request
:用于创建一个请求对象,可以自定义请求的各个方面。
二、请求参数示例
- headers:
- 字典,用于自定义HTTP请求头。
headers = {'User-Agent': 'Mozilla/5.0 (compatible; YourBot/0.1)'} response = requests.get('http://example.com', headers=headers)
- cookies:
- 字典,或
RequestsCookieJar
对象,包含 cookies。cookies = {'session_token': '123456789'} response = requests.get('http://example.com', cookies=cookies)
- 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)
- 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" '''
- data:
- 字典或类似字典的对象,用于表单数据的提交。(POST、PUT请求)
requests
库会自动设置Content-Type
为application/x-www-form-urlencoded
。如果指定了headers中的Content-Type
为application/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)
- json:
- 字典或类似字典的对象,用于发送JSON数据。(POST、PUT请求)
requests
库会自动设置Content-Type
为application/json
。response = requests.post('https://httpbin.org/post', json={'key1': 'value1'})
- files:
- 字典
{'表单字段名': ('文件名', 文件对象)}
,用于上传文件。(POST请求)
requests
库会自动设置Content-Type
为multipart/form-data
,这是文件上传的标准格式。- 键:是是表单字段名,相当于HTML表单中的name属性。
- 值:是一个元组。第一个元素是文件名(在服务器上保存的名称),第二个元素是文件对象(可以使用
open()
函数打开文件并获取文件对象)。为什么通常不建议省略文件名:
- 服务器端处理:服务器端的代码通常依赖于文件名来保存上传的文件。如果没有提供文件名,服务器可能无法正确处理文件,或者会使用默认的文件名,这可能不是你想要的。
- 内容识别:文件名可以提供关于文件内容类型的线索,有助于服务器端正确处理文件(例如,根据文件扩展名设置正确的 Content-Type)。
- 避免冲突:如果多个文件上传到同一个服务器端路径,明确的文件名可以避免命名冲突。
- 如果省略了文件名,服务器接收到的文件名将是文件对象的名称,如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)
- 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)
- 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("请求超时")
- 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')
- cert:
- 字符串或元组,用于传递客户端证书和私钥文件的路径。
通常,cert
和verify
参数一起使用,以确保客户端和服务器之间的通信是安全和加密的。# 只传递证书文件,字符串:.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'))
- 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) # 打印最终响应的状态码
- 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')
会话的用途
-
保持参数:
Session
对象允许你设置一些参数一次,然后对多个请求重用这些参数。 -
保持 Cookies:
Session
会自动处理 Cookies,保持用户会话。 -
连接池:
Session
使用连接池来管理持久连接,这可以显著提高性能。 - 会话头部:可以为会话设置自定义头部,这些头部会自动应用于会话中的所有请求。
常用方法和属性
-
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)或重用参数的情况下。通过使用会话,你可以简化代码并提高应用程序的性能。