【Python】Python http编程:urllib包与http包详解

来源:互联网 发布:蒋方舟写作水平知乎 编辑:程序博客网 时间:2024/06/05 19:48

python自3.x版本推出之后,web端的编程更加方便。对于python的Internet方面的官方提供接口可以在Internet Protocols and Support栏目下查询。在该栏目下可以发现包括ftp(文件传输协议)、smtp(邮件协议)等相关的应用层的编程接口。除此之外,python对网络端的数据处理也提供了非常好的支持,具体内容可以参考Internet Data Handlingt。在该栏目中python对常用的ascii和json,还有一些其他的数据编解码都提供了很好的接口支持。不过,这些都不是我们本文的重点,我们这里是主要讨论Internet Protocols and Support下python对使用http协议的的web端开发相关的内容。当然如果有可能,还是建议使用更好的web开发框架,比如webpy、django,或者其他的请求协议框架比如Requests

文章分为三部分,第一部分是讲解python提供的库的支持,第二部分讲述简单的使用场景,第三部分是我认为有用的链接,包括官方的教程和一些深入的介绍的资料。

python库介绍

在web端编程主要使用的库有两个。

一个是和url请求与返回相关的包urllib,其主要包括:

  • urllib.request for opening and reading URLs
  • urllib.error containing the exceptions raised byurllib.request
  • urllib.parse for parsing URLs
  • urllib.robotparser for parsingrobots.txt files 
另外一个是http协议处理相关的http包,主要包括:
  • http.client is a low-level HTTP protocol client; for high-level URL opening useurllib.request
  • http.server contains basic HTTP server classes based onsocketserver
  • http.cookies has utilities for implementing state management with cookies
  • http.cookiejar provides persistence of cookies  
下面我们就针对每个库进行详细介绍。

urllib库详解

在python3之前,是存在urllib and urllib2两个库对url请求进行处理的。但是,在python3.X之后,两个库就合并为一个urllib。在urllib下的子库都是直接或者间接和一个url进行打交道或者有一定关联关系。比如url.error库中提供的类与接口都是在打开一个url抛出的错误,而url.request中提供的类与接口都是直接通过一个url进行请求。下面我们就针对每个子库进行简单说明。
urllib.request 它是url库中最重要也是最复杂,提供最多接口的一个库。它包含了请求的发出,跳转,代理,安全等各个方面。现在它只提供了对http,https,ftp与本地文件的打开支持,还没有其他协议的实现。因为urllib.request是urllib库下面最重要的一个,我们就着重介绍这个库。urllib.request(下面简称request注意开始字母小写),request的首要作用是根据你提供的一个url,对这个url进行请求并返回请求结果。它具体的类型请参考下面截图:

在这里结合上图先介绍一下request中的基本概念。在request中主要存在handler、opener与processor几种对象类型。opener负责请求具体的URL或者打开相应的文件,handler主要是声明的处理方式。比如你可以声明打开某个请求利用HttpHandler或者FTPHandler,当opener打开某个URL的时候,就利用你声明的handler中提供的方法加python提供的默认handler,就是上面截图中的以Handler结尾的类。当声明和初始化的时候没有声明要采用的handler,那么opener就会仅采用所有默认的handler。processor存在HTTPCookieProcessor(负责处理cookie,其实是调用http库中的接口)与HTTPErrorProcessor(负责处理请求的错误)
如何对该url进行请求,请求的时候是否需要参数,是否需要代理,都可以使用request提供的方法完成这些任务。当然request已经为我们封装了很多底层内容,比如operner和handler等。下面我们就开始介绍一个http请求是如何通过调用request中的接口发出去的。
req = urllib.request.Request("http://weibo.com/")data = urllib.request.urlopen(req)#data = urllib.request.urlopen("http://weibo.com/")for d in data.readlines():    print(str(d,encoding = "utf-8"))

request对外提供的接口是urlopen方法,该方法可以接受一个纯粹的字符串形式的url(注释部分,也可以接受一个Request对象(注意是大写)。当你传递的是字符串的时候,request中会有相关底层方法把你的字符串封装为一个Request对象。最后把request方法传递给opener中的open方法,open方法中会采用你声明的handler或者默认handler进行具体的URL请求处理。这是一个最简单的处理过程,复杂的应用场景会在下面应用场景分析那里讲解。urlopen方法请看下面源码:
def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,            *, cafile=None, capath=None, cadefault=False):    global _opener    if cafile or capath or cadefault:        if not _have_ssl:            raise ValueError('SSL support not available')        context = ssl._create_stdlib_context(cert_reqs=ssl.CERT_REQUIRED,                                             cafile=cafile,                                             capath=capath)        https_handler = HTTPSHandler(context=context, check_hostname=True)        opener = build_opener(https_handler)    elif _opener is None:        _opener = opener = build_opener()    else:        opener = _opener    return opener.open(url, data, timeout)

通过上面可以看出,当你调用urlopen方法的时候,具体底层调用次序为:
根据请求类型,构造相应的HTTPS或者HTTP所需要的对象->调用或者生成opener->通过opener调用open方法,打开连接。具体的open方法如下面源码所示:
每个handler调用http库中的接口完成请求的处理

httplib库详解

相对于urllib库来说,httplib库是提供了你直接和http协议打交道的机会。在python 3之前,是以httplib为名,但是在3之后所有的库就重名为http.client。
在urllib库中,很多接口都提供了底层的封装,包括链接的建立,请求的发出,根据返回的状态码是否跳转,获取相应内容等。但是,在http库下,这些东西必须用开发者来显式调用接口来处理。虽然两种接口差别很大,但是各有各的使用场所。虽然urllib很多东西不需要考虑,其实他底层的很多实现都是通过调用http库来完成的。具体采用那一种方式来开发,要针对你的项目和你的应用场景(移步SO上针对这两个的回答)。需要注意的是,在使用urllib 的时候,当打开一个地址的时候,都是要建立链接,这部分可能会有一些延迟。所以,如果是对延迟有一定要求的化,除非是利用多线程,否则可能不会满足你的使用场景。
当想通过http包进行网络编程的时候,需要注意的是http.client包下面的HTTPConnection,HTTPResponse两个类库。对于HTTPConnection,主要是用来建立链接与发出相应的请求等操作,HTTPResponse则是封装请求的返回结果的类库。对于一个简单的请求,示例如下:
import http.clientconn = http.client.HTTPConnection("www.baidu.com")conn.request("GET", "/index.html")r1 = conn.getresponse()#返回的是HTTPResponse对象

但是,我没有找到具体的如何使用代理,采用3.X之前的版本中的使用代理的代码进行测试是无法正常工作的。在使用代理这一块有具体进展会再次更新,或者有朋友使用过也可以进行回复。
和urllib库相比,http库中不仅仅提供了客户端请求的接口,它还提供了服务器端的接口。通过使用http.server就可以实现一个简单的web服务器,接受web请求。但是,该接口是相当简单,在扩展性和应对高并发访问的时候都有很多局限性。除此之外,对于返回数据的渲染和客户端与服务器端数据交互的复杂性也必须由开发者来完成,生产效率非常低,所以现在已经有很多框架都已经封装以上顾虑,让开发者可以集中于业务开发。比如小型的webpy还有非常流行的Django,更多详细资料请看底部链接。
在如今使用python进行简单的http编程的时候,比如写爬虫已经很少使用http包中的接口,大部分都是直接使用urllib库。下面的具体示例都是基于urllib库。

应用示例

因为http库的使用不是特别多,这里的应用我们都是基于urllib库的应用示例。

单纯一个请求

req = urllib.request.Request("http://weibo.com/")data = urllib.request.urlopen(req)for d in data.readlines():  print(str(d,encoding = "utf-8"))
这是最简单的一种请求发出的方式,通过构造一个Request对象然后调用接口发出请求,读取返回数据,读取后的数据是字节的形式。最后把字节数据通过utf-8转化为字符串输出结果。

发送HEAD请求

        req= urllib2.Request(url)        req.get_method = lambda : 'HEAD'        r = urllib2.urlopen(req)


使用代理

proxy_url="http://XXX.com:port/"proxy_handler = urllib.request.ProxyHandler({'http': proxy_url})opener = urllib.request.build_opener(proxy_handler)urllib.request.install_opener(opener)req = urllib.request.Request("http://weibo.com/")data = urllib.request.urlopen(req)
这是使用代理的请求代码,通过提前声明一个代理,然后构造一个Handler,并把该handler在opener中声明,最后还有调用安装opener接口,用来覆盖掉默认的opener。这时候,当打开一个连接的时候,就会调用我们构造的opener,相应的当opener打开某个连接的时候,就可以调用代理handler处理具体的请求。在构造代理handler的时候需要一个字典,字典的key是说明代理的类型,本文是http;字典的value是代理的地址与端口号组成的字符串。
对于urllib2使用代理也可以使用如下方式
 proxy = urllib2.ProxyHandler({'http': 'ip:port'}) opener = urllib2.build_opener(proxy) urllib2.install_opener(opener) r = urllib2.urlopen(url)

r是一个response的对象,可以通过print r.info()获取消息头信息。


传递参数

param= urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})param= param.encode('utf-8')request = urllib.request.Request("http://weib.com")request.add_header("Content-Type","application/x-www-form-urlencoded;charset=utf-8")data = urllib.request.urlopen(request, param)
把要传递的参数以map的形式通过urlencode进行编码,然后通过utf-8再进行编码

附录

Use Python in the web:http://docs.python.org/3.2/howto/webservers.html

Using The urllib Package:http://docs.python.org/3.2/howto/urllib2.html

webpy:http://webpy.org/

Django:https://www.djangoproject.com/

0 0
原创粉丝点击