Python使用urllib2获取网络资源实例讲解


Posted in Python onDecember 02, 2013

这是具有利用不同协议获取URLs的能力,他同样提供了一个比较复杂的接口来处理一般情况,例如:基础验证,cookies,代理和其他。
它们通过handlers和openers的对象提供。
urllib2支持获取不同格式的URLs(在URL的":"前定义的字串,例如:"ftp"是"ftp:python.ort/"的前缀),它们利用它们相关网络协议(例如FTP,HTTP)
进行获取。这篇教程关注最广泛的应用--HTTP。
对于简单的应用,urlopen是非常容易使用的。但当你在打开HTTP的URLs时遇到错误或异常,你将需要一些超文本传输协议(HTTP)的理解。
最权威的HTTP文档当然是RFC 2616(http://rfc.net/rfc2616.html)。这是一个技术文档,所以并不易于阅读。这篇HOWTO教程的目的是展现如何使用urllib2,
并提供足够的HTTP细节来帮助你理解。他并不是urllib2的文档说明,而是起一个辅助作用。
获取 URLs

最简单的使用urllib2将如下所示

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

urllib2的很多应用就是那么简单(记住,除了"http:",URL同样可以使用"ftp:","file:"等等来替代)。但这篇文章是教授HTTP的更复杂的应用。
HTTP是基于请求和应答机制的--客户端提出请求,服务端提供应答。urllib2用一个Request对象来映射你提出的HTTP请求,在它最简单的使用形式中你将用你要请求的
地址创建一个Request对象,通过调用urlopen并传入Request对象,将返回一个相关请求response对象,这个应答对象如同一个文件对象,所以你可以在Response中调用.read()。

import urllib2
req = urllib2.Request('https://3water.com')
response = urllib2.urlopen(req)
the_page = response.read()

记得urllib2使用相同的接口处理所有的URL头。例如你可以像下面那样创建一个ftp请求。

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

在HTTP请求时,允许你做额外的两件事。首先是你能够发送data表单数据,其次你能够传送额外的关于数据或发送本身的信息("metadata")到服务器,此数据作为HTTP的"headers"来发送。
接下来让我们看看这些如何发送的吧。
Data数据
有时候你希望发送一些数据到URL(通常URL与CGI[通用网关接口]脚本,或其他WEB应用程序挂接)。在HTTP中,这个经常使用熟知的POST请求发送。这个通常在你提交一个HTML表单时由你的浏览器来做。
并不是所有的POSTs都来源于表单,你能够使用POST提交任意的数据到你自己的程序。一般的HTML表单,data需要编码成标准形式。然后做为data参数传到Request对象。编码工作使用urllib的函数而非
urllib2。

import urllib
import urllib2
url = 'https://3water.com'
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()

记住有时需要别的编码(例如从HTML上传文件--看http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13 HTML Specification, Form Submission的详细说明)。
如ugoni没有传送data参数,urllib2使用GET方式的请求。GET和POST请求的不同之处是POST请求通常有"副作用",它们会由于某种途径改变系统状态(例如提交成堆垃圾到你的门口)。
尽管HTTP标准说的很清楚POSTs通常会产生副作用,GET请求不会产生副作用,但没有什么可以阻止GET请求产生副作用,同样POST请求也可能不产生副作用。Data同样可以通过在Get请求
的URL本身上面编码来传送。
可看如下例子

 >>> 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 = 'https://3water.com' 
 >>> full_url = url + '?' + url_values 
 >>> data = urllib2.open(full_url)

Headers
我们将在这里讨论特定的HTTP头,来说明怎样添加headers到你的HTTP请求。
有一些站点不喜欢被程序(非人为访问)访问,或者发送不同版本的内容到不同的浏览器。默认的urllib2把自己作为“Python-urllib/x.y”(x和y是Python主版本和次版本号,例如Python-urllib/2.5),
这个身份可能会让站点迷惑,或者干脆不工作。浏览器确认自己身份是通过User-Agent头,当你创建了一个请求对象,你可以给他一个包含头数据的字典。下面的例子发送跟上面一样的内容,但把自身
模拟成Internet Explorer。

import urllib
import urllib2
url = 'https://3water.com'
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()

response应答对象同样有两个很有用的方法。看下面的节info and geturl,我们将看到当发生错误时会发生什么。
Handle Exceptions处理异常
当urlopen不能够处理一个response时,产生urlError(不过通常的Python APIs异常如ValueError,TypeError等也会同时产生)。
HTTPError是urlError的子类,通常在特定HTTP URLs中产生。
URLError
通常,URLError在没有网络连接(没有路由到特定服务器),或者服务器不存在的情况下产生。这种情况下,异常同样会带有"reason"属性,它是一个tuple,包含了一个错误号和一个错误信息。
例如

>>> req = urllib2.Request('https://3water.com')
>>> try: urllib2.urlopen(req)
>>> except URLError, e:
>>>    print e.reason
>>>
(4, 'getaddrinfo failed')

HTTPError
服务器上每一个HTTP 应答对象response包含一个数字"状态码"。有时状态码指出服务器无法完成请求。默认的处理器会为你处理一部分这种应答(例如:假如response是一个"重定向",需要客户端从别的地址获取文档
,urllib2将为你处理)。其他不能处理的,urlopen会产生一个HTTPError。典型的错误包含"404"(页面无法找到),"403"(请求禁止),和"401"(带验证请求)。
请看RFC 2616 第十节有所有的HTTP错误码
HTTPError实例产生后会有一个整型'code'属性,是服务器发送的相关错误号。
Error Codes错误码
因为默认的处理器处理了重定向(300以外号码),并且100-299范围的号码指示成功,所以你只能看到400-599的错误号码。
BaseHTTPServer.BaseHTTPRequestHandler.response是一个很有用的应答号码字典,显示了RFC 2616使用的所有的应答号。这里为了方便重新展示该字典。(译者略)
当一个错误号产生后,服务器返回一个HTTP错误号,和一个错误页面。你可以使用HTTPError实例作为页面返回的应答对象response。这表示和错误属性一样,它同样包含了read,geturl,和info方法。

>>> req = urllib2.Request('http://www.python.org/fish.html')
>>> try:
>>>     urllib2.urlopen(req)
>>> except URLError, e:
>>>     print e.code
>>>     print e.read()
>>>
404
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
  "http://www.w3.org/TR/html4/loose.dtd">
<?xml-stylesheet href="./css/ht2html.css"
  type="text/css"?>
<html><head><title>Error 404: File Not Found</title>
...... etc...

Wrapping it Up包装
所以如果你想为HTTPError或URLError做准备,将有两个基本的办法。我则比较喜欢第二种。
第一个:
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

注意:except HTTPError 必须在第一个,否则except URLError将同样接受到HTTPError。
第二个:

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

info and geturl
urlopen返回的应答对象response(或者HTTPError实例)有两个很有用的方法info()和geturl()
geturl -- 这个返回获取的真实的URL,这个很有用,因为urlopen(或者opener对象使用的)或许
会有重定向。获取的URL或许跟请求URL不同。
info -- 这个返回对象的字典对象,该字典描述了获取的页面情况。通常是服务器发送的特定头headers。目前是httplib.HTTPMessage 实例。
经典的headers包含"Content-length","Content-type",和其他。查看Quick Reference to HTTP Headers(http://www.cs.tut.fi/~jkorpela/http.html)
获取有用的HTTP头列表,以及它们的解释意义。
Openers和Handlers
当你获取一个URL你使用一个opener(一个urllib2.OpenerDirector的实例,urllib2.OpenerDirector可能名字可能有点让人混淆。)正常情况下,我们
使用默认opener -- 通过urlopen,但你能够创建个性的openers,Openers使用处理器handlers,所有的“繁重”工作由handlers处理。每个handlers知道
如何通过特定协议打开URLs,或者如何处理URL打开时的各个方面,例如HTTP重定向或者HTTP cookies。
如果你希望用特定处理器获取URLs你会想创建一个openers,例如获取一个能处理cookie的opener,或者获取一个不重定向的opener。
要创建一个 opener,实例化一个OpenerDirector,然后调用不断调用.add_handler(some_handler_instance).
同样,可以使用build_opener,这是一个更加方便的函数,用来创建opener对象,他只需要一次函数调用。
build_opener默认添加几个处理器,但提供快捷的方法来添加或更新默认处理器。
其他的处理器handlers你或许会希望处理代理,验证,和其他常用但有点特殊的情况。
install_opener 用来创建(全局)默认opener。这个表示调用urlopen将使用你安装的opener。
Opener对象有一个open方法,该方法可以像urlopen函数那样直接用来获取urls:通常不必调用install_opener,除了为了方便。

Python 相关文章推荐
python排序方法实例分析
Apr 30 Python
Python实现把数字转换成中文
Jun 29 Python
python的pstuil模块使用方法总结
Jul 26 Python
Django在admin后台集成TinyMCE富文本编辑器的例子
Aug 09 Python
Atom Python 配置Python3 解释器的方法
Aug 28 Python
python__new__内置静态方法使用解析
Jan 07 Python
利用python在excel中画图的实现方法
Mar 17 Python
如何在python中执行另一个py文件
Apr 30 Python
python利用蒙版抠图(使用PIL.Image和cv2)输出透明背景图
Aug 04 Python
Python中的流程控制详解
Feb 18 Python
python百行代码实现汉服圈图片爬取
Nov 23 Python
Python字符串的转义字符
Apr 07 Python
python读写文件操作示例程序
Dec 02 #Python
python通过ElementTree操作XML获取结点读取属性美化XML
Dec 02 #Python
一个简单的python程序实例(通讯录)
Nov 29 #Python
Python时间戳与时间字符串互相转换实例代码
Nov 28 #Python
python计算程序开始到程序结束的运行时间和程序运行的CPU时间
Nov 28 #Python
SublimeText 2编译python出错的解决方法(The system cannot find the file specified)
Nov 27 #Python
Pyramid添加Middleware的方法实例
Nov 27 #Python
You might like
PHP输出控制功能在简繁体转换中的应用
2006/10/09 PHP
PHP+DBM的同学录程序(5)
2006/10/09 PHP
Codeigniter中集成smarty和adodb的方法
2016/03/04 PHP
对联广告js flash激活
2006/10/19 Javascript
javascript中&quot;/&quot;运算符常见错误
2010/10/13 Javascript
jQuery回车实现登录简单实现
2013/08/20 Javascript
使用js简单实现了tree树菜单
2013/11/20 Javascript
js中Image对象以及对其预加载处理示例
2013/11/20 Javascript
一个简单的全屏图片上下打开显示网页效果示例
2014/07/08 Javascript
js获取表格的行数和列数的方法
2015/10/23 Javascript
浅谈JavaScript函数的四种存在形态
2016/06/08 Javascript
vue v-on监听事件详解
2017/05/17 Javascript
JS库之Particles.js中文开发手册及参数详解
2017/09/13 Javascript
vue组件父子间通信之综合练习(聊天室)
2017/11/07 Javascript
浅谈super-vuex使用体验
2018/06/25 Javascript
详解Vue取消eslint语法限制
2018/08/04 Javascript
vue如何安装使用Quill富文本编辑器
2018/09/21 Javascript
Js参数RSA加密传输之jsencrypt.js的使用
2020/02/07 Javascript
[04:52]DOTA2亚洲邀请赛附加赛 TOP10精彩集锦
2015/01/29 DOTA
python实现扫描日志关键字的示例
2018/04/28 Python
python实现在函数中修改变量值的方法
2019/07/16 Python
基于python traceback实现异常的获取与处理
2019/12/13 Python
Django 项目通过加载不同env文件来区分不同环境
2020/02/17 Python
python修改微信和支付宝步数的示例代码
2020/10/12 Python
移动Web—CSS为Retina屏幕替换更高质量的图片
2012/12/24 HTML / CSS
html5 乒乓球(碰撞检测)实例二
2013/07/25 HTML / CSS
捷克原创男装和女装购物网站:Bolf.cz
2018/04/28 全球购物
免税水晶:Duty Free Crystal
2019/05/13 全球购物
护校行动方案
2014/05/31 职场文书
基层党组织整改方案
2014/10/25 职场文书
2015年大学生暑期实习报告
2015/07/13 职场文书
2015年小学总务工作总结
2015/07/21 职场文书
智慧人生:永远不需要向任何人解释你自己
2019/08/20 职场文书
导游词之白茶谷九龙峡
2019/10/23 职场文书
nginx 防盗链防爬虫配置详解
2021/03/31 Servers
原生JS实现飞机大战小游戏
2021/06/09 Javascript