标签:python
获取web页面
#!/usr/bin/env python import sys,urllib2 req=urllib2.Request(sys.argv[1]) fd=urllib2.urlopen(req) while True: data=fd.read(1024) if not len(data): break sys.stdout.write(data)
首先建立了一个urllib2.Request对象,该对象用URL做参数。然后调用urlopen得到一个文件类对象。当然urlopen也可以直接用url做为参数。。除此以外,还有geturl()函数,用来获得来源的URL,通常情况下,它可以跟踪到重定向的页面。info()函数用来获取页面的meta-information。
认证
有些站点需要HTTP认证后方可访问。HTTP认证一般显示一个弹出窗口,询问用户名和密码,它与基于cookie和form的认证是不同的。
若试图访问一个需要进行认证的URL,通常会得到HTTP错误401,然而urllib可以替你处理认证。例子:
#!/usr/bin/env python import sys,urllib2,getpass class TerminalPassword(urllib2.HTTPPasswordMgr): def find_user_password(self,realm,authuri): retval=urllib2.HTTPPasswordMgr.find_user_password(self,realm,authuri) if retval[0]==None and retval[1]==None: sys.stdout.write("Login required for %s\n" % (realm,authuri)) sys.stdout.write(‘Username: ‘) username=sys.stdin.readline().strip() password=getpass.getpass().rstrip() return (username,password) else: return retval req=urllib2.Request(sys.argv[1]) opener=urllib2.build_opener(urllib2.HTTPBasicAuthHandler(TerminalPassword())) fd=opener.open(req) print ‘Retrieved‘,fd.geturl() info=fd.info() for key,value in info.items(): print ‘%s = %s‘ % (key,value)
这个程序中定义了一个TerminalPassword类,允许程序在需要的时候向操作员询问用户名和密码,另一个调用是build_opener()。这个函数允许指定额外的处理程序,通常在默认情况下就有一些处理程序(例如基本HTTP和FTP支持),而其他的一些处理程序也可以有选择地添加。因为这段代码要支持基本认证,所以必须把HTTPBasicAuthHandler加到处理程序链上。在前一个例子中,代码简单地调用了urllib2.urlopen(),它在内部调用了build_opener(),并且不带任何参数。这就导致了只选择默认的处理程序。注意,一旦连接被打开,就不会有改变。如果需要认证,HTTPBasicAuthHandler会自动地调用TerminalPassword里面合适的函数,不用进一步地检查。还要注意的是,若你访问一个不需要认证的普通站点,这段代码表现地和前面一样。
提交表单数据
CGI脚本和其他交互式的服务器端程序经常从Web客户端收到数据,一般是从表单。有两种方法提交表单数据:GET和POST。至于是用哪种方法,取决于HTML文档中<form>标签里面的方法参数。
1、用GET方法提交
提交表单的GET方法是把表单数据编码至URL。在给出请求的页面后,加上一个问好,接着是表单的元素。每个键和值对被“&”分割。有些字符需要被避免,例如空格需要用“+”代替。因为URL中包含了全部的数据,所以GET方法不太适合数据量比较大的情况。例子:
#!/usr/bin/env python import sys,urllib2,urllib def addGETdata(url,data): """Adds data to url.Data should be a list or tuple consisting of 2-item lists or tuples of the form:(key,value). Items that have no key should have key set to None. A given key may occur more than once. """ return url+‘?‘+urllib.urlencode(data) zipcode=sys.argv[1] url=addGETdata(‘http://www.wunderground.com/cgi-bin/findweather/getForecast‘,[(‘query‘,zipcode)]) print ‘Using URL‘,url req=urllib2.Request(url) fd=urllib2.urlopen(req) while True: data=fd.read(1024) if not len(data): break sys.stdout.write(data)
2、用POST方法提交
编码后的数据以请求的一个单独部分发送。当需要交换大量数据时,POST是一个很好的方法。例子:
#!/usr/bin/env python import sys,urllib2,urllib zipcode=sys.argv[1] url=‘http://www.wunderground.com/cgi-bin/findweather/getForecast‘ data=urllib.urlencode([(‘query‘,zipcode)]) req=urllib2.Request(url) fd=urllib2.urlopen(req,data) while True: data=fd.read(1024) if not len(data): break sys.stdout.write(data) #附加的细腻希通过第二个参数传递给urlopen()
处理错误
当和远程Web服务器建立连接时,很多地方都可能出现问题:提供的URL不对;URL也许使用了一个不支持的协议;主机名也许不对;或者访问不到服务器;或者服务器针对请求返回一个错误。。。任何在连接过程中产生的异常要么都是urllib2.URLError的实例,要么是它的一个子类。因此,可以通过捕捉这个超类(指URLError)来捕获异常。。但是HTTP的错误信息实际上还包含一个解释发生了什么的文档。如果直接使用超类将看不到这一文档,为此,urllib2有一个HTTPError的异常类(一个URLError的子类)。HTTPError本身是一种文件类对象,可以被用来读。记住,有些错误不是HTTPError,还是需要处理URLError。例子:
#!/usr/bin/env python import sys,urllib2 req=urllib2.Request(sys.argv[1]) try: fd=urllib2.urlopen(req) except urllib2.HTTPError,e: print ‘Error retrieving data:‘,e print ‘Server error document follows:\n‘ print e.read() sys.exit(1) except urllib2.URLError,e: print ‘Error retrieving data:‘,e sys.exit(2) print ‘Retrieved‘,fd.geturl() info=fd.info() for key,value in info.items(): print ‘%s = %s‘ % (key,value)
在读取数据的有两种不同的问题会发生:一是通信错误,会使socket模块在调用read()函数时产生socket.error;二是在没有通信错误的情况下发送的文档被删节。对于第一种情况可以通过处理socket错误的方法来处理。对于第二种情况却有些难度。
对于客户端来说收到被删节的文档而没有任何异常是完全可能的。例如:当一个程序发送文档的时候,服务器出现了问题,这时服务器的问题导致远程socket被正常关闭,所以用户的客户端会简单地收到一个文件结束标志,而无任何异常。
检查这个问题的方法是在服务器的回答中找到内容长度的报头,这样可以对比接受到的数据长度和该报头中提供的长度来检查。但是,内容长度的报头不总是被提供,特别是CGI产生页面都不含此报头。在这种情况下就没有办法检查文件是否被删节。例子:
#!/usr/bin/env python import sys,urllib2,socket req=urllib2.Request(sys.argv[1]) try: fd=urllib2.urlopen(req) except urllib2.HTTPError,e: print ‘Error retrieving data:‘,e print ‘Server error document follows:\n‘ print e.read() sys.exit(1) except urllib2.URLError,e: print ‘Error retrieving data:‘,e sys.exit(2) print ‘Retrieved‘,fd.geturl() bytesread=0 while True: try: data=fd.read(1024) except socket.error,e: print ‘Error reading data:‘,e sys.exit(3) if not len(data): break bytesread+=len(data) sys.stdout.write(data) if fd.info().has_key(‘Content-Length‘) and long(fd.info()[‘Content-Length‘])!=long(bytesread): print ‘Expected a document of size %d , but read %d bytes‘ % (long(fd.info()[‘Content-Length‘]),bytesread) sys.exit(4)
本文出自 “莲的思念” 博客,请务必保留此出处http://liandesinian.blog.51cto.com/7737219/1555361
标签:python
原文地址:http://liandesinian.blog.51cto.com/7737219/1555361