版本是 request-2.22.0
init 初始化 一些信息 将各个包都导入
主要是这一句
from .api import request, get, head, post, patch, put, delete, options
这是从api 那里导入了 这么多的功能
api中导出的这些都是基于 request 方法的
get head等是对他的方法的封装
从其他模块导入到 __init__
这样直接就能 from request import
了
是在api.py下的
request方法 注释 参数很详细
request方法参数
1 | def request(method, url, **kwargs): |
特别是有个json 可以 直接 json=data 这样就发送的就是直接将data转为json发送了
比如说 get 就是对rquest的method进行了封装
get方法参数
1 | def get(self, url, **kwargs): |
根本还是 request里面的使用 session的request来创建
1 | with sessions.Session() as session: |
这个用于提供cookie持久性、连接池和配置
都是实例化 Session来发起请求的
设置 包含哪些属性 __attrs__
接下来我们看 __init__
初始化方法
比较多
1 | # 设置默认清头 |
1 | # 默认的身份验证 |
1 | # 代理 |
1 | # 事件动作钩子 |
1 | # 参数 |
1 | # 默认响应流 |
1 | # 默认是对ssl验证 |
1 | # 默认证书 |
1 | # 允许的最大重定向数 30 |
1 | # 代理的身份验证 |
1 | # cookiejar 对cookie的管理 |
1 | # 默认适配器 是一个有序字典 |
1 | # 将连接适配器注册到前缀适配器按前缀长度降序排序 |
重写了 enter 方法 和 exit方法
这样可用于 with open 来操作 也就是自动关闭
1 | def __enter__(self): |
以上就是 init
接下来
如果我们正常一个get请求是怎样的
1 | def get(self, url, **kwargs): |
如下注释
还可以看文档 https://2.python-requests.org//zh_CN/latest/api.html
1 | """ |
创建一个 Request对象
1 | req = Request( |
Request
Request 是从 models导入的from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT
我们跟入查看下
在 198行位置
参数就是上面session中那些传入的参数
对于直接打印输出的是在这
1 | def __repr__(self): |
在session的request方法中 是直接获取初始化的request对象
后调用 prepare_request方法prep = self.prepare_request(req)
这个方法会返回 requests.PreparedRequest
正常来说直接调用 Request的 prepare方法也是返回 PreparedRequest实例的对象
那为啥又要回到session创建呢
继续往下看
添加cookie, auth
然后创建 PreparedRequest 实例
区别是在创建的时候使用了方法 merge_setting
对一些参数处理
即是把 request的和session的参数合并到一起再创建这个 PreparedRequest实例
models下的Request 的创建 PreparedRequest
实例
1 | def prepare(self): |
session下的的=创建 PreparedRequest
实例
1 | p = PreparedRequest() |
为什么没有直接一起传入参数直接创建返回一个实例而是创建完的
reques再合并session的数据后再创建
主要的类就是这个了 PreparedRequest
是一个准备的请求类
初始化就是对之前传入的参数进行初始化
在 models的 272行
1 | class PreparedRequest(RequestEncodingMixin, RequestHooksMixin): |
返回 PreparedRequest 实例后
更新要发送的数据字典并调用 send方法
跟入send方法 (发送 PreparedRequest)
各种获取request的参数值
1 | def send(self, request, **kwargs): |
对于 start 即请求的开始时间如下获取
1 | if sys.platform == 'win32': |
然后调用 发起请求
r = adapter.send(request, **kwargs)
get_adapter 返回的是 adapters.BaseAdapter
调用的send方法就是 这个
1 | class BaseAdapter(object): |
调用的是这个发送
但是如果是基类的话怎么有这个send方法呢
那就要往回看
设置默认的适配器
1 | # Default connection adapters. |
使用适配器的概念,匹配前缀url来使用对于的适配器来操作
这样 我们就要看 HTTPAdapter
1 | import requests |
可以看到使用就是这样的
可以看到可以获取的几个属性
1 | __attrs__ = ['max_retries', 'config', '_pool_connections', '_pool_maxsize', |
初始化可以看到是一个连接池
self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block)
初始化urllib3池管理器
对urlli3进行了连接池的管理
创建 PoolManager
1 | self.poolmanager = PoolManager(num_pools=connections, maxsize=maxsize,block=block, strict=True, **pool_kwargs) |
这个 PoolManager 是urllib3中的
那么继续看下send方法
1 | def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None): |
首先创建一个连接对象
1 | try: |
使用urllib3的poolmanager的 connection_from_url方法
返回一个connconn = self.poolmanager.connection_from_url(url)
证书 请求头添加
1 | self.cert_verify(conn, request.url, verify, cert) |
chunked = not (request.body is None or 'Content-Length' in request.headers)
如果 请求的body为空或者 请求头中有 Content-Length字段则如下
1 | resp = conn.urlopen( |
返回resp对象
否则
1 | low_conn = conn._get_conn(timeout=DEFAULT_POOL_TIMEOUT) |
接下来各种异常捕获
很详细可以快速判断问题所在
最后返回
return self.build_response(request, resp)
build_response即是对响应的封装
最后返回response对象
一个完整的get请求。
下面重新梳理下
api中对request的get post 等封装
request的实质是session.request
再往里是因为HTTPAdapter适配器
里面实质还是使用的urllib3的请求
对请求和响应做了很多封装
来回导入调用很多
还有很多地方模块细节没有细读 留作下次再深入一些读