Requests源码阅读-Day1[toc]Requests介绍requests是一个Python网络请求库。与urllib和httplib相比,最大的优势就是使用方便。库是为人服务的。”另外,requests还支持https认证,是线程安全的官方文档分析环境系统:Linux-Fedora29x64开发工具:vscodeRequests版本:V2.20.0python版本:3.6.7git下载地址来源代码分析首先gitclone源码到本地,然后使用cloc工具查看文件格式,如果系统没有cloc工具,可以安装。由于我本地是fedora系统,所以可以使用dnfinstallcloc命令安装。使用如下命令查看项目的python文件统计:[jian@laptoprequests]$cloc--include-lang=Python.LanguagefilesblankcommentcodePython35195119905937可以看到python文件一共有35个,代码量为5937行单元测试[jian@laptoprequests]$pwd/home/jian/prj/github/requests[jian@laptoprequests]$pythonPython3.6.7(默认,2019年3月21日,20:23:57)[GCC8.3.120190223(RedHat8.3.1-2)]在linux上键入“help”、“copyright”、“credits”或“license”以获得更多信息。>>>importrequests>>>r=requests.get("http://www.baidu.com")>>>r.status_code200打开README.md文件查看requests国际域名目前支持哪些功能和URLs#InternationalizeddomainnameandURLSKeep-Alive&ConnectionPooling#keep—Alive&ConnectionPoolSessionswithCookiePersistence#PersistentcookiesessionBrowser-styleSSLVerification#Browser-styleSSLcertificationBasic&DigestAuthentication#Basic/DigestAuthentication熟悉的dict-likeCookies#key/valuecookiesAutomaticDecompressionofContent#自动内容解压AutomaticCon帐篷解码#AutomaticcontentdecodingAutomaticConnectionPooling#AutomaticconnectionpoolUnicodeResponseBodies#UnicoderesponsebodyMulti-partFileUploads#FileblockuploadSOCKSProxySupport#HTTP(S)代理支持ConnectionTimeouts#ConnectiontimeoutStreamingDownloads#DataflowDownloads.netrc的自动honoring#netrcsupportsChunkedHTTPRequests#Chunkedrequest看源码看思路,明白作者的设计思路是什么,比如requests,看完之后你应该问问自己,cookies为什么要封装而不是直接使用?为什么请求有两种形式?会话旨在解决什么问题?只有理解了设计思路,再看具体的实现细节,才能有所收获,否则看到的是满屏raise和isinstanceof,看代码可能是浪费时间。所以……让我们开始吧。test_requests.py源码目录下有tests文件夹。test开头的测试文件专门用于测试requests接口。使用了pytest方法。pytest我会单独写一章来介绍具体内容,首先选择第一个方法进行分析,找到test_DIGEST_HTTP_200_OK_GET方法tests/test_requests.pydeftest_DIGEST_HTTP_200_OK_GET(self,httpbin):forauthtypeinself.digest_auth_algo:auth=HTTPDigestAuth('user','pass')url=httpbin('digest-auth','auth','user','pass',authtype,'never')r=requests.get(url,auth=auth)assertr.status_code==200r=requests.get(url)assertr.status_code==401print(r.headers['WWW-Authenticate'])s=requests.session()s.auth=HTTPDigestAuth('user','pass')r=s.get(url)assertr.status_code==200上面的代码主要做了以下工作:1.传递一个httpbin参数,这个httpbin是什么?2、遍历不同的摘要认证算法,什么是self.digest_auth_algo?3、摘要认证变量auth和url变量设置,什么是HTTPDigestAuth?4.向url发起get请求,200表示请求成功,401表示未授权。本次测试是为了验证auth的必要性5.新建一个session对象s,同时设置auth变量。与上一个不同的是,这个请求是由session对象发起的。Digest_auth_algo首先回答上面提到的self.digest_auto_algo问题:tests/test_requests.pyclassTestRequests:digest_auth_algo=('MD5','SHA-256','SHA-512')....digest访问认证,这是一个协议,Web服务器用于与Web浏览器通信的方法,用于协商身份验证信息。浏览器在向服务器发送请求的过程中,需要传递认证信息authauth,通过摘要算法加密后形成密文,最后发送给服务器。服务器验证成功后返回“200”告诉浏览器可以继续访问;如果验证失败,则返回“401”,告诉浏览器禁止访问。目前,摘要算法是“MD5”、“SHA-256”和“SHA-512”。HTTPDigestAuthtests/test_requests.pyfromrequests.authimportHTTPDigestAuth,_basic_auth_str看到是导入requests.auth模块里面的HTTPDigestAuth方法好我们去看看下面这个东西是什么?HTTP:"AuthDigestAuth.pyclass对给定请求对象的身份验证。"""def__init__(self,username,password):self.username=usernameself.password=password#在每个线程本地存储中保持状态self._thread_local=threading.local()....def__call__(self,r):#如果需要,初始化每线程状态self.init_per_thread_state()#如果我们有保存的随机数,跳过401ifself._thread_local.last_nonce:r.headers['Authorization']=self.build_digest_header(r.method,r.url)try:self._thread_local.pos=r.body.tell()exceptAttributeError:#在HTTPDigestAuth被重用的情况下#上一个请求的主体是s是一个类似文件的对象,pos具有前一个主体的#文件位置。确保将其设置为#None。self._thread_local.pos=Noner.register_hook('response',self.handle_401)r.register_hook('response',self.handle_redirect)self._thread_local.num_401_calls=1returnr...HTTPDigestAuth:为http请求对象。在实例化对象auth时,需要传入认证所需的用户名和密码。threading.local()在这里的作用是保存一个全局变量,但是这个全局变量只能在当前线程中访问,每个线程都有单独的内存空间来保存这个变量,它们在逻辑上是隔离的,其他线程是不可访问的.我们可以通过一个例子来演示摘要认证:[jian@laptoprequests]$pythonPython3.6.7(default,Mar212019,20:23:57)[GCC8.3.120190223(RedHat8.3.1-2)]onlinuxType“help”、“copyright”、“credits”或“license”以获得更多信息。>>>importrequests>>>fromrequests.authimportHTTPDigestAuth>>>r=requests.get('http://httpbin.org/digest-auth/auth/user/pass',auth=HTTPDigestAuth...('user','pass'))>>>r.status_code200httpbin终于要解决这个东西了,这个东西是什么?1.设置断点:tests/conftest.py@pytest.fixturedefhttpbin(httpbin):pytest.set_trace()#设置断点returnprepare_url(httpbin)在tests目录下新建文件test_xx.pytests/test_xx.pyfromrequests.authimportHTTPDigestAuthimportrequestsimportpytestclassTestRequests:digest_auth_algo=('MD5','SHA-256','SHA-512')deftest_DIGEST_HTTP_200_OK_GET(self,httpbin):forauthtypeinself.digest_auth_algo:auth=HTTPuserDigestAuth,'('通过')url=httpbin('digest-auth','auth','user','pass',authtype,'never')pytest.set_trace()#设置断点r=requests.get(url,auth=auth)assertr.status_code==200r=requests.get(url)assertr.status_code==401print(r.headers['WWW-Authenticate'])s=requests.session()s.auth=HTTPDigestAuth('user','pass')r=s.get(url)断言r。status_code==200并在终端执行[jian@laptoprequests]$pwd/home/jian/prj/github/requests[jian@laptoprequests]$pytesttests/test_xx.pyxxx@pytest.fixturedefhttpbin(httpbin):Efixture'httpbin'notfound怎么报错?-它说找不到httpbinfixture。查资料,是说缺少pytest-httpbin模块。启动(平台:linux,Python3.6.7,pytest3.2.1,pytest-sugar0.9.2)rootdir:/home/jian/prj/github/requests,inifile:pytest.iniplugins:sugar-0.9.2,pep8-1.0.6,mock-1.6.2,httpbin-1.0.0,flakes-2.0.0,env-0.6.2,cov-2.5.1,assume-2.2.0,allure-adaptor-1.7.10,celery-4.4.0>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>PDBset_trace(关闭IO捕获)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>/home/jian/prj/github/requests/tests/conftest.py(20)httpbin()->returnprepare_url(httpbin)(Pdb)httpbin
