python中文官方文档:https://docs.python.org/zh-cn/3/
Requests中文官方文档地址:https://requests.readthedocs.io/projects/cn/zh_CN/latest/
1.Requests模块快速入门
requests库的基本使用详解
1.Requests模块作用:发送http请求,获取响应数据
2.Requests模块是第三方模块,需要在python环境中额外安装:pip/pip3 install requests
3.HTTP请求类型
import requests
r = requests.get('https://api.github.com/events') # get类型
r1 = requests.get(url='http://dict.baidu.com/s', params={'wd': 'python'}) # 带参数的get请求
r2 = requests.post("http://m.ctrip.com/post") # post类型
r3 = requests.put("http://m.ctrip.com/put") # put类型
r4 = requests.delete("http://m.ctrip.com/delete") # delete类型
r5 = requests.head("http://m.ctrip.com/head") # head类型
r6 = requests.options("http://m.ctrip.com/get") # options类型
4.通过上面的方法返回的是一个Response对象,该对象有以下一些常用的属性和方法
常用方法和属性 描述
status_code 服务器返回的状态码
text 返回字符串方式的响应体,requests会自动根据响应头部的字符编码进行解码
content 返回字节方式的响应体,会自动解码gzip和deflate压缩
headers 以字典对象存储服务器响应头,但是这个字典比较特殊,字典键不区分大小写,若键不存在则返回None
request.headers 请求头
elapsed.total_seconds() 获取rest请求响应的时间
cookies 返回响应携带的cookies(经过set-cookie动作),返回类型为RequestsCookieJar对象
cookies.get_dict() 以字典形式返回响应的cookie
cookies.items() 以List(set())形式返回响应的cookie
encoding requests猜测的相应内容编码方式,text就是根据该编码格式进行解码
json() 返回内容进行json转换
url 响应的的url,有时候响应的url和请求的url并不一致
raw 获取来自服务器的原始套接字响应
history 追踪重定向,返回一个Response对象列表
raise_for_status() 发送请求出现异常时,可以通过此方法抛出异常
text.encode("ISO-8859-1") "ISO-8859-1":是网页的一种的编码方式,此方法的作用是将get获取到的信息以此方式进行编码
5.requests库使用详解
5.1 使用requests发送get请求
HTTP 中最常见的请求之一就是 GET 请求,下面首先来详细了解一下利用 requests 构建 GET请求的方法。
(1)GET 参数说明:
get(url, params=None, **kwargs):
❖ URL: 待请求的网址
❖ params :(可选)字典,列表为请求的查询字符串发送的元组或字节
❖ **kwargs: 可变长关键字参数
首先,构建一个最简单的 GET 请求,请求的链接为 http://httpbin.org/get ,该网站会判断如果客户端发起的是 GET 请求的话,它返回相应的请求信息,如下就是利用 requests 构建一个 GET请求
#coding = 'utf-8'
import requests
r = requests.get('http://httpbin.org/get')
print(r.text)
{
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.24.0",
"X-Amzn-Trace-Id": "Root=1-5fb5b166-571d31047bda880d1ec6c311"
},
"origin": "36.44.144.134",
"url": "http://httpbin.org/get"
}
5.2 传递url参数
url_params = {'key1': 'value1', 'key2': 'value2'}
r7 = requests.get("http://httpbin.org/get", params=url_params) #字典传递参数,注意字典里值为 None 的键都不会被添加到 URL 的查询字符串里。
print(r7.url)#输出:http://httpbin.org/get?key1=value1&key2=value2
5.3 获取/修改网页编码
#coding = 'utf-8'
import requests
res = requests.get(url='http://dict.baidu.com/s', params={'wd': 'python'})
print(res.encoding) #获取网页编码
res.encoding = 'ISO-8859-1' #修改网页编码
5.4 获取响应内容
5.4.1 res.content
# 以字节的方式去显示,中文显示为字符,这个是直接从网络上面抓取的数据,没有经过任何解码。所以是一个bytes类型。
#其实在硬盘上和在网络上传输的字符串都是bytes类型。
print(res.content)
5.4.2 res.text
# 以文本的方式去显示,这个是requests将response.content进行解码的字符串。解码需要指定一个编码方式,requests会根据自己的猜测来判断编码的方式。
#所以有的时候可能会猜测错误,产生乱码。这时就应该使用response.content.decode('utf-8')指定解码使用的编码方式(这里使用的utf-8)进行手动解码。
#response.content.decode() 默认utf-8
#常见的编码字符集:utf-8、gbk、gb2312、ascii、iso-8859-1
import requests
#目标url
url = 'https://www.baidu.com/'
#向目标url发送get请求
resp = requests.get(url)
#打印响应内容
print(resp.text)#内容乱码
print(resp.encoding)
print(resp.content.decode('utf-8'))#指定解码方式解决乱码问题
5.4.3 获取json格式的响应内容
r = requests.get('https://github.com/timeline.json')
print(r.json())#Requests中有一个内置的 JSON 解码器,助你处理 JSON 数据
#注意:如果 JSON 解码失败,r.json() 就会抛出一个异常。例如,响应内容是 401 (Unauthorized),尝试访问 r.json() 将会抛出 ValueError: No JSON object could be decoded 异常。
#需要注意的是,成功调用 r.json() 并不意味着响应的成功。有的服务器会在失败的响应中包含一个 JSON 对象(比如 HTTP 500 的错误细节)。这种 JSON 会被解码返回。
# 要检查请求是否成功,请使用 r.raise_for_status() 或者检查 r.status_code 是否和你的期望相同。
5.4.4获取原始响应内容
#在罕见的情况下,你可能想获取来自服务器的原始套接字响应,那么你可以访问 r.raw。 使用raw属性时,确保在初始请求中设置了 stream=True。如下所示:
r8 = requests.get('https://api.github.com/events', stream=True)
print(r8.raw)
print(r8.raw.read(10))
6.定制请求头
#在请求头中带上User-Agent,模拟浏览器发送请求
url = 'http://m.ctrip.com'
headers = {'User-Agent' : 'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 4 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19'}
r9 = requests.post(url, headers=headers)
print(r9.request.headers)
#httpbin.org 这个网站能测试 HTTP 请求和响应的各种信息,比如 cookie、ip、headers 和登录验证等,且支持 GET、POST 等多种方法,对 web 开发和测试很有帮助。
#下面用此网站详解request库的使用
7.使用requests库进行post请求
思考:哪些地方我们会用到 POST 请求?
(1) 登录注册(在 web 工程师看来 POST 比 GET 更安全, url 地址中不会暴露用户的账号密码等信息)
(2) 需要传输大文本内容的时候( POST 请求对数据长度没有要求)
所以同样的,我们的爬虫也需要在这两个地方回去模拟浏览器发送 post 请求其实发送 POST 请求与 GET 方式很相似,只是参数的传递我们需要定义在 data 中即可:
(3)POST 参数说明:
post(url, data=None, json=None, **kwargs):
❖ URL: 待请求的网址
❖ data : ( 可选 ) 字典,元组列表,字节或类似文件的对象,以在 Request 的正文中发送
❖ json: ( 可选 )JSON 数据,发送到 Request 类的主体中。
❖ **kwargs: 可变长关键字参数
7.1 给data传字典参数,类似实现HTML中的form表单形式
payload = {'key1': 'value1', 'key2': 'value2'}
r10 = requests.post("http://httpbin.org/post", data=payload)
print(r10.text)
#输出
# {
# "args": {},
# "data": "",
# "files": {},
# "form": {
# "key1": "value1",
# "key2": "value2"
# },
# "headers": {
# "Accept": "*/*",
# "Accept-Encoding": "gzip, deflate",
# "Content-Length": "23",
# "Content-Type": "application/x-www-form-urlencoded",
# "Host": "httpbin.org",
# "User-Agent": "python-requests/2.21.0",
# "X-Amzn-Trace-Id": "Root=1-614c46f4-62d1363a3780f5b76459094e"
# },
# "json": null,
# "origin": "222.211.234.162",
# "url": "http://httpbin.org/post"
# }
7.2 给data传元组列表参数,对应于form表单中多个元素使用同一 key的情况
payload = (('key1', 'value1'), ('key1', 'value2'))
r11 = requests.post('http://httpbin.org/post', data=payload)
print(r11.text)
#输出
# {
# ...
# "form": {
# "key1": [
# "value1",
# "value2"
# ]
# },
# ...
# }
7.3 POST发送JSON数据
很多时候你想要发送的数据并非编码为表单形式的,发现特别在爬取很多 java 网址中出现这个问题。如果你传递一个 string 而不是一个 dict ,那么数据会被直接发布出去。我们可以使用json.dumps() 将 dict 转化成 str 格式 ; 此处除了可以自行对 dict 进行编码,你还可以使用 json 参
数直接传递,然后它就会被自动编码。
# coding=utf-8
import json
import requests
url ="http://httpbin.org/post"
payload = {'some': 'data'}
req1 = requests.post(url, data=json.dumps(payload))
req2 = requests.post(url, json=payload)
print(req1.text)
print(req2.text)
输出的结果
# {
# "args": {},
# "data": "{\"some\": \"data\"}",
# "files": {},
# "form": {},
# "headers": {
# "Accept": "*/*",
# "Accept-Encoding": "gzip, deflate",
# "Content-Length": "16",
# "Host": "httpbin.org",
# "User-Agent": "python-requests/2.27.1",
# "X-Amzn-Trace-Id": "Root=1-64f05a3f-07bb212b673fe65f0fe0f47a"
# },
# "json": {
# "some": "data"
# },
# "origin": "222.210.10.227",
# "url": "http://httpbin.org/post"
# }
7.4 POST一个Multipart-Encoded的文件
7.4.1 POST单个文件
#示例1
url = 'http://httpbin.org/post'
files = {'file': open('report.xls', 'rb')}
r = requests.post(url, files=files)
print(r.text)
#示例2:显式地设置文件名,文件类型和请求头
url = 'http://httpbin.org/post'
files = {'file': (
'report.xls', #文件名
open('report.xls', 'rb'),#文件流
'application/vnd.ms-excel', #请求头Content-Type字段对应的值
{'Expires': '0'})
}
r = requests.post(url, files=files)
#示例3:发送作为文件来接收的字符串
import requests
url = 'http://httpbin.org/post'
files = {'file': ('report.csv', 'some,data,to,send\nanother,row,to,send\n')}
r = requests.post(url, files=files)
print(r.text)
#输出
{
"args": {},
"data": "",
"files": {
"file": "some,data,to,send\nanother,row,to,send\n"
},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "184",
"Content-Type": "multipart/form-data; boundary=2e709f54c60d7bff4b99ee79b0e28197",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.21.0",
"X-Amzn-Trace-Id": "Root=1-614d396f-42e527fa6c6baa544bb12d7d"
},
"json": null,
"origin": "222.211.234.162",
"url": "http://httpbin.org/post"
}
7.4.2 POST多个文件
import requests
#有时需要在一个请求中同时发送多个文件,同样使用files参数传入一个数组即可
files = [
('file1', ('1.png', open('logo.png', 'rb'), 'image/png')),
('file2', ('2.png', open('logo.png', 'rb'), 'image/png'))
]
response = requests.post('http://www.hangge.com/upload.php', files=files)
print(response.text)
7.4.3 上传文件时需要附带其它参数
import requests
data = {
"name": "hangge.com",
"age": 100
}
files = [
('file1', ('1.png', open('logo.png', 'rb'), 'image/png')),
('file2', ('2.png', open('logo.png', 'rb'), 'image/png'))
]
response = requests.post('http://www.hangge.com/upload.php', data=data, files=files)
print(response.text)
7.4.4 流式上传文件
如果有熟悉 WEB 开发的伙伴应该知道,如果你发送一个非常大的文件作为 multipart/form data 请求,你可能希望将请求做成数据流。默认下 requests 不支持 , 你可以使用 requests-toolbelt 三方库。
实例:使用requests-toolbelt 来实现文件的流式上传:
①不同于requests全部读到内存中上传,requests-toolbelt是边读边上传。
②其本质还是multipart/form-data 方式提交数据,所以服务端代码不需要变化。
import requests
from requests_toolbelt import MultipartEncoder
# 边读取文件边上传文件
m = MultipartEncoder(
fields={'name': 'logo.com', # 字段1
"age": '100', # 字段2
'file1': ('1.png', open('logo.png', 'rb'), 'image/png'), # 文件1
'file2': ('2.png', open('logo.png', 'rb'), 'image/png') # 文件2
}
)
r = requests.post('http://www.hangge.com/upload.php', data=m, headers={'Content-Type': m.content_type})
print(r.text)
7.4.5 监听流式上传文件的速度
①requests-toolbelt库还提供了个监视器MultipartEncoderMonitor,该监视器接受一个回调函数,我们可以在回调中实时跟踪进度。
import requests
from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
def my_callback(monitor):
progress = (monitor.bytes_read / monitor.len) * 100
print("\r 文件上传进度:%d%%(%d/%d)" % (progress, monitor.bytes_read, monitor.len), end=" ")
e = MultipartEncoder(
fields={'name': 'logo.com', # 参数1
"age": '100', # 参数2
'file1': ('1.png', open('logo.png', 'rb'), 'image/png'), # 文件1
'file2': ('2.png', open('logo.png', 'rb'), 'image/png') # 文件2
}
)
m = MultipartEncoderMonitor(e, my_callback)
r = requests.post('http://www.hangge.com/upload.php', data=m, headers={'Content-Type': m.content_type})
print(r.text)
8.request 请求总结
requests 模块发送请求有 data 、 json 、 params 三种携带参数的方法
params 在 get 请求中使用, data 、 json 在 post 请求中使用。
data 可以接收的参数为:字典,字符串,字节,文件对象,
❖ 使用 json 参数,不管报文是 str 类型,还是 dict 类型,如果不指定 headers 中 content-type 的类型,默认是: application/json 。
❖ 使用 data 参数,报文是 dict 类型,如果不指定 headers 中 content-type 的类型,默认 application/x-www-form-urlencoded ,相当于普通 form 表单提交的形式,会将表单内的数据转换成键值对,此时数据可以从 request.POST 里面获取,而 request.body 的内容则为 a=1&b=2 的这种键值对形式。
(数据报文:dict字典类型,那么默认情况下请求头中tontent-type为application/x-www-form-urlencoded ,表示以form表单的方式传参,格式:a=1&b=2&c=3)
❖ 使用 data 参数,报文是 str 类型,如果不指定 headers 中 content-type 的类型,默认 text/plain 。
(数据报文:str类型,那么默认情况下headers中的content-type是text/plain,如果是字典格式需要转换为str格式传参)
❖用 data 参数提交数据时, request.body 的内容则为 a=1&b=2 的这种形式,
❖用 json 参数提交数据时, request.body 的内容则为 {"a": 1, "b": 2}的这种形式
❖data只能传简单的只有键值对的dict或者str格式。json一般只传dict格式。嵌套的dict只能用json传参。
json.dumps(data)序列化,把字典格式的数据转换为str格式。
json.loads(data)反序列化,把str格式转换成字典格式
9.状态响应码
r1 = requests.get('http://httpbin.org/get')
print(r1.status_code)
#为方便引用,Requests还附带了一个内置的状态码查询对象:
r.status_code == requests.codes.ok#如果返回的状态码为200,则为True
如果发送了一个错误请求(一个 4XX 客户端错误,或者 5XX 服务器错误响应),我们可以通过 Response.raise_for_status() 来抛出异常:
10.响应头
r2 = requests.get('http://m.ctrip.com')
#a)查看以一个 Python 字典形式展示的服务器响应头
print (r2.headers)
#b)访问响应头字段的两种方式
#headers字典比较特殊:它是仅为 HTTP 头部而生的。根据 RFC 2616, HTTP 头部是大小写不敏感的。因此,我们可以使用任意大小写形式来访问这些响应头字段:
print (r2.headers['Content-Type'])
print (r2.headers.get('content-type'))
11.Cookie
11.1 在headers参数中携带cookie发送请求
网站经常利用请求头中的Cookie字段来做用户访问状态的保持,那么我们可以在headers参数中添加Cookie,模拟普通用户的请求。我们以github登陆为例
github登陆抓包分析
打开浏览器,右键-检查,点击Net work,勾选Preserve log
访问github登陆的url地址 https://github.com/login
输入账号密码点击登陆后,访问一个需要登陆后才能获取正确内容的url,比如点击右上角的Your profile访问https://github.com/USER_NAME
确定url之后,再确定发送该请求所需要的请求头信息中的User-Agent和Cookie
从浏览器中复制User-Agent和Cookie
浏览器中的请求头字段和值与headers参数中必须一致
headers请求参数字典中的Cookie键对应的值是字符串
示例:
import requests
url = 'https://github.com/USER_NAME'
# 构造请求头字典
headers = {
# 从浏览器中复制过来的User-Agent
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36',
#从浏览器中复制过来的Cookie
'Cookie': 'xxx这里是复制过来的cookie字符串'
}
# 请求头参数字典中携带cookie字符串
resp = requests.get(url, headers=headers)
print(resp.text)
11.2 使用cookies参数发送带cookie的请求
cookies参数的形式:字典
cookies = {"cookie的name":"cookie的value"}
该字典对应请求头中Cookie字符串,以分号、空格分割每一对字典键值对
等号左边的是一个cookie的name,对应cookies字典的key,等号右边对应cookies字典的value
注意:cookie一般是有过期时间的,一旦过期需要重新获取
示例1:将网页直接复制的cookie字符串转换为cookies参数所需的字典后进行请求发送
import requests
url = 'https://github.com/USER_NAME'
# 构造请求头字典
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'
}
# 构造cookies字典
cookies_str = '从浏览器中copy过来的cookies字符串'
cookies_dict = {cookie.split('=')[0]:cookie.split('=')[-1] for cookie in cookies_str.split('; ')}
# 请求头参数字典中携带cookie字符串
resp = requests.get(url, headers=headers, cookies=cookies_dict)
print(resp.text)
示例2:
url = 'http://httpbin.org/cookies'
cookies = dict(cookies_are='working')
r4 = requests.get(url, cookies=cookies)
print(r4.text)
#输出
# {
# "cookies": {
# "cookies_are": "working"
# }
# }
11.3 读取cookies,将cookieJar对象转换为cookies字典或列表
import requests
url = 'https://www.baidu.com/'
r3 = requests.get(url)
print(r3.cookies)#<RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
print(r3.cookies.get_dict())#{'BDORZ': '27315'}
print(r3.cookies.items())#[('BDORZ', '27315')]
11.4 通过cookie名访问对应的cookie值
url = 'http://example.com/some/cookie/setting/url'
r = requests.get(url)
print(r.cookies['example_cookie_name'])
#'example_cookie_value'
12设置超时时间
#你可以告诉 requests 在经过以 timeout 参数设定的秒数时间之后停止等待响应。基本上所有的生产代码都应该使用这一参数。如果不使用,你的程序可能会永远失去响应:
#:发送请求后,timeout秒钟内返回响应,否则就抛出异常
r = requests.get('http://m.ctrip.com', timeout=0.001)
13.设置访问代理
1)proxy代理参数通过指定代理ip,让代理ip对应的正向代理服务器转发我们发送的请求,那么我们首先来了解一下代理ip以及代理服务器
2)理解使用代理的过程:代理ip是一个ip,指向的是一个代理服务器,代理服务器能够帮我们向目标服务器转发请求
3)正向代理和反向代理的区别:
前边提到proxy参数指定的代理ip指向的是正向的代理服务器,那么相应的就有反向服务器;现在来了解一下正向代理服务器和反向代理服务器的区别
从发送请求的一方的角度,来区分正向或反向代理
为浏览器或客户端(发送请求的一方)转发请求的,叫做正向代理;浏览器知道最终处理请求的服务器的真实ip地址,例如VPN
不为浏览器或客户端(发送请求的一方)转发请求、而是为最终处理请求的服务器转发请求的,叫做反向代理;浏览器不知道服务器的真实地址,例如nginx
4)代理ip分类
A.根据代理ip的匿名程度,代理IP可以分为下面三类:
透明代理(Transparent Proxy):透明代理虽然可以直接“隐藏”你的IP地址,但是还是可以查到你是谁。目标服务器接收到的请求头如下:
REMOTE_ADDR = Proxy IP
HTTP_VIA = Proxy IP
HTTP_X_FORWARDED_FOR = Your IP
匿名代理(Anonymous Proxy):使用匿名代理,别人只能知道你用了代理,无法知道你是谁。目标服务器接收到的请求头如下:
REMOTE_ADDR = proxy IP
HTTP_VIA = proxy IP
HTTP_X_FORWARDED_FOR = proxy IP
高匿代理(Elite proxy或High Anonymity Proxy):高匿代理让别人根本无法发现你是在用代理,所以是最好的选择。毫无疑问使用高匿代理效果最好。目标服务器接收到的请求头如下:
REMOTE_ADDR = Proxy IP
HTTP_VIA = not determined
HTTP_X_FORWARDED_FOR = not determined
B.根据网站所使用的协议不同,需要使用相应协议的代理服务。从代理服务请求使用的协议可以分为:
http代理:目标url为http协议
https代理:目标url为https协议
socks隧道代理(例如socks5代理)等:
socks 代理只是简单地传递数据包,不关心是何种应用协议(FTP、HTTP和HTTPS等)。
socks 代理比http、https代理耗时少。
socks 代理可以转发http和https的请求
5)为了让服务器以为不是同一个客户端在请求;为了防止频繁向一个域名发送请求被封ip,所以我们需要使用代理ip;那么我们接下来要学习requests模块是如何使用代理ip的
使用示例:
proxies = {
"http": "http://10.10.1.10:3128",
"https": "http://10.10.1.100:4444",
}
r = requests.get('http://m.ctrip.com', proxies=proxies)
#如果代理需要用户名和密码,则需要这样:
proxies = {
"http": "http://user:[email protected]:3128/",
}
14.使用verify参数忽略CA证书
#在使用浏览器上网的时候,有时能够看到证书提示
#运行代码查看代码中向不安全的链接发起请求的效果
#运行下面的代码将会抛出包含ssl.CertificateError ...字样的异常
import requests
url = "https://sam.huat.edu.cn:8443/selfservice/"
response = requests.get(url)
#解决方案:
为了在代码中能够正常的请求,我们使用verify=False参数,此时requests模块发送请求将不做CA证书的验证:verify参数能够忽略CA证书的认证
import requests
url = "https://sam.huat.edu.cn:8443/selfservice/"
response = requests.get(url,verify=False)
15.重定向与请求历史
#默认情况下,除了 HEAD, Requests 会自动处理所有重定向。可以使用响应对象的 history 方法来追踪重定向。
#Response.history 是一个 Response 对象的列表,为了完成请求而创建了这些对象。这个对象列表按照从最老到最近的请求进行排序。
#例如,Github 将所有的 HTTP 请求重定向到 HTTPS:
import requests
headers = {'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36"}
r = requests.get('http://github.com/',headers=headers)
print(r.url)#https://github.com/
print(r.status_code)#200
print(r.history)#[<Response [301]>]
#如果你使用的是GET、OPTIONS、POST、PUT、PATCH 或者 DELETE,那么你可以通过 allow_redirects 参数禁用重定向处理:
r = requests.get('http://github.com', headers=headers,allow_redirects=False)
print(r.status_code)#301(301状态码指网页被永久重定向)
print(r.history)#[]
#如果你使用了 HEAD,你也可以启用重定向
r = requests.head('http://github.com', allow_redirects=True)
print(r.url)#'https://github.com/'
print(r.history) #[<Response [301]>]
16.错误与异常
16.1官网提及的异常
遇到网络问题(如:DNS 查询失败、拒绝连接等)时,Requests 会抛出一个 ConnectionError 异常。
如果 HTTP 请求返回了不成功的状态码, Response.raise_for_status() 会抛出一个 HTTPError 异常。
若请求超时,则抛出一个 Timeout 异常。
若请求超过了设定的最大重定向次数,则会抛出一个 TooManyRedirects 异常。
所有Requests显式抛出的异常都继承自 requests.exceptions.RequestException 。
16.2requests模块内置异常的层次结构
IOError
+-- RequestException # 处理不确定的异常请求
+-- HTTPError # HTTP错误
+-- ConnectionError # 连接错误
| +-- ProxyError # 代理错误
| +-- SSLError # SSL错误
| +-- ConnectTimeout(+-- Timeout) # (双重继承,下同)尝试连接到远程服务器时请求超时,产生此错误的请求可以安全地重试。
+-- Timeout # 请求超时
| +-- ReadTimeout # 服务器未在指定的时间内发送任何数据
+-- URLRequired # 发出请求需要有效的URL
+-- TooManyRedirects # 重定向太多
+-- MissingSchema(+-- ValueError) # 缺少URL架构(例如http或https)
+-- InvalidSchema(+-- ValueError) # 无效的架构,有效架构请参见defaults.py
+-- InvalidURL(+-- ValueError) # 无效的URL
| +-- InvalidProxyURL # 无效的代理URL
+-- InvalidHeader(+-- ValueError) # 无效的Header
+-- ChunkedEncodingError # 服务器声明了chunked编码但发送了一个无效的chunk
+-- ContentDecodingError(+-- BaseHTTPError) # 无法解码响应内容
+-- StreamConsumedError(+-- TypeError) # 此响应的内容已被使用
+-- RetryError # 自定义重试逻辑失败
+-- UnrewindableBodyError # 尝试倒回正文时,请求遇到错误
+-- FileModeWarning(+-- DeprecationWarning) # 文件以文本模式打开,但Requests确定其二进制长度
+-- RequestsDependencyWarning # 导入的依赖项与预期的版本范围不匹配
Warning
+-- RequestsWarning # 请求的基本警告
实际应用常见异常举例:
(1)连接超时
服务器在指定时间内没有应答,抛出 requests.exceptions.ConnectTimeout
requests.get('http://github.com', timeout=0.001)
# 抛出错误
requests.exceptions.ConnectTimeout: HTTPConnectionPool(host='github.com', port=80): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x7f1b16da75f8>, 'Connection to github.com timed out. (connect timeout=0.001)'))
(2)连接、读取超时
若分别指定连接和读取的超时时间,服务器在指定时间没有应答,抛出 requests.exceptions..ReadTimeout
- timeout=([连接超时时间], [读取超时时间])
- 连接:客户端连接服务器并并发送http请求服务器
- 读取:客户端等待服务器发送第一个字节之前的时间
requests.get('http://github.com', timeout=(6.05, 0.01))
# 抛出错误
requests.exceptions.ReadTimeout: HTTPConnectionPool(host='github.com', port=80): Read timed out. (read timeout=0.01)
(3)未知的服务器
抛出 requests.exceptions.ConnectionError
requests.get('http://github.comasf', timeout=(6.05, 27.05))
# 抛出错误
requests.exceptions.ConnectionError: HTTPConnectionPool(host='github.comasf', port=80): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f75826665f8>: Failed to establish a new connection: [Errno -2] Name or service not known',))
(4) 代理连接不上
代理服务器拒绝建立连接,端口拒绝连接或未开放,抛出 requests.exceptions.ProxyError
requests.get('http://github.com', timeout=(6.05, 27.05), proxies={"http": "192.168.10.1:800"})
# 抛出错误
requests.exceptions.ProxyError: HTTPConnectionPool(host='192.168.10.1', port=800): Max retries exceeded with url: http://github.com/ (Caused by ProxyError('Cannot connect to proxy.', NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fce3438c6d8>: Failed to establish a new connection: [Errno 111] Connection refused',)))
(5) 连接代理超时
代理服务器没有响应 requests.exceptions.ConnectTimeout
requests.get('http://github.com', timeout=(6.05, 27.05), proxies={"http": "10.200.123.123:800"})
# 抛出错误
requests.exceptions.ConnectTimeout: HTTPConnectionPool(host='10.200.123.123', port=800): Max retries exceeded with url: http://github.com/ (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x7fa8896cc6d8>, 'Connection to 10.200.123.123 timed out. (connect timeout=6.05)'))
(6)代理读取超时
说明与代理建立连接成功,代理也发送请求到目标站点,但是代理读取目标站点资源超时
即使代理访问很快,如果代理服务器访问的目标站点超时,这个锅还是代理服务器背
假定代理可用,timeout就是向代理服务器的连接和读取过程的超时时间,不用关心代理服务器是否连接和读取成功
requests.get('http://github.com', timeout=(2, 0.01), proxies={"http": "192.168.10.1:800"})
# 抛出错误
requests.exceptions.ReadTimeout: HTTPConnectionPool(host='192.168.10.1:800', port=1080): Read timed out. (read timeout=0.5)
(7)网络环境异常
可能是断网导致,抛出 requests.exceptions.ConnectionError
requests.get('http://github.com', timeout=(6.05, 27.05))
# 抛出错误
requests.exceptions.ConnectionError: HTTPConnectionPool(host='github.com', port=80): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fc8c17675f8>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution',))
requests库的基本使用详解
Request详解
1)get 请求
# a、无参数实例
import requests
ret = requests.get('https://github.com/timeline.json')
print ret.url
print ret.text
# b、有参数实例
import requests
payload = {'key1': 'value1', 'key2': 'value2'}
ret = requests.get("http://httpbin.org/get", params=payload)
print ret.url
print ret.text
2)Post请求
# a、基本POST实例
import requests
payload = {'key1': 'value1', 'key2': 'value2'}
ret = requests.post("http://httpbin.org/post", data=payload)
print ret.text
# b、发送请求头和数据实例
import requests
import json
url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}
headers = {'content-type': 'application/json'}
ret = requests.post(url, data=json.dumps(payload), headers=headers)
print ret.text
print ret.cookies
3)其他请求
requests.get(url, params=None, **kwargs)
requests.post(url, data=None, json=None, **kwargs)
requests.put(url, data=None, **kwargs)
requests.head(url, **kwargs)
requests.delete(url, **kwargs)
requests.patch(url, data=None, **kwargs)
requests.options(url, **kwargs)
# 以上方法均是在此方法的基础上构建
requests.request(method, url, **kwargs)
4)request方法参数详解
def request(method, url, **kwargs):
"""Constructs and sends a :class:`Request <Request>`.
:param method: method for the new :class:`Request` object.
:param url: URL for the new :class:`Request` object.
:param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`.
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
:param json: (optional) json data to send in the body of the :class:`Request`.
:param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
:param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.
:param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload.
``file-tuple`` can be a 2-tuple ``('filename', fileobj)``, 3-tuple ``('filename', fileobj, 'content_type')``
or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``, where ``'content-type'`` is a string
defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers
to add for the file.
:param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
:param timeout: (optional) How long to wait for the server to send data
before giving up, as a float, or a :ref:`(connect timeout, read
timeout) <timeouts>` tuple.
:type timeout: float or tuple
:param allow_redirects: (optional) Boolean. Set to True if POST/PUT/DELETE redirect following is allowed.
:type allow_redirects: bool
:param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.
:param verify: (optional) whether the SSL cert will be verified. A CA_BUNDLE path can also be provided. Defaults to ``True``.
:param stream: (optional) if ``False``, the response content will be immediately downloaded.
:param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
:return: :class:`Response <Response>` object
:rtype: requests.Response
Usage::
>>> import requests
>>> req = requests.request('GET', 'http://httpbin.org/get')
<Response [200]>
"""
参数详解
#1)--param url:请求地址
def param_method_url():
# requests.request(method='get', url='http://127.0.0.1:8000/test/')
# requests.request(method='post', url='http://127.0.0.1:8000/test/')
pass
#2)--param params:在URL地址中传递的参数
def param_param():
# - 可以是字典
# - 可以是字符串
# - 可以是字节(ascii编码以内)
# requests.request(method='get',
# url= 'http://www.oldboyedu.com',
# params={'k1': 'v1', 'k2': 'v2'})
# 实际请求的地址为http://www.oldboyedu.com?k1=v1&k2=v2
# requests.request(method='get',
# url='http://127.0.0.1:8000/test/',
# params="k1=v1&k2=水电费&k3=v3&k3=vv3")
# requests.request(method='get',
# url='http://127.0.0.1:8000/test/',
# params=bytes("k1=v1&k2=k2&k3=v3&k3=vv3", encoding='utf8'))
# 错误
# requests.request(method='get',
# url='http://127.0.0.1:8000/test/',
# params=bytes("k1=v1&k2=水电费&k3=v3&k3=vv3", encoding='utf8'))
pass
#3)--param data:在请求体中传递的数据
def param_data():
# 可以是字典
# 可以是字符串
# 可以是字节
# 可以是文件对象
# requests.request(method='POST',
# url= 'http://www.oldboyedu.com',
#params = {'k1':'v1','k2':'v2'},
# data = {'use':'alex','pwd': '123','x':[11,2,3]})
#此时,content-type为application/x-www-form-urlencoded
# requests.request(method='POST',
# url='http://127.0.0.1:8000/test/',
# data="k1=v1& k2=v2& k3=v3&k3=v4"
# )
# requests.request(method='POST',
# url='http://127.0.0.1:8000/test/',
# data="k1=v1&k2=v2&k3=v3&k3=v4",
# headers={'Content-Type': 'application/x-www-form-urlencoded'}
# )
# requests.request(method='POST',
# url='http://127.0.0.1:8000/test/',
# data=open('data_file.py', mode='r', encoding='utf-8'), # 文件内容是:k1=v1;k2=v2;k3=v3;k3=v4
# headers={'Content-Type': 'application/x-www-form-urlencoded'}
# )
pass
#4)--param json:在请求体里传递的数据
def param_json():
# 将json中对应的数据进行序列化成一个字符串,json.dumps(...)
# 然后发送到服务器端的body中,并且Content-Type是 {'Content-Type': 'application/json'}
requests.request(
method='POST',
url= 'http://www.oldboyedu.com',
params = {'k1':'v1','k2':'v2'},
json = {'use':'alex','pwd': '123'}
)
#即此时请求头: content-type: application/json,请求体:"{'use':'alex','pwd': '123'}",字典中嵌套字典时,只能用此json格式发请求体
#5)--param headers:请求头
def param_headers():
# 发送请求头到服务器端
requests.request(
method='POST',
url= 'http://www.oldboyedu.com',
params = {'k1':'v1','k2':'v2'},
json = {'use':'alex','pwd': '123'},
headers={
'Referer': 'http://dig.chouti.com/',
'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
}
)
#6)--param cookies
def param_cookies():
# 发送Cookie到服务器端
requests.request(method='POST',
url='http://127.0.0.1:8000/test/',
data={'k1': 'v1', 'k2': 'v2'},
cookies={'cook1': 'value1'},
)
# 也可以使用CookieJar(字典形式就是在此基础上封装)
from http.cookiejar import CookieJar
from http.cookiejar import Cookie
obj = CookieJar()
obj.set_cookie(Cookie(version=0, name='c1', value='v1', port=None, domain='', path='/', secure=False, expires=None,
discard=True, comment=None, comment_url=None, rest={'HttpOnly': None}, rfc2109=False,
port_specified=False, domain_specified=False, domain_initial_dot=False, path_specified=False)
)
requests.request(method='POST',
url='http://127.0.0.1:8000/test/',
data={'k1': 'v1', 'k2': 'v2'},
cookies=obj)
#7)--param files:上传文件
def param_files():
# 发送文件
# file_dict = {
# 'f1': open('readme', 'rb')
# }
# requests.request(method='POST',
# url='http://127.0.0.1:8000/test/',
# files=file_dict)
# 发送文件,定制文件名
# file_dict = {
# 'f1': ('test.txt', open('readme', 'rb'))
# }
# requests.request(method='POST',
# url='http://127.0.0.1:8000/test/',
# files=file_dict)
# 发送文件,定制文件名
# file_dict = {
# 'f1': ('test.txt', "hahsfaksfa9kasdjflaksdjf")
# }
# requests.request(method='POST',
# url='http://127.0.0.1:8000/test/',
# files=file_dict)
# 发送文件,定制文件名
# file_dict = {
# 'f1': ('test.txt', "hahsfaksfa9kasdjflaksdjf", 'application/text', {'k1': '0'})
# }
# requests.request(method='POST',
# url='http://127.0.0.1:8000/test/',
# files=file_dict)
pass
#8)--param auth:认证
def param_auth():
from requests.auth import HTTPBasicAuth, HTTPDigestAuth
ret = requests.get('https://api.github.com/user', auth=HTTPBasicAuth('wupeiqi', 'sdfasdfasdf'))
print(ret.text)
# ret = requests.get('http://192.168.1.1',
# auth=HTTPBasicAuth('admin', 'admin'))
# ret.encoding = 'gbk'
# print(ret.text)
# ret = requests.get('http://httpbin.org/digest-auth/auth/user/pass', auth=HTTPDigestAuth('user', 'pass'))
# print(ret)
#
#9)--param timeout:响应超时时间
def param_timeout():
# ret = requests.get('http://google.com/', timeout=1)
# print(ret)
# ret = requests.get('http://google.com/', timeout=(5, 1))
# print(ret)
pass
#10)--param allow_redirects:是否允许重定向
def param_allow_redirects():
ret = requests.get('http://127.0.0.1:8000/test/', allow_redirects=False)
print(ret.text)
#11)--param proxies:代理
def param_proxies():
# proxies = {
# "http": "61.172.249.96:80",
# "https": "http://61.185.219.126:3128",
# }
# proxies = {'http://10.20.1.128': 'http://10.10.1.10:5323'}
# ret = requests.get("http://www.proxy360.cn/Proxy", proxies=proxies)
# print(ret.headers)
# from requests.auth import HTTPProxyAuth
#
# proxyDict = {
# 'http': '77.75.105.165',
# 'https': '77.75.105.165'
# }
# auth = HTTPProxyAuth('username', 'mypassword')
#
# r = requests.get("http://www.google.com", proxies=proxyDict, auth=auth)
# print(r.text)
pass
#12)--param stream
def param_stream():
ret = requests.get('http://127.0.0.1:8000/test/', stream=True)
print(ret.content)
ret.close()
# from contextlib import closing
# with closing(requests.get('http://httpbin.org/get', stream=True)) as r:
# # 在此处理响应。
# for i in r.iter_content():
# print(i)
#13) --param session:用于保存客户端历史访问信息
def requests_session():
import requests
session = requests.Session()
### 1、首先登陆任何页面,获取cookie
i1 = session.get(url="http://dig.chouti.com/help/service")
### 2、用户登陆,携带上一次的cookie,后台对cookie中的 gpsd 进行授权
i2 = session.post(
url="http://dig.chouti.com/login",
data={
'phone': "8615131255089",
'password': "xxxxxx",
'oneMonth': ""
}
)
i3 = session.post(
url="http://dig.chouti.com/link/vote?linksId=8589623",
)
print(i3.text)
Request详解
2.Requests模块进阶使用
2.1 Requests库中的session对象
session用法详解:
1 1.cookie和session简介
2
3 http协议本身是无状态的,为了让请求之间保持状态,有了session和cookie机制。cookie在客户的浏览器上,session存在服务器上。cookie是不安全的,且有失效时间,session是
4 在cookie的基础上,服务端设置session时会向浏览器发送设置一个设置cookie的请求,这个cookie包括session的id,当访问服务端时带上这个session_id就可以获取到用户保存在服
5 务端对应的session。
6
7 爬虫处理cookie和session
8 带上cookie和session的好处:能够请求到登录后的界面
9 带上cookie和session的弊端:一个cookie和session往往和一个用户对应,访问太快容易被服务器检测出来爬虫
10
11 2.requests库中的session对象
12 request提供了一个叫做session的类,来实现客户端和服务端的会话保持。
13 requests模块中的session对象能够让我们跨http请求保持某些参数,即让同一个session对象发送的请求头携带某个指定的参数。当然,最常见的应用是它可以让cookie保持在后续的
14 一串请求中。
15
16 2.1会话对象的基本使用
17
18 #会话对象让你能够跨请求保持某些参数。它也会在同一个 Session 实例发出的所有请求之间保持 cookie, 期间使用 urllib3 的 connection pooling 功能。所以如果你向同一主机
19 #发送多个请求,底层的 TCP 连接将会被重用,从而带来显著的性能提升。
20 #会话对象具有主要的 Requests API 的所有方法。
21
22 2.1.1 跨请求保持一些cookie
23
24 import requests
25 s = requests.Session()
26 # 第一步:发送一个请求,用于设置请求中的cookies
27 # tips: http://httpbin.org能够用于测试http请求和响应
28 s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
29 # 第二步:再发送一个请求,用于查看当前请求中的cookies
30 r = s.get("http://httpbin.org/cookies")
31 print(r.text)
32 #输出
33 # {
34 # "cookies": {
35 # "sessioncookie": "123456789"
36 # }
37 # }
38
39 #从结果中我们可以看出,第二次请求已经携带上了第一次请求所设置的cookie,即通过session达到了保持cookie的目的。示例中创建了一个requests.Session()对象,通过该对象来
40 #进行http请求操作,该操作基本类似于requests.request()
41
42 2.1.2 为请求方法提供缺省数据
43 #由于session让请求之间具有了连贯性,那么,就有了跨请求参数和非跨请求参数的区别。即有时我想让所有请求均带有某个参数,而有时我只是想让单独的一条请求带上临时的参数。
44 通过下面的例子来了解如何使用。
45
46 import requests
47
48 s = requests.Session()
49 s.headers.update({'x-test': 'true'})
50 # both 'x-test' and 'x-test2' are sent
51 r1 = s.get('http://httpbin.org/headers', headers={'x-test2': 'true'})
52 print(r1.text)
53 # 'x-test' is sent
54 r2 = s.get('http://httpbin.org/headers')
55 print(r2.text)
56
57 #输出
58 # r1.text
59 {
60 "headers": {
61 "Accept": "*/*",
62 "Accept-Encoding": "gzip, deflate",
63 "Host": "httpbin.org",
64 "User-Agent": "python-requests/2.22.0",
65 "X-Amzn-Trace-Id": "Root=1-5e91656f-b99f14a4d6f47f9e55a90bb4",
66 "X-Test": "true",
67 "X-Test2": "true"
68 }
69 }
70 # r2.text
71 {
72 "headers": {
73 "Accept": "*/*",
74 "Accept-Encoding": "gzip, deflate",
75 "Host": "httpbin.org",
76 "User-Agent": "python-requests/2.22.0",
77 "X-Amzn-Trace-Id": "Root=1-5e91656f-e9741db4c2ca2fd6e0628396",
78 "X-Test": "true"
79 }
80 }
81
82 从结果中我们可以得出两条结论:
83 1)session可以为请求方法提供缺省数据,比如第一次请求中的{'x-test': 'true'}就是缺省数据,此时的缺省数据就是跨请求参数。
84 2)方法级别的参数不会被跨请求保持,比如第二次请求时,没有携带headers={'x-test2': 'true'},返回的结果中也没有{'x-test2': 'true'},
85 说明该参数没有在第一次请求后被保持住。
86
87
88 2.1.3 会话用作前后文管理器:
89
90 with requests.Session() as s:
91 s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
92
93 这样就能确保 with 区块退出后会话能被关闭,即使发生了异常也一样。
94
95
96 2.1.4手动为会话添加cookie
97 session()中添加cookie有两种情况,第一种cookie传参为字典格式,则需要通过requests.cookies.RequestsCookieJar()的set方法将转换成Jar包格式然后update到session()对象中,
98 第二种cookie直接传参Jar包格式。这种直接update将cookies更新到session()对象中
99
100 #coding = 'utf-8'
101 import requests
102 # 字典格式cookie添加方法
103 r = requests.session()
104 cookie = {"cookie1": "value_1", "cookie2": "value2"}
105 c = requests.cookies.RequestsCookieJar()
106 for key, value in cookie.items():
107 c.set(key, value) # 添加cookie到RequestsCookieJar中
108 r.cookies.update(c) # 将RequestsCookieJar中的cookie更新到session()中
109 print(r.cookies)
110
111 # jar包格式cookie添加方法
112 s = requests.session()
113 print(s.cookies) # 打印session会话中cookies为空
114 s.cookies.update(r.cookies) # 将变量r中的jar包格式cookie直接更新到赋值session对象的变量s中
115 print(s.cookies)
session
使用session模拟登录gitup,并访问登录后的页面
session练习
#coding=utf-8
import requests
from lxml import etree
class Login(object):
def __init__(self):
self.headers = {
'Referer': 'https: // github.com /',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36',
'Host': 'github.com'
}
self.login_url = 'https://github.com/login'
self.post_url = 'https://github.com/session'
self.logined_url = 'https://github.com/settings/profile'
# 创建一个session对象
self.session = requests.Session()
#创建一个html解析对象
self.parser = etree.HTMLParser()
def get_token(self):
# 该方法用于获取登录界面中表单需要提交的authenticity_token值
resp = self.session.get(self.login_url,headers = self.headers)
if resp.status_code == 200:
print("获取登录页面成功")
root = etree.fromstring(resp.text,parser=self.parser)
token_value = root.xpath('//div[@class="auth-form-body mt-3"]//input[1]/@value')[0]
return token_value
def login(self,email,password):
#构造登录数据
post_data = {
'commit': 'Sign in',
'utf8': '✓',
'authenticity_token': self.get_token(),
'login': email,
'password': password
}
if post_data['authenticity_token']:
resp = self.session.post(self.post_url,data=post_data,headers =self.headers)
if resp.status_code == 200:
print('成功登录')
#登录成功后将cookie手动添加到会话
print(self.session.cookies)
self.session.cookies.update(resp.cookies)
print(self.session.cookies)
def logined(self):
#访问登录后的页面
r = self.session.get(self.logined_url,headers=self.headers)
if r.status_code == 200:
print(r.url)
print("成功访问登录后页面")
html = r.text
root = etree.fromstring(html,parser=self.parser)
user_name = root.xpath('//input[@name="user[profile_name]"]/@value')
return user_name
if __name__ == '__main__':
# 类的实例化类似函数调用方式
login = Login()
# 使用点号 . 来访问对象的属性
login.login(email='youremail', password='yourpassword')
user_name = login.logined()
print(user_name)
session练习
2.2 使用Prepared Request对象
任何时候进行了类似 requests.get() 的调用,你都在做两件主要的事情。其一,你在构建一个 Request 对象, 该对象将被发送到某个服务器请求或查询一些资源。其二,一旦 requests 得到一个从服务器返回的响应就会产生一个 Response 对象。该响应对象包含服务器返回的所有信息,也包含你原来创建的 Request 对象。那么这个 Request 是什么类型呢?实际上它就是 Prepared Request。我们可以不用 get 方法,直接构造一个 Prepared Request 对象来进行请求,实现代码如下:
from requests import Request, Session
url = 'http://httpbin.org/post'
data = {'name': 'yourname'}
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36'
}
s = Session()
req = Request('POST', url, data=data, headers=headers)
prepped = s.prepare_request(req)
r = s.send(prepped)
print(r.text)
这里我们引入了 Request,然后用 url、data 和 headers 参数构造了一个 Request 对象,这时需要再调用 Session 的 prepare_request 方法将其转换为一个
Prepared Request 对象,然后调用 send 方法发送,运行结果如下:
# {
# "args": {},
# "data": "",
# "files": {},
# "form": {
# "name": "yourname"
# },
# "headers": {
# "Accept": "*/*",
# "Accept-Encoding": "gzip, deflate",
# "Content-Length": "13",
# "Content-Type": "application/x-www-form-urlencoded",
# "Host": "httpbin.org",
# "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36",
# "X-Amzn-Trace-Id": "Root=1-61517b12-390a281254c2f1390a24fa04"
# },
# "json": null,
# "origin": "222.211.232.81",
# "url": "http://httpbin.org/post"
# }
可以看到,我们达到了同样的 POST 请求效果。有了 Request 这个对象,就可以将请求当作独立的对象来看待,这样在一些场景中我们可以直接操作这个 Request 对象,
更灵活地实现请求的调度和各种操作。
直接构造一个 Prepared Request 对象来进行请求
直接构造一个 Prepared Request 对象来进行请求
有时在发送请求之前,你需要对 body 或者 header (或者别的什么东西)做一些额外处理,下面演示了一个简单的做法:
from requests import Request, Session
s = Session()
req = Request('GET', url,
data=data
headers=headers
)
prepped = s.prepare_request(req)
# do something with prepped.body
# do something with prepped.headers
resp = s.send(prepped,
stream=stream,
verify=verify,
proxies=proxies,
cert=cert,
timeout=timeout
)
print(resp.status_code)
2.3 SSL 证书验证
Requests 可以为 HTTPS 请求验证 SSL 证书,就像 web 浏览器一样。SSL 验证默认是开启的,如果证书验证失败,Requests 会抛出 SSLError:
你可以为 verify 传入 CA_BUNDLE 文件的路径,或者包含可信任 CA 证书文件的文件夹路径:
requests.get('https://github.com', verify='/path/to/certfile')
或者将其保持在会话中:
s = requests.Session()
s.verify = '/path/to/certfile'
注意:如果 verify 设为文件夹路径,文件夹必须通过 OpenSSL 提供的 c_rehash 工具处理。
你还可以通过 REQUESTS_CA_BUNDLE 环境变量定义可信任 CA 列表。
如果你将 verify 设置为 False,Requests 也能忽略对 SSL 证书的验证。
默认情况下, verify 是设置为 True 的。选项 verify 仅应用于主机证书。
标签:http,请求,get,python,url,模块,print,Requests,requests
From: https://blog.csdn.net/weixin_39926295/article/details/143292467