仅以此纪念python标准库学习!翻译什么会有不顺或者错误,见谅啦。。。。 后边为案例。
#coding:utf-8 import urllib """ 本模块提供了通过万维网抓取数据的高级接口。尤其是,urlopen()函数和内置的open()相似,只是接受的参数为Urls,而不是文件名称。 有一些限制:该方法仅仅可以打开Urls进行读取,没有可用的查询操作。 """ "------------------------------【高级接口】--------------------------------------------" def urlopen_test(url,data,proxies,context): """ .以读的方式打开url指定的网络对象。如果url没有协议标识符或者url以file://作为协议标识符,将打开一个本地文件。否则会建立一个向网络上任意服务的socket连接。如果连接无法建立,则会报错:IOError。 如果一切顺利,则会返回一个类似文件的对象。这个对象支持下面的方法: read() readline() readlines() fileno() close() info() getcode() geturl() .它也有适当的迭代器支持协议。 .警告:read()方法如果size参数没有指定或是负数,则直到数据流结束才会进行读取。在通常情况下,没有一个好的方法来判定来自socket的整个流已经被读取完毕。 .除了info() getcode() geturl() ,其他的方法有和file对象相同的接口。 info()方法返回mimetools.Message类的一个实例。包括和url相关联的meta-information。当方法是HTTP时,返回的头部信息是服务器返回的html页面的头部信息(包括:Content-length 和 Content-Type). 如果是FTP,则服务器将会返回响应该FTP请求的文件长度作为头部的Content-Length。如果是可确认的MIME类型,则将会返回Content-Type头部信息。 如果是一个本地文件,则返回的头部信息中将会包括:文件最近一次更新时间的日期,文件长度的Content-Length,一个包含文件类型的Content-Type。 getUrl()返回页面真实的url。在一些情况下,HTTP服务器会将一些客户请求重定向到别的URL。urlopen()方法可以透明地处理这些操作。但是一些情况下,调用者需要知道这个客户端请求被重定向到了哪个url,此时可用geturl()得到最终重定向的真实的url getcode()将返回发送http请求后,响应的状态码。当url不是http请求时,将返回None .如果url使用了http://标识,如果指定可选的参数data,则该请求被指定为POST。(通常情况下,请求是GET)。data必须是一个标准的application/x-www-form-urlencoded格式。 可选的proxies参数可以被用来明确指出代理。代理必须是一个字典类型({协议:代理url}),空的字典表示没有可用的代理。当peoxies为空时(默认值),将会使用系统环境变量设置中的代理 需要验证的代理服务器现在还不支持 proxies代理服务器的使用如下所示: url="http://baidu.com:80" proxies={"http":"http://www.someproxy.com:3128"} #代理服务器设置:以字典形式,key为协议,如:http。 value为真实url 包括端口 f1=urllib.urlopen(url, proxies=proxies) f2=urllib.urlopen(url,proxies={}) #将代理设置为空字典,表示不使用任何代理 f3=urllib.urlopen(url,proxies=None) f4=urllib.urlopen(url) #f3 f4 代理服务器均使用系统默认 """ def urlretrieve(url,filename,reporthook,data): """ .将url指定的网站对象拷贝到本地文件中。如果需要,url可以指向一个本地文件或已存在对象的有效的缓存拷贝,此时这个对象并没有被拷贝。 .返回一个元祖:(filename,headers) filename为可找得到的本地文件名,headers是urlopen()返回对象(远程对象,可能是缓存)的info()方法的返回值。 .异常和urlopen()方法的异常一致。 .第二个参数:filename指出了文件拷贝目的地址(如果没有filename,地址将会是自动生成的临时文件地址)。 .第三个参数是一个方法,一旦网络连接建立且每一个块被读取后,这个hook方法就会被调用。hook函数需要三个参数:到目前已经被读取的块数量,每块的字节数,文件大小。在旧有的FTP服务器上,对于retrieve请求,在响应中,并不返回文件大小,此时文件大小可能为-1 .如果url使用"http://"标识符,data参数如果被指定,则该请求为POST(默认是GET请求)。data格式必须是标准的:application/x-www-form-urlencoded格式。 .在2.5版本后,如果发现可用的数据大小小于 预期大小(在Content-Length头信息中的大小),会报错:ContentTooShortError。如:当下载被中断时。 .Content_length是文件大小的下限。如果有更多信息需要读取,则urlretrieve会读取更多的信息。 但是如果实际可读信息小于预期Content-Length,则会报错 .在这个情况下,你仍然可以检索被下载的数据,它被存储在异常实例的content属性中。 .当没有提供Content-Length头信息,urlretrieve不会检查已经下载了多少数据,仅仅是返回对象。这个时候不能确保下载成功。 """ """ urllib.__urlopener 公共方法urlopen()和urlretrieve()会创建一个FancyURLopener类的实例。并用这个实例来操作urlopen()和urlretrieve()的请求。 为了覆盖这个功能,可以创建一个URLopener或者FancyURLopener的子类,然后再调用urlopen()和urlretrieve()方法之前将子类实例赋值给urllib._urlopener属性。 如:用户想要定义一个用户自定义的头信息。代码如下; class AppURLopener(urllib.FancyURLopener): version="App/1.7" urllib._urlopener=AppURLopener() """ def urlcleanup(): """ .清除之前的urlretrieve()方法可能带来的缓存。 """ "------------------------------【公共功能】--------------------------------------------" def quote_test(string,safe): """ 使用%xx逃逸字符来代替string中的特殊字符。 字母、数字、下划线将不会被quoted。默认情况下这个方法被用来quote url中的路径分隔符。 safe参数用来标识不会被quote的字符串,默认是"/" """ print urllib.quote("http://localhost:8080/#s~d") #结果http%3A//localhost%3A8080/%23s%7Ed 将字母、数字、下划线和默认的safe/之外的特殊字符转化为%xx格式的字符串 print urllib.quote("http://localhost:8080/#s~d",safe=":") #结果http:%2F%2Flocalhost:8080%2F%23s%7Ed 此时除了:和字母、数字、下划线之外的所有特殊字符均被转化为%xx类型的字符串 print urllib.quote("http://localhost:8080/#s~d",safe=":/~") #结果为:http://localhost:8080/%23s~d safe中的字符均没有被quote def quote_plus(string,safe): """ 类似于quote()。这个方法 会将空格转化为+。被用来quote html。字符串中的"+",会被quote。直到"+"被包含在safe中 """ print urllib.quote_plus("<html><body> welcome!~n </body></html>") #结果:%3Chtml%3E%3Cbody%3E++++++welcome%21%7En++%3C%2Fbody%3E%3C%2Fhtml%3E print urllib.quote_plus("<body> welcome++Lindsay </body>") #%3Cbody%3E+++welcome%2B%2BLindsay++%3C%2Fbody%3E 此时+也被quote print urllib.quote_plus("<body> welcome++Lindsay </body>","+") #%3Cbody%3E+++welcome++Lindsay++%3C%2Fbody%3E 此时"+"正常显示 def unquote(string): "quote反操作" q1=urllib.quote("http://localhost:8080/~@#") print q1 src=urllib.unquote(q1) print src def unquote_plus(string): "quote_plus反操作" q1=urllib.quote_plus("<html><head></head><body> WELCOME++Lindsay </body></html>") print q1 src=urllib.unquote_plus(q1) print src def urlencode(query,doseq): """ .将一个映射对象或二元元组的序列转化为完全编码的字符串。将对象转化为urlopen()中可用的data参数。将字典或 表单数据转化为POST请求的参数是有用的。返回值是类似于:f1=v1&f2=v2&f3=v3格式的字符串。(f和v均是由quoteplus转化而来) 当二元元组集被用来作为查询条件,每个元组的第一个参数都是key,第二个元素是value。 """ d={"a":"lindsay","b":12,"c":"56788","d":"234"} print d print urllib.urlencode(d) #a=lindsay&c=56788&b=12&d=234 def pathname2url(path): """ 将路径名称path从本地语法转化为URL中路径组件使用的形式。 返回值已经被用quote()函数处理过。 并不会生成一个完整的URL """ print urllib.pathname2url("C://TEST.TXT") #///C:///TEST.TXT def url2pathname(path): """ 将路径组件path从完全编码的url转化为本地语法形式。path并不是一个完整的URL。这个方法使用unquote()来堆path解码 """ uf1=urllib.pathname2url("C://test.txt") print uf1 path=urllib.url2pathname(uf1) print path def getproxies(): """ .返回协议和代理服务器URL的映射字典。 """ d=urllib.getproxies() print d print type(d) "------------------------------【URL Opener objects】--------------------------------------------" """ urllib.URLopener([proxies[,context[,**509]]]) 打开和阅读URLs的基本类。除非你要支持打开的对象使用http: ftp: file: 之外的协议,否则应该使用:FancyURLopener。 默认情况下,发送一个用户自定义的urllib头部信息/VVV ,VVV是urllib的版本号。应用可以通过继承URLopener或FancyURLopener,并在子类定义时为version赋值来自定义自己的User_Agent头部信息, 可选的proxies参数应该是协议和代理服务器URL映射的字典,如果proxies为{},则不适用任何代理。默认proxies为None,此时会使用系统配置的代理。 **509可以被用来当客户端使用http:协议时进行客户端验证. 如果服务端返回错误码时,URLopener对象将会报错:IOError open(fillurl[,data]): 使用合适的协议打开fillurl。这个方法会建立缓存和代理信息,然后使用输入参数调用适当的open方法。如果没有找到合适的协议,则会调用open_unknown()。data参数和urlopen()中一致 open_unknown() 重写接口,打开未知的url类型 retrieve(url[,filename[mreporthook[,data]]]) version urllib.FancyURLopener(...) 提供了对于http响应码:301 302 303 307 401的默认处理。对于上述列出的30X响应码,本地header被用来查询真正的url。对于401响应码(需要认证),会执行基本的认证。 对于30X响应码,递归次数通过maxtries属性来限制。默认是10 对于其他响应码,将会调用:http_error_default()方法。你可以在子类中重写这个方法来适当地处理这个错误。 根据RFC 2616,POST请求的301和302响应如果没有用户确认是不会自动进行重定向的。事实上,浏览器会将POST改变成GET,然后自动进行重定向。urllib复制了这个操作 异常:urllib.ContentTooShortError(msg[,content]) urllib的限制: 目前仅仅支持以下的协议:http ftp localfiles """ "----------------------------------------------【examples】-----------------------------------" def get_test(): params = urllib.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0}) f = urllib.urlopen("http://www.musi-cal.com/cgi-bin/query?%s" % params) print f,type(f) # print f.read() print f.info() print f.geturl() print f.getcode() ''' 结果: <addinfourl at 26900880 whose fp = <socket._fileobject object at 0x019B0730>> <type 'instance'> Cache-Control: private Content-Type: text/html; charset=utf-8 Server: Microsoft-IIS/7.5 X-AspNet-Version: 4.0.30319 X-Server-Identity: 1 X-Powered-By: ASP.NET Date: Tue, 11 Aug 2015 06:30:41 GMT Connection: close Content-Length: 138689 http://www.concertvault.com/?eggs=2&bacon=0&spam=1 200 ''' def post_test(): params = urllib.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0}) f = urllib.urlopen("http://www.musi-cal.com/cgi-bin/query",params) print f,type(f) # print f.read() print f.info() print f.geturl() print f.getcode() #所得结果和get_test()一致 def proxies_test(): "使用了指定的http代理,覆盖了系统设置" ''' proxies = {'http': 'http://proxy.example.com:8080/'} opener = urllib.FancyURLopener(proxies) f = opener.open("http://www.python.org") ''' "用上述代理服务器访问不到" f=urllib.urlopen("http://www.python.org") print f.info() print f.geturl() print f.getcode() print "--------------------------------------------------" "使用空的代理" proxies={} opener=urllib.FancyURLopener(proxies) f=opener.open("http://www.python.org") print f.info() print f.geturl() print f.getcode() def get_remote_info(): "利用urllib获取远程资源" fp=urllib.urlopen("http://www.python.org") op=open("out.html","wb") n=0 while 1: s=fp.read(8192) if not s: break op.write(s) n=n+len(s) fp.close() op.close() for k,v in fp.headers.items(): print k,"=",v print "copied",n ,"bytes from ",fp.url """ urlopen 函数实际上是一个辅助函数,会创建一个FancyURLopener类的实例并调用它的open方法。 也可以继承这个类完成特殊的行为。 例如下例会在必要时自动登录服务器 """ class myURLOpener(urllib.FancyURLopener): "read an URL,with automatic HTTP authentication" def setpasswd(self,user,passwd): self.__user=user self.__passwd=passwd def prompt_user_passwd(self,host,realm): return self.__user,self.__passwd def auto_authentication(): urlopener=myURLOpener() urlopener.setpasswd("mulder", "trustnol") fp=urlopener.open("http://www.secretlabs.com") print fp print fp.geturl() print fp.getcode() print len(fp.readlines()) if __name__ == "__main__": """ urlopen_test(None, None, None, None) quote_test(None,None) quote_plus(None,None) unquote(None) unquote_plus(None) urlencode(None,None) pathname2url(None) url2pathname(None) getproxies() get_test() post_test() proxies_test() get_remote_info() """ auto_authentication()