浅谈urllib2中内部调用流程
来源:互联网 发布:英语语言变迁 知乎 编辑:程序博客网 时间:2024/04/20 18:54
一. 背景
最近项目中有个需求:策划表数据修改完成后,向服务器发送一个https请求,通知服务器从svn服务器拉去代码,并且重启服务器。对于服务端来说,需要提供一个url,当有主机发出https请求,通过认证后,完成后续的工作。对于客户端来说,也非常简单:在使用倒表工具完成倒表后,将数据commit到svn服务器,然后发送一个url请求即可。
二. urllib2库使用
urllib2是python的一个获取URL的组件。它以urllib2.urlopen接口的形式提供了一个非常简单的接口。具体的使用方法可以参考 extensible library for opening URLs 的接口说明。一般的使用:
<代码段1>
import urllib2response = urllib2.urlopen('http://python.org/')html = response.read()
从表面看,通过urlopen接口输入一个url字符串即可获得response,其实接口urlopen接口的参数非常丰富。来看一下签名:
<代码段2>
def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, cafile=None, capath=None, cadefault=False, context=None):
其中:
data 发给服务器附带的数据,可以通过一定的格式编码;
cafile, capath 是特别为https请求提供的证书;
context 是用来描述SSL选项的 ssl.SSLContext 实例;
返回是一个类似 file 类型的实例,并且附带了三个接口:geturl, info, getcode,具体参考上述链接。
三. 内部调用流程
urlopen是urllib2库中的全局函数,进入函数体后,它会根据其传入的7个参数(少于7个以签名默认值填充)的值,或者采用全局默认值_opener(注意这里有下划线),或者新建一个OpenerDirector实例,来作为该接口内的局部变量 opener(无下划线)<urllib2.OpenerDirector> :
<代码段3>
global _opener if cafile or capath or cadefault: ... opener = build_opener(https_handler) elif context: https_handler = HTTPSHandler(context=context) opener = build_opener(https_handler) elif _opener is None: _opener = opener = build_opener() else: opener = _opener
并且返回OpenerDirector类中的open方法的返回值:
<代码段4>
return opener.open(url, data, timeout)
<代码段5>
def build_opener(*handlers): ... opener = OpenerDirector() ... return opener
<代码段6>:
def install_opener(opener): global _opener _opener = opener
OpenerDirector类管理了一些处理器handlers,所有的任务都有handlers处理。每个handlers知道如何通过特定协议打开URLs,或者如何处理URL打开方式。build_opener接口参数handlers ,是要加入到新建的opener的(他是OpenerDirector类实例,调用该类的add_handler(h) ),不过在加入之前要经过筛选:如果handlers里面是default_class的子类或是其中的类,那么这些handlers会被排除(skip),将筛选后的handlers和default_class加入到opener中:
<代码段7>
opener = OpenerDirector()...# 如果handlers里面是default_class的子类或是其中的类,那么这些handlers会被排除(skip)for klass in default_classes: for check in handlers: if isclass(check): if issubclass(check, klass): skip.add(klass) elif isinstance(check, klass): skip.add(klass)for klass in skip: default_classes.remove(klass)#将筛选后的handlers和default_class加入到opener中:for klass in default_classes: opener.add_handler(klass())for h in handlers: if isclass(h): h = h() opener.add_handler(h)return opener
讲好了opener是怎么来,再简说一下代码段4中opener.open是怎么回事,他的输入是url, data, timeout,前面介绍过了,返回类型与urlopen接口返回相同:
<代码段8>
def open(self, fullurl, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
接口内首先根据fullurl的类型,生成一个Request,并将data加入到request当中:
<代码段9>
if isinstance(fullurl, basestring): req = Request(fullurl, data)else: req = fullurlif data is not None: req.add_data(data)
所以无论传入的fullurl是str类型,还是Request类型,open接口都能讲fullurl转成Request类型的一个实例。经过request的预处理后,调用了OpenerDirector类的 _open接口,在_open接口内部,就是handler处理的机制了。根据 使用默认的形式获取url,如果默认获取不到,再使用req的获取url的形式,并且调用_call_chain的接口:
<代码段10>
def _call_chain(self, chain, kind, meth_name, *args):在这个接口中,会从chain取出handlers,对handlers中的每一个handler获取,名为meth_name的函数对象func,并且将*args作为func的参数调用,将不为None的结果返回,即为response:
<代码段11>
handlers = chain.get(kind, ()) for handler in handlers: func = getattr(handler, meth_name) result = func(*args) if result is not None: return result
四. 结语
文章简要的描述了一下urllib2库中,由urllib2.open(url)发起后的内部调用流程,这里并没有讲述网络中的一些专业知识,例如Request的类型(type),handlers的default_class的种类,以及相关的作用。更多的使用方式和细节请移步urllib2总结。
1 0
- 浅谈urllib2中内部调用流程
- 简析 Android Adapter适配器的内部调用流程
- hadoop put内部调用,hdfs写文件流程
- Python中urllib2总结
- python中urllib2 总结
- Python中urllib2总结
- Python中urllib2总结
- python调用httplib,urllib2模块
- 外来人员如何发起流程与参与内部流程?CCFlow中Guest流程说明
- 无线网络模拟中分组在节点内部的流程
- 浅谈C#中DLL的调用方式
- 浅谈Linux中系统调用代码相关
- urllib2
- urllib2
- urllib2
- urllib2
- urllib2
- urllib2
- 【MySQL】常用MySQL语句
- 51NOD 1136 欧拉函数模板
- mysql优化-sql语句
- Activiti 5.17 JNDI数据源配置
- 中华人民共和国护照
- 浅谈urllib2中内部调用流程
- Prim算法生成最小生成树
- C#读取xml文件
- http协议介绍(servlet)
- Hibernate——org.hibernate.StaleStateException: Batch update returned unexpected row count from update
- 最大熵模型中的数学推导
- Arduino - 关于内存
- Canvas基础知识总结之一
- IIS7/8 HTTP Error 500.19 错误 0x80070021