python urllib2模块技术参考

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

urlib2支持获取url的多种url 协议(以url中“:”前的字符串区别,如ftp是ftp形式的url协议),用它们关联的网络协议(如HTTP,FTP)。这个教程著重于最广泛的状况--HTTP。

最简单的状况下urlopen用起来很是简单。但随着你打开HTTPur时遇到错误或无心义的事情,你须要对HTTP的一些理解。对HTTP最权威最容易让人理解的参考是RFC2616。这是一个技术文档,并且不太容易读懂。这篇HOWTO意在用足够关于HTTP的细节阐明urllib2,使你明白。它的意图不在替换urllib2 docs,而是对它们的一个补充。

获取url:

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

import urllib2
response = urllib2.urlopen('http://python.org/')
html = response.read()

许多urlib2的使用都是如此简单(注意咱们原本也能够用一个以“ftp:”“file:”等开头的url取代“HTTP”开头的url).然而,这篇教程的目的是解释关于HTTP更复杂的情形。

HTTP建基于请求和回应(requests &responses)-客户端制造请求服务器返回回应。urlib2用表明了你正在请求的HTTPrequest的Request对象反映了这些。用它最简单的形式,你创建了一个Request对象来明确指明你想要获取的url。调用urlopen函数对请求的url返回一个respons对象。这个respons是一个像file的对象,这意味着你能用.read()函数操做这个respon对象:

import urllib2

req = urllib2.Request('http://www.voidspace.org.uk')
response = urllib2.urlopen(req)
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()

注意有时须要其余的Encoding(例如,对于一个来自表单的文件上传(file upload)--详细内容见HTMLSpecification, Form Submission )。

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

这经过如下实现:

>>> importurllib2
>>> importurllib
>>> data = {}
>>> data['name'] ='Somebody Here'
>>> data['location'] ='Northampton'
>>> data['language'] ='Python'
>>> url_values =urllib.urlencode(data)
>>> printurl_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)

注意一个完整的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(虽然像日常同样对于pythonAPIs,内建异常如,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')

HTTPError:
每一个来自服务器的HTTP response包含一个“statuscode”(状态代码)。有时状态代码暗示了服务器不能处理这个请求。默认的句柄将会为你处理一些response(如,若是返回的是一个要求你从一个不一样的url获取文件的“重定向”,urlib2将会为你处理)。对于那些它不能处理的,urlopen将会抛出一个HTTPerror。
典型的错误包含404(页面没有找到),403(请求禁止)和401(须要许可)。
全部的HTTP错误代码参见RFC2616的第十部分。

HTTP错误代码将会有一个code(integer)属性,这个code属性的integer值和服务器返回的错误代码是一致的。

错误代码:
由于默认的句柄处理重定向(300序列中的代码)和在100-299之间表示成功的代码,你一般只须要了解在400-599序列中的错误代码。

BaseHTTPServer.BaseHTTPRequestHandler.responses是一个有用的response字典,其中的代码显示了全部RFC2616使用的response代码。

为了方便,代码被复制到了这里:
# Table mapping response codes to messages; entries have the

# form {code: (shortmessage, longmessage)}.

responses = {

    100: ('Continue', 'Requestreceived, please continue'),

    101: ('SwitchingProtocols',

         'Switchingto new protocol; obey Upgrade header'),



    200: ('OK', 'Requestfulfilled, document follows'),

    201: ('Created', 'Documentcreated, URL follows'),

    202: ('Accepted',

         'Requestaccepted, processing continues off-line'),

    203: ('Non-AuthoritativeInformation', 'Request fulfilled from cache'),

    204: ('No Content', 'Requestfulfilled, nothing follows'),

    205: ('Reset Content', 'Clearinput form for further input.'),

    206: ('Partial Content','Partial content follows.'),



    300: ('MultipleChoices',

         'Object hasseveral resources -- see URI list'),

    301: ('Moved Permanently','Object moved permanently -- see URI list'),

    302: ('Found', 'Object movedtemporarily -- see URI list'),

    303: ('See Other', 'Objectmoved -- see Method and URL list'),

    304: ('Not Modified',

         'Documenthas not changed since given time'),

    305: ('Use Proxy',

         'You mustuse proxy specified in Location to access this '

        'resource.'),

    307: ('TemporaryRedirect',

         'Objectmoved temporarily -- see URI list'),



    400: ('Bad Request',

         'Badrequest syntax or unsupported method'),

    401: ('Unauthorized',

         'Nopermission -- see authorization schemes'),

    402: ('PaymentRequired',

         'No payment-- see charging schemes'),

    403: ('Forbidden',

         'Requestforbidden -- authorization will not help'),

    404: ('Not Found', 'Nothingmatches the given URI'),

    405: ('Method NotAllowed',

         'Specifiedmethod is invalid for this server.'),

    406: ('Not Acceptable', 'URInot available in preferred format.'),

    407: ('Proxy AuthenticationRequired', 'You must authenticate with '

         'this proxybefore proceeding.'),

    408: ('Request Timeout','Request timed out; try again later.'),

    409: ('Conflict', 'Requestconflict.'),

    410: ('Gone',

         'URI nolonger exists and has been permanently removed.'),

    411: ('Length Required','Client must specify Content-Length.'),

    412: ('Precondition Failed','Precondition in headers is false.'),

    413: ('Request Entity TooLarge', 'Entity is too large.'),

    414: ('Request-URI Too Long','URI is too long.'),

    415: ('Unsupported MediaType', 'Entity body in unsupported format.'),

    416: ('Requested Range NotSatisfiable',

         'Cannotsatisfy request range.'),

    417: ('ExpectationFailed',

         'Expectcondition could not be satisfied.'),



    500: ('Internal ServerError', 'Server got itself in trouble'),

    501: ('NotImplemented',

         'Serverdoes not support this operation'),

    502: ('Bad Gateway', 'Invalidresponses from another server/proxy.'),

    503: ('ServiceUnavailable',

         'The servercannot process the request due to a high load'),

    504: ('GatewayTimeout',

         'Thegateway server did not receive a timely response'),

    505: ('HTTP Version NotSupported', 'Cannot fulfill request.'),

    }
当一个错误被抛出的时候,服务器返回一个HTTP错误代码和一个错误页。你可使用返回的HTTP错误示例。这意味着它不但具备code属性,并且同时
具备read,geturl,和info,methods属性。
>>> req =urllib2.Request('http://www.python.org/fish.html')
>>> try:
>>>    urllib2.urlopen(req)
>>> except URLError,e:
>>>    printe.code
>>>    printe.read()
>>>
404
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
<?xml-stylesheet href="./css/ht2html.css"
   type="text/css"?>
<html><head><title>Error404: File Not Found</title>
...... etc


python urllib2.urlopen的geturl方法 当使用python的urllib2.urlopen()打开一个url时,会产生一个file-like对象,这个对象包含两个方法: geturl()和info() 其中geturl()在网页地址存在重定向现象时特别有用,这个方法能够获得重定向后的url地址。 >>>importurllib2 >>>url='http://***.com' >>>u=urllib2.urlopen(url) >>>redirectUrl=u.geturl() 文章来源:http://blog.sina.com.cn/s/blog_a4e327c201011pfn.html