一、request模块的响应
1、响应头中最常见的一些内容
- Content-Type:指示响应正文的媒体类型,例如 text/html、application/json 等。
- Content-Length:指示响应正文的长度(以字节为单位)。
- Date:指示响应生成的日期和时间。
- Server:指示响应的服务器软件名称和版本号。
- Set-Cookie:用于设置 HTTP Cookie,以便在客户端和服务器之间传递状态信息。
- Cache-Control:指示客户端如何缓存响应内容,控制缓存行为。
- Expires:指示响应内容的过期时间,告诉客户端何时应该丢弃缓存的副本。
- Location:指示客户端重定向的位置,通常在响应码为 3xx(重定向)时使用。
- ETag:用于标识资源的版本,客户端可以使用它进行缓存验证。
- Last-Modified:指示资源的最后修改时间,也用于缓存验证。
2、response对象的属性
发送GET/POST请求后,服务器会返回一个响应对象
post请求一般返回数据都是json数据。
服务器响应包含:状态行(协议,状态码)、响应头、空行、响应正文。
(1)响应正文
字符串格式:response.text
bytes类型:response.content
json格式:respone.josn()
(2)状态码
response.status_code
(3)响应头
response.headers --字典
# 获取响应头中的cookie
response.headers['cookie']
(4)响应正文的编码
response.encoding
# response.text获取到的字符串类型的响应正文,其实是通过下面的步骤获取的
response.encoding = response.content.decode()
(5)乱码问题的解决办法
产生的原因:编码和解码的编码格式不一致造成的。
str.encode() # 将字符串解码成bytes类型
bytes.decode() # 将bytes类型编码成字符串
第一种方法:
response.content.decode('页面正确的编码格式')
第二种方法:找到正确的编码,设置到 response.encoding 中
response.encoding = '正确的编码'
response.text ---> 正确的页面内容
(6)迭代获取二进制数据
response.iter_content()
:迭代获取响应内容(适用于处理视频、图片等二进制数据)
# 导入requests库
import requests
# 定义目标地址:该地址是一张图片,图片属于二进制数据
tag_url = "https://pic.netbian.com/uploads/allimg/240322/232300-171112098057a5.jpg"
# 向目标地址发起请求
response = requests.get(tag_url)
# 打开本地的文件路径,写入二进制数据必须用 wb 模式
file_path = "./a.jpg"
with open(file_path, 'wb') as f:
# 循环获取响应数据中的二进制数据,每次只获取 1024 个字节
for chunk in response.iter_content(chunk_size=1024):
# 如果存在数据,则进行文件数据的写入
if chunk:
f.write(chunk)
(7)响应Cookie
response.cookies
: 获取服务器返回的cookie信息。response.cookies.get_dict()
: 将cookie信息转换为字典形式。response.cookies.items()
: 获取cookie信息并以列表形式返回。
import requests
response = requests.get('https://www.baidu.com/')
# `response.cookies`: 获取服务器返回的cookie信息。
print(response.cookies)
# <RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
# `response.cookies.get_dict()`: 将cookie信息转换为字典形式。
print(response.cookies.get_dict())
# {'BDORZ': '27315'}
# `response.cookies.items()`: 获取cookie信息并以列表形式返回。
print(response.cookies.items())
# [('BDORZ', '27315')]
(8)补充
① respone.josn()和respone.text区别
improt requests
url = "https://www.baidu.com/"
prams = { 'pw':'root',
'wd':'123456'
'QQ':'中文' # 这里requests会自动将中文转成urlencode编码
}
respone = requests.post(url,prams=prams)
print(respone.json()) # 这里json解析,返回的是dict
print(respone.text) # 返回text文本
② response的返回内容其它方法
-- r.status_code # 响应状态码
-- r.content # 字节方式的响应体,会自动为你解码 gzip和deflate 压缩
-- r.headers # 以字典对象存储服务器响应头,但是这个字典比较特殊,字典键不区分大小写,若键不存在则返回None
-- r.json() # Requests中内置的JSON解码器 ,json转成python的字典了
-- r.url # 获取最后一次访问的url
-- r.request.url # 获取当前请求第一次发送的原始
-- r.encoding # 编码格式
-- r.cookies # 获取返回的cookie
-- r.text # 字符串方式的响应体,会自动根据响应头部的字符编码进行解码
-- r.raise_for_status() # 失败请求(非200响应)抛出异常
-- r.ok # 返回True / False 状态码在200-400之间 返回True状态码在400-600之间返回 False
-- r.history # 有重定向请求的时候,可以查看重定向记录
-- r.apparent_encoding # 分析响应编码
③ response.url和response.request.url的区别
在网络编程中,针对HTTP请求和响应,response.url
和response.request.url
是两个具有不同含义的属性。
-
response.url
:在HTTP响应对象中,response.url
属性表示最终响应的URL。这个URL可能与最初请求的URL不同,因为在HTTP请求过程中可能发生重定向。response.url
会给出最终响应的URL地址,即最后一个重定向的URL。 -
response.request.url
:在HTTP响应对象中,response.request.url
属性表示生成该响应的请求的URL。这个URL是最初发出的请求的URL,不会受到重定向的影响。
总结一下:
response.url
表示最终响应的URL,可能经过重定向后得到的URL。response.request.url
表示生成该响应的请求的URL,即最初发出请求时的URL。
通过理解这两个属性的区别,您可以更好地处理HTTP请求和响应之间的URL信息。如果您有任何其他问题或需要进一步解释,请随时告诉我。
二、SSL(Secure Sockets Layer)认证
现在很多网站都要求使用 HTTPS 协议,但是有些网站可能并没有设置好 HTTPS 证书,或者网站的 HTTPS 证书不被 CA 机构认可,这时候,这些网站可能就会出现 SSL 证书错误的提示。
比如这个示例网站:https://ssr2.scrape.center/。
1、验证整数演示
如果我们用 Chrome 浏览器打开这个 URL,则会提示「您的连接不是私密连接」这样的错误,如图所示:
我们可以在浏览器中通过一些设置来忽略证书的验证。
我们首先直接请求:
import requests
response = requests.get('https://ssr2.scrape.center/')
print(response.status_code)
请求的结果:
requests.exceptions.SSLError: HTTPSConnectionPool(host='ssr2.scrape.center', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:992)')))
这里直接抛出了SSLEror 错误,原因就是因为我们请求的 URL 的证书是无效的。
2、不验证证书演示
那如果我们一定要爬取这个网站怎么办呢?我们可以使用 verify 参数 控制是否验证证书,如果将其设置为 False,在请求时就不会再验证证书是否有效。如果不加 verify 参数的话,默认值是 True,会自动验证。
我们改写代码如下:
import requests
response = requests.get('https://ssr2.scrape.center/',verify=False)
print(response.status_code)
运行结果如下:
InsecureRequestWarning: Unverified HTTPS request is being made to host 'ssr2.scrape.center'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings
warnings.warn(
200
3、自定义证书路径
- 如果您希望使用自定义的证书进行验证,可以将
verify
参数设置为证书文件的路径。例如:
import requests
cert_file = "/path/to/my_certificate.pem"
# 发送请求,并使用自定义证书进行 SSL 验证
response = requests.get(url, verify=cert_file)
# 打印响应状态码
print(response.status_code)
# 打印响应内容
print(response.text)
- 在上述代码中,将
verify
参数设置为自定义证书文件的路径。requests
将使用指定的证书进行验证。 - 请注意,在实际使用中,如果从未提供过自定义证书,并且要禁用验证,则最好提供证书路径。这样可以避免不必要的错误和警告。
4、小结
注意:禁用 SSL 证书验证存在安全风险,因为它允许您的请求受到中间人攻击。
另外,在生产环境中,强烈建议启用 SSL 证书验证,以确保通信的安全性。
三、代理
1、代理的基本原理
代理服务器的基本原理是在客户端和目标服务器之间充当中间人,转发客户端和服务器之间的请求和响应。当客户端向代理服务器发送请求时,代理服务器会代表客户端向目标服务器请求数据,并将目标服务器的响应返回给客户端。
2、代理的作用
- 突破自身 ip访问限制,访问一些平时不能访问的站点。
- 访问一些单位或团体内部资源。
- 提高访问速度。代理服务器的主要作用就是中转,所以一般代理服务器里面都是用内存来进行数据存储的。
- 隐藏 ip。对于爬虫来说,我们用代理就是为了隐藏自身 IP,防止自身的 IP被封锁。
3、代理的分类
代理分类时,既可以根据协议区分,也可以根据其匿名程度区分。
(1)根据协议区分
FTP代理服务器:一般有上传、下载以及缓存功能,端口一般为 21、2121。
HTTP代理服务器:主要用于访问网页,一般有内容过滤和缓存功能,端口一般为 80,8080。
SSL/TLS代理:主要用于访问加密网站,一般有SSL或TLS加密功能(最高支持 128 位加密强度),端口一般为 443。
Telnet代理:主要用于 telnet远程控制(黑客入侵计算机时常用于隐藏身份),端口一般为 23。
(2)根据匿名程度区分
高度匿名代理:数据包会原封不动转化,在服务端看来,就好像一个普通用户在访问,做到完全隐藏 IP。
普通匿名代理:数据包会做一些改动,服务器有可能找到原 IP。
透明代理:不但改动数据,还会告诉服务器,是哪个用户访问的。
间谍代理:指组织或者个人用于记录用户传输的数据,然后进行研究、监控等目的的代理。
4、在requests模块中设置代理
在使用 Python 的 requests
模块发送 HTTP 请求时,可以通过设置代理来实现代理服务器的中转。
(1)使用proxies参数设置全局代理
以下是在 requests
模块中设置代理的方法:
代理ip格式
proxies={"协议":"协议://IP:端口号"}
import requests
# 定义代理服务器的地址
proxies = {
'http': 'http://your_proxy_server_address:port',
'https': 'https://your_proxy_server_address:port'
}
# 发送带代理的请求
response = requests.get('http://www.example.com', proxies=proxies)
# 打印响应内容
print(response.text)
在上面的代码中,首先定义了一个代理服务器的地址,然后将代理信息传递给 requests.get()
函数的 proxies
参数。这样 requests
模块会通过指定的代理服务器发送请求,而不是直接连接目标服务器。
需要注意的是,代理服务器的地址应该根据实际情况进行替换,包括代理服务器的协议(http 或 https)、IP 地址和端口号。另外,有些代理服务器可能需要用户名和密码进行认证,这时可以在代理地址中添加认证信息,例如:
proxies = {
'http': 'http://username:password@your_proxy_server_address:port',
'https': 'https://username:password@your_proxy_server_address:port'
}
通过以上方法,你可以在使用 requests
模块发送请求时指定代理服务器,实现代理功能。
(2)使用session对象设置会话级别的代理
- 若你需要在多个请求之间保持相同的代理设置,可以使用requests库中的Session对象。
- Session对象允许你在会话级别上保持一些参数,包括代理设置。
import requests
session = requests.Session()
session.proxies = {
'http': 'http://proxy.example.com:8080',
'https': 'https://proxy.example.com:8080'
}
response = session.get(url)
- 在这种情况下,创建的Session对象将会持续保持代理设置,直到我们显式地修改或重置它。
- 这对于需要在多个请求中使用相同代理的情况非常有用,例如爬取网站的多个页面时。
- 请注意,无论是使用全局代理还是会话级别的代理,都要确保代理地址和端口号的正确性,并根据实际情况选择http或https类型的代理。
5、代理配置示例
我们编写一个python代码,使用免费代理IP访问测试网站:http://httpbin.org/get 来获取当前访问环境的ip地址
(1)获取本机IP
import requests
from fake_useragent import UserAgent
# 定义目标地址
url = 'http://httpbin.org/get'
# 定义请求头参数
headers = {
"User-Agent": UserAgent().random
}
# 获取响应对象
response = requests.get(url=url, headers=headers)
# 检查请求是否成功
if response.status_code == 200:
# 处理响应内容
response.encoding = 'utf-8' # 设置响应内容的编码格式为utf-8
# 解析JSON结果
data = response.text # 获取响应信息
print(data)
else:
print("请求失败:", response.status_code)
{
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1 Ddg/17.0",
"X-Amzn-Trace-Id": "Root=1-66040d75-18c03afc0e7c608e470b96a4"
},
"origin": "218.82.160.16",
"url": "http://httpbin.org/get"
}
(2)使用代理IP
首先我们找到一个免费代理网站:https://ip.ihuan.me/ 来获取免费的代理IP
import requests
from fake_useragent import UserAgent
# 定义目标地址
url = 'http://httpbin.org/get'
# 定义请求头参数
headers = {
"User-Agent": UserAgent().random
}
# 设置代理地址
proxies = {
'http': 'http://111.59.4.88:9002'
}
# 获取响应对象
response = requests.get(url=url, headers=headers, proxies=proxies)
# 检查请求是否成功
if response.status_code == 200:
# 处理响应内容
response.encoding = 'utf-8' # 设置响应内容的编码格式为utf-8
# 解析JSON结果
data = response.text # 获取响应信息
print(data)
else:
print("请求失败:", response.status_code)
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
"X-Amzn-Trace-Id": "Root=1-66040ef0-5e63ed4a32e9b4df0e371f14"
},
"origin": "111.59.4.88",
"url": "http://httpbin.org/get"
}
四、超时设置
在使用 requests
模块时,你可以通过设置 timeout
参数来控制请求的超时时间。超时时间指的是在发出请求后等待服务器响应的最大时间。如果在超时时间内未收到响应,将引发超时异常。
在 requests.get()
或 requests.post()
方法中,你可以将 timeout
参数设置为一个包含两个值的元组,分别表示连接超时和读取超时。例如,timeout=(3, 7)
表示连接超时为3秒,读取超时为7秒。
下面是一个简单的示例,演示如何在使用 requests
模块时设置超时时间:
import requests
url = 'http://www.example.com'
try:
response = requests.get(url, timeout=(3, 7)) # 设置连接超时为3秒,读取超时为7秒
response.raise_for_status() # 如果响应状态码不是 2xx,会抛出异常
print(response.text)
except requests.exceptions.RequestException as e:
print(f'Error: {e}')
在这个示例中,我们设置了连接超时为3秒,读取超时为7秒。如果在这段时间内没有收到响应,将会引发 requests.exceptions.Timeout
异常。请根据你的需求调整超时时间,确保它既不会太短导致误判,也不会太长影响程序性能。
五、认证设置
1、官网链接
2、认证设置
- 登陆网站是,弹出一个框,要求你输入用户名密码(与alter很类似),此时是无法获取html的
- 但本质原理是拼接成请求头发送
r.headers['Authorization'] = _basic_auth_str(self.username, self.password)
- 一般的网站都不用默认的加密方式,都是自己写
- 那么我们就需要按照网站的加密方式,自己写一个类似于_basic_auth_str的方法
- 得到加密字符串后添加到请求头
r.headers['Authorization'] =func('.....')
- 在使用requests模块进行认证设置时,可以通过HTTPBasicAuth类或简写方式来提供用户名和密码进行认证。
3、基本身份认证
- 许多需要身份验证的 Web 服务都接受 HTTP 基本身份验证。
- 这是 最简单的类型,Requests 开箱即用地支持它。
(1)完整语法
- 可以使用requests.auth模块中的HTTPBasicAuth类来提供用户名和密码进行认证。
- 示例代码如下:
from requests.auth import HTTPBasicAuth
import requests
# 创建一个使用 'user' 和 'pass' 进行基本身份验证的函数。
basic = HTTPBasicAuth('user', 'pass')
# 然后使用该函数进行请求。
response = requests.get('https://httpbin.org/basic-auth/user/pass', auth=basic)
# 输出响应的文本。
print(response.text)
# {
# "authenticated": true,
# "user": "user"
# }
# 输出响应的状态码。
print(response.status_code)
# <Response [200]>
(2)简写语法
- 可以直接在auth参数中以元组的形式提供用户名和密码进行认证,无需导入HTTPBasicAuth类。
- 示例代码如下:
import requests
# 携带认证参数,使用该函数进行请求。
response = requests.get('https://httpbin.org/basic-auth/user/pass', auth=('user', 'pass'))
# 输出响应的文本。
print(response.text)
# {
# "authenticated": true,
# "user": "user"
# }
# 输出响应的状态码。
print(response.status_code)
# <Response [200]>
- 需要注意的是,上述示例代码中的'xxx'应替换为具体的URL地址,用于发送请求进行认证。
(3)小结
- 默认情况下,这两种方式都会使用HTTP基本认证(Basic Authentication),即将用户名和密码以base64编码形式拼接到请求头的Authorization字段中发送给服务器。
- 然而,大多数网站都会使用自定义的加密方式,所以需要根据网站的加密方式进行相应的处理,在认证之前生成正确的认证字符串,并将其添加到请求头的Authorization字段中。
- 例如,如果网站使用了自定义的加密方式,可以按照该方式编写一个自定义函数,并将生成的认证字符串通过r.headers['Authorization'] = 函数名('...')的方式添加到请求头中。
- 需要根据具体网站的加密方式和认证机制进行处理,可以参考相关网站的文档或联系网站开发人员获取详细的认证设置信息。
4、netrc 身份验证
- 如果参数未给出身份验证方法,则请求将 尝试从 用户的 NETRC 文件。
- netrc 文件覆盖原始 HTTP 身份验证标头 使用 headers= 设置。
auth
- 如果找到主机名的凭据,则使用 HTTP Basic 发送请求 认证。
5、摘要式身份验证
- 另一种非常流行的 HTTP 身份验证形式是摘要式身份验证
from requests.auth import HTTPDigestAuth
import requests
url = 'https://httpbin.org/digest-auth/auth/user/pass'
response = requests.get(url, auth=HTTPDigestAuth('user', 'pass'))
print(response.status_code)
# <Response [200]>
六、异常处理
官方文档:https://docs.python-requests.org/en/latest/api/#requests.RequestException
在使用 Python 的 requests 库发送网络请求时,可能会遇到以下一些常见的异常:
-
requests.exceptions.RequestException:这是所有请求异常的父类,如果发生请求相关的异常,大多数情况下会抛出此异常。
-
requests.exceptions.ConnectionError:当请求失败时(如 DNS 查询失败、拒绝连接等),会引发此异常。
-
requests.exceptions.Timeout:如果请求超时,将引发此异常。
-
requests.exceptions.TooManyRedirects:如果请求重定向次数超过了预设的最大次数,会引发此异常。
-
requests.exceptions.HTTPError:当 HTTP 响应状态码指示请求失败时(如 4xx 客户端错误或 5xx 服务器错误),会引发此异常。
-
requests.exceptions.URLRequired:如果请求中没有提供 URL,会引发此异常。
-
requests.exceptions.TooManyRedirects:如果请求重定向次数超过了预设的最大次数,会引发此异常。
-
requests.exceptions.SSLError:当 SSL 验证失败时,会引发此异常。
这些是 requests 库中一些常见的异常类型。在处理网络请求时,捕获这些异常并适当地处理它们是很重要的,以确保代码的稳定性和可靠性。
七、上传文件
在使用 requests
模块上传文件时,你可以通过files
参数来实现。files
参数允许你指定要上传的文件,可以是单个文件或多个文件。下面是一个简单的示例,演示如何使用requests
模块上传单个文件:
import requests
url = 'http://www.example.com/upload'
file_path = 'path/to/your/file.txt'
files = {'file': open(file_path, 'rb')}
try:
response = requests.post(url, files=files)
response.raise_for_status() # 如果响应状态码不是 2xx,会抛出异常
print('File uploaded successfully!')
except requests.exceptions.RequestException as e:
print(f'Error: {e}')
在这个示例中,我们指定了要上传的文件路径file_path
,然后通过open(file_path, 'rb')
打开文件并将其放入files
字典中。键'file'
是上传文件的字段名,可以根据实际情况进行调整。
接着,我们使用requests.post()
方法发送POST请求,将文件作为files
参数传递给请求。如果上传成功,服务器将返回相应的响应。请确保替换url
和file_path
为实际的上传地址和文件路径。
如果你需要上传多个文件,可以将多个文件添加到files
字典中,如下所示:
files = {
'file1': open('path/to/file1.txt', 'rb'),
'file2': open('path/to/file2.jpg', 'rb'),
'file3': open('path/to/file3.pdf', 'rb')
}
这样,你就可以使用requests
模块方便地上传文件到指定的服务器端。