python的urllib2详解

简介:html

urllib2是python的一个获取url(Uniform Resource Locators,统一资源定址器)的模块。它用urlopen函数的形式提供了一个很是简洁的接口。这使得用各类各样的协议获取url成为可能。它同时 也提供了一个稍微复杂的接口来处理常见的情况-如基本的认证,cookies,代理,等等。这些都是由叫作opener和handler的对象来处理的。python

如下是获取url最简单的方式:web

import urllib2浏览器

response = urllib2.urlopen('http://python.org/')服务器

html = response.read()cookie

许多urlib2的使用都是如此简单(注意咱们原本也能够用一个以”ftp:”"file:”等开头的url取代”HTTP”开头的url).然 而,这篇教程的目的是解释关于HTTP更复杂的情形。HTTP建基于请求和回应(requests &responses )-客户端制造请求服务器返回回应。urlib2用代 表了你正在请求的HTTP request的Request对象反映了这些。用它最简单的形式,你创建了一个Request对象来明确指明你想要获取的url。调用urlopen函 数对请求的url返回一个respons对象。这个respons是一个像file的对象,这意味着你能用.read()函数操做这个respon对象:网络

import urllib2socket

req = urllib2.Request('http://www.voidspace.org.uk')函数

response = urllib2.urlopen(req)fetch

the_page = response.read()

注意urlib2利用了一样的Request接口来处理全部的url协议。例如,你能够像这样请求一个ftpRequest:

req = urllib2.Request('ftp://example.com/')

对于HTTP,Request对象容许你作两件额外的事:第一,你能够向服务器发送数据。第二,你能够向服务器发送额外的信息(metadata),这些信息能够是关于数据自己的,或者是关于这个请求自己的–这些信息被看成HTTP头发送。让咱们依次看一下这些。

数据:

有时你想向一个URL发送数据(一般这些数据是表明一些CGI脚本或者其余的web应用)。对于HTTP,这一般叫作一个Post。当你发送一个你 在网上填的form(表单)时,这一般是你的浏览器所作的。并非全部的Post请求都来自HTML表单,这些数据须要被以标准的方式encode,而后 做为一个数据参数传送给Request对象。Encoding是在urlib中完成的,而不是在urlib2中完成的。

import urllib

import urllib2

url = 'http://www.someserver.com/cgi-bin/register.cgi'

values = {'name' : 'Michael Foord',

'location' : 'Northampton',

'language' : 'Python' }

data = urllib.urlencode(values)

req = urllib2.Request(url, data)

response = urllib2.urlopen(req)

the_page = response.read()

若是你不传送数据参数,urlib2使用了一个GET请求。一个GET请求和POST请求的不一样之处在于POST请求一般具备边界效应:它们以某种 方式改变系统的状态。(例如,经过网页设置一条指令运送一英担罐装牛肉到你家。)虽然HTTP标准清楚的说明Post常常产生边界效应,而get从不产生 边界效应,但没有什么能阻止一个get请求产生边界效应,或一个Post请求没有任何边界效应。数据也能被url本身加密(Encoding)而后经过一 个get请求发送出去。

这经过如下实现:

>>> import urllib2

>>> import urllib

>>> data = {}

>>> data['name'] = 'Somebody Here'

>>> data['location'] = 'Northampton'

>>> data['language'] = 'Python'

>>> url_values = urllib.urlencode(data)

>>> print url_values

name=Somebody+Here&language=Python&location=Northampton

>>> url = 'http://www.example.com/example.cgi'

>>> full_url = url + '?' + url_values

>>> data = urllib2.open(full_url)

头:

咱们将会在这里讨论一个特殊的HTTP头,来阐释怎么向你的HTTP请求中加入头。

有一些网站不但愿被某些程序浏览或者针对不一样的浏览器返回不一样的版本。默认状况下,urlib2把本身识别为Python-urllib/x.y(这里的 xy是python发行版的主要或次要的版本号,如, Python-urllib/2.5),这些也许会混淆站点,或者彻底不工做。浏览器区别自身的方式是经过User-Agent头。当你创建一个 Request对象时,你能够加入一个头字典。接下来的这个例子和上面的请求同样,不过它把本身定义为IE的一个版本。

import urllib

import urllib2

url = 'http://www.someserver.com/cgi-bin/register.cgi'

user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'

values = {'name' : 'Michael Foord',

'location' : 'Northampton',

'language' : 'Python' }

headers = { 'User-Agent' : user_agent }

data = urllib.urlencode(values)

req = urllib2.Request(url, data, headers)

response = urllib2.urlopen(req)

the_page = response.read()

Respons一样有两种有用的方法。当咱们出差错以后,看一下关于info and geturl的部分。

异常处理:

不能处理一个respons时,urlopen抛出一个urlerror(虽然像日常同样对于python APIs,内建异常如,ValueError, TypeError 等也会被抛出。)

HTTPerror是HTTP URL在特别的状况下被抛出的URLError的一个子类。

urlerror:

一般,urlerror被抛出是由于没有网络链接(没有至特定服务器的链接)或者特定的服务器不存在。在这种状况下,含有reason属性的异常将被抛出,以一种包含错误代码和文本错误信息的tuple形式。

e.g.

>>> req = urllib2.Request('http://www.pretend_server.org')

>>> try: urllib2.urlopen(req)

>>> except URLError, e:

>>> print e.reason

>>>

(4, 'getaddrinfo failed')

当一个错误被抛出的时候,服务器返回一个HTTP错误代码和一个错误页。你可使用返回的HTTP错误示例。这意味着它不但具备code属性,并且 同时具备read,geturl,和info,methods属性。>>> req = urllib2.Request('http://www.python.org/fish.html')>>> try:>>> urllib2.urlopen(req)>>> except URLError, e:>>> print e.code>>> print e.read()>>>404...... etc

容错:

若是你准备处理HTTP错误和URL错误这里有两种基本的方法,我更倾向于后一种:

1.

from urllib2 import Request, urlopen, URLError, HTTPError

req = Request(someurl)

try:

response = urlopen(req)

except HTTPError, e:

print 'The server couldn/'t fulfill the request.'

print 'Error code: ', e.code

except URLError, e:

print 'We failed to reach a server.'

print 'Reason: ', e.reason

else:

# everything is fine

注意:HTTP错误异常必须在前面,不然URL错误也会捕获一个HTTP错误。

2

from urllib2 import Request, urlopen, URLError

req = Request(someurl)

try:

response = urlopen(req)

except URLError, e:

if hasattr(e, 'reason'):

print 'We failed to reach a server.'

print 'Reason: ', e.reason

elif hasattr(e, 'code'):

print 'The server couldn/'t fulfill the request.'

print 'Error code: ', e.code

else:

# everything is fine

注意:URL错误是IO错误异常的一个子类。这意味着你能避免引入(import)URL错误而使用:

from urllib2 import Request, urlopen

req = Request(someurl)

try:

response = urlopen(req)

except IOError, e:

if hasattr(e, 'reason'):

print 'We failed to reach a server.'

print 'Reason: ', e.reason

elif hasattr(e, 'code'):

print 'The server couldn/'t fulfill the request.'

print 'Error code: ', e.code

else:

# everything is fine

极少数环境下,urllib2可以抛出socket.error.

INFO and GETURL

urlopen返回的response(或者HTTP错误实例)有两个有用的方法:info和geturl。

geturl–它返回被获取网页的真正的url。这是颇有用的,由于urlopen(或使用的opener对象)也许会伴随一个重定向。

获取的网页url也许和要求的网页url不同。

info–它返回一个像字典的对象来描述获取的网页,尤为是服务器发送的头。它如今通常是httplib.HTTPMessage的一个实例。

典型的头包含'Content-length', 'Content-type', 等等。看一下Quick Reference to HTTP Headers中,HTTP头列表,还有

关于他们简单的解释和使用方法。

Openers 和Handlers

当你获取一个URL时,你使用一个opener(一个可能以一个比较迷糊名字命名的实例–urllib2.OpenerDirector)。正常状况下

咱们一直使用默认的opener,经过urlopen,但你也能够建立自定义的openers。opener使用操做器(handlers)。全部的重活都交给这些handlers来作。每个handler知道

怎么打开url以一种独特的url协议(http,ftp等等),或者怎么处理打开url的某些方面,如,HTTP重定向,或者HTTP cookie。

你将会建立openers若是你想要用安装特别的handlers获取url,例如,获取一个处理cookie的opener,或者一个不处理重定向的opener。

枚举一个OpenerDirector,而后屡次调用.add_handler(some_handler_instance)来建立一个opener。

或者,你能够用build_opener,这是一个很方便的建立opener对象的函数,它只有一个函数调用。build_opener默认会加入许多

handlers,可是提供了一个快速的方法添加更多东西和/或使默认的handler失效。

其余你想要的handlers可以处理代理,authentication和其余日常可是又有些特殊的状况。

install_opener能被用于建立一个opener对象,(全局)默认的opener。这意味着调用urlopen将会用到你刚安装的opener。

opener对象有一个open方法,它能够被直接调用来获取url以一种和urlopen函数一样的方式:没有必要调用install_opener,除非是为了方便。

Basic Authentication:(基本验证)

为了解释建立和安装一个handler,咱们将会使用 HTTPBasicAuthHandler。更多关于这个东西的内容和详细讨论—包括一个 Basic Authentication如何工做的解说–参见 Basic Authentication Tutorial.

当须要Authentication的时候,服务器发送一个头(同时还有401代码)请求Authentication。它详细指明了一个Authentication和一个域。这个头看起来像:

Www-authenticate: SCHEME realm=”REALM”.

e.g.

Www-authenticate: Basic realm=”cPanel Users”

客户端而后就会用包含在头中的正确的账户和密码从新请求这个域。这是”基本验证”。为了简化这个过程,咱们能够建立一个

HTTPBasicAuthHandler和opener的实例来使用这个handler。

HTTPBasicAuthHandler用一个叫作密码管理的对象来处理url和用户名和密码的域的映射。若是你知道域是什么(从服务器发送的authentication

头中),那你就可使用一个HTTPPasswordMgr。多数状况下人们不在意域是什么。那样使用HTTPPasswordMgrWithDefaultRealm就很方便。它

容许你为一个url具体指定用户名和密码。这将会在你没有为一个特殊的域提供一个可供选择的密码锁时提供给你。咱们经过提供None做为add_password方法域的参数指出

这一点。

最高级别的url是须要authentication的第一个url。比你传递给.add_password()的url更深的url一样也会匹配。

# create a password manager

password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()

# Add the username and password.

# If we knew the realm, we could use it instead of “None“.

top_level_url = “http://example.com/foo/”

password_mgr.add_password(None, top_level_url, username, password)

handler = urllib2.HTTPBasicAuthHandler(password_mgr)

# create “opener” (OpenerDirector instance)

opener = urllib2.build_opener(handler)

# use the opener to fetch a URL

opener.open(a_url)

# Install the opener.

# Now all calls to urllib2.urlopen use our opener.

urllib2.install_opener(opener)

注意:在以上的示例中咱们只给build_opener提供了HTTPBasicAuthHandler。默认opener有对普通状况的操做器 (handlers)- ProxyHandler, UnknownHandler, HTTPHandler, HTTPDefaultErrorHandler, HTTPRedirectHandler, FTPHandler, FileHandler, HTTPErrorProcessor.

高级别url其实是一个完整的url(包括http:协议组件和主机名可选的端口号),如”http://example.com”或者是一个受权(一样,主机名,可选的端口号)

如”"example.com” 或 “example.com:8080″(后一个示例包含了一个端口号)。受权,若是被呈现,必定不能包含用户信息-如”oe@password:example.com”

是不正确的、

代理:

urllib2将会自动检测你的代理设置并使用它们。这是经过 ProxyHandler实现的,它是操做器链的一部分。正常状况下,这是个好东西,可是也有它不那么有用的偶然状况。

一个作这些的方法是安装咱们本身的ProxyHandler,不用任何定义任何代理。使用一个和创建Basic Authentication操做器类似的步骤能够实现:

>>> proxy_support = urllib2.ProxyHandler({})

>>> opener = urllib2.build_opener(proxy_support)

>>> urllib2.install_opener(opener)

注意:

目前urllib2不支持经过代理获取HTTPs位置。这是一个问题。

sockets和layers

python支持获取层叠的网页的源码。urllib2使用httplib library,而httplib library反过来使用socket library。

对于python2.3你能够指明一个socket应该在超时以前等待response多久。这在这些不得不获取网页的应用中颇有用。默认socket模块没有超时并且可以挂起。

目前,socket超时在urllib2或者httplib水平中不可见。然而,你能够全局地为全部socket设置默认的超时。

import socket

import urllib2

# timeout in seconds

timeout = 10

socket.setdefaulttimeout(timeout)

# this call to urllib2.urlopen now uses the default timeout

# we have set in the socket module

req = urllib2.Request('http://www.voidspace.org.uk')

response = urllib2.urlopen(req) 

相关文章
相关标签/搜索