(译)Python中如何使用urllib2模块

这是Python For Beginners 中的一篇文章,原文How to use urllib2 in Python,对urllib2讲解的深入浅出,确实是一篇很好的urllib2入门教程。为了确保翻译准确,关键词汇会使用原文或将原文备注于括号内。全文翻译如下:

概述(Overview)

尽管文章题目为”urllib2“,但是我们也会展示一些使用urllib模块的例子,因为它们经常一起使用。

这是一篇介绍urllib2的文章,在这里我们将关注Getting URLs、Requests、Posts、User Agents以及Error handling等内容。

更多内容请查看官方文档。

这篇文章基于Python 2.x 版本

HTTP 基于requests(请求)和response(响应)----客户发送请求,服务器返回响应。

Internet上的程序可以作为一个客户(访问资源),或者作为一个服务器(提供服务)

URL标识了Internet上一个资源的地址

什么是urlllib2(What is Urllib2)

urllib2是一个Python模块,可以用来获取URL资源(fetching URLs)

它定义了函数和类,用以协助URL操作(actions),如基本身份验证和摘要式身份验证(basic and digest authentication)、重定向、cookies等

通过导入urllib2模块,开始我们的奇幻之旅

urllib2和urllib的区别(What is the difference between urllib and urllib2)

尽管两个模块都完成URL 请求相关的工作,但是它们的功能(functionality)不一样

urllib2可以接受一个Request对象,用来设置URL request的头部信息(header);urllib只能接受一个URL

urllib提供了urlencode函数,用来生成GET 查询字符串(query strings);urllib2没有这个函数

正因如此,urllliburllib2常用一起使用。

更多内容,请查看文档UrllibUrllib2

 

什么是urlopen(What is urlopen)

urllib2提供了一个非常简单的接口,以urlopen函数这种形式。

这个函数能够使用很多不同的协议(如HTTP、FTP…)取回URLs资源(fetching URLs)

仅需要把URL传递给urlopen(),就能获得远程数据的一个“类似文件”(file-like)的句柄(handle)。

(译注:文件操作如 fd = file(“1.txt”);fd.read()…

urlopen函数使用如url=”http://zhujiangtao.com”;fd=urlopen(url);fd.read()…)

另外,urllib2提供了处理common situations的接口,如基本的身份验证、cookies、代理(proxies)等等。

通过被称为handlers和openers的对象,提供了上述这些功能。

获取URL资源(Getting URLs)

这是使用urllib2最基本的方式.

下面的代码会为你展示如何使用urllib2,发送一个简单的request请求。

首先导入(import)urllib2模块

将response存储到一个变量(response)

response现在就是一个“类似文件”的对象

从response中读取数据到一个string中(html)

用这个string做些什么

注意:如果URL中有空格(space),你需要使用urlencode解析它

让我们来看一个关于它如何工作的示例代码

[python]import urllib2
response = urllib2.urlopen('http://pythonforbeginners.com/')
print response.info()
html = response.read()
# do something
response.close() # best practice to close the file

#Note: you can also use an URL starting with "ftp:", "file:", etc.).[/python]

远程服务器接受传入的值,格式化一个普通文本response并传回。

urlopen()的返回值让我们可以通过info()函数访问HTTP服务器的头部信息,通过像read()和readlines()这样的函数来访问远程资源的数据。

另外,urlopen()返回的文件对象是可迭代的(或者说是可遍历的)(iterable)

简单的urllib2脚本(Simple urllib2 script)

让我们看另一段urllib2示例代码

[python]import urllib2

response = urllib2.urlopen('http://python.org/')
print "Response:", response

# Get the URL. This gets the real URL.
print "The URL is: ", response.geturl()

# Getting the code
print "This gets the code: ", response.code

# Get the Headers.
# This returns a dictionary-like object that describes the page fetched,
# particularly the headers sent by the server
print "The Headers are: ", response.info()

# Get the date part of the header
print "The Date is: ", response.info()['date']

# Get the server part of the header
print "The Server is: ", response.info()['server']

# Get all data
html = response.read()
print "Get all data: ", html

# Get only the length
print "Get the length :", len(html)
# Showing that the file object is iterable

for line in response:
print line.rstrip()

# Note that the rstrip strips the trailing newlines and carriage returns before
# printing the output.[/python]

使用urllib2下载文件(Download files with Urllib2)

这是一个小型的脚本代码,它可以从pythonforbeginners.com网站下载一个文件

[python]import urllib2

# file to be written to
file = "downloaded_file.html"

url = "http://www.pythonforbeginners.com/"
response = urllib2.urlopen(url)

#open the file for writing
fh = open(file, "w")

# read from request while writing to file
fh.write(response.read())
fh.close()

# You can also use the with statement:
with open(file, 'w') as f: f.write(response.read())[/python]

下面这段代码的区别在于我们使用’wb’,意思是我们以二进制的形式打开文件

[python]import urllib2

mp3file = urllib2.urlopen("http://www.example.com/songs/mp3.mp3")
output = open('test.mp3','wb')
output.write(mp3file.read())
output.close()[/python]

urllib2 请求(Urllib2 Requests)

Request对象代表了你正在请求的HTTP request。

最简单的方式就是你创建一个Request对象,然后指定你想要获取资源的URL地址。使用这个Request对象为参数,调用urlopen函数,会返回一个URL请求对应的response响应对象。urllib2类中的Request函数可以同时接受URL和参数。

当你不包含数据(仅传递一个url),这个request实际上会被作为一个GET 请求。

当你包含了数据,这个reques会被作为POST请求,传入的url会被当做POST的url,参数会被作为http post content。

让我们看下面的示例代码

[python]import urllib2
import urllib

# Specify the url
url = 'http://www.pythonforbeginners.com'

# This packages the request (it doesn't make it)
request = urllib2.Request(url)

# Sends the request and catches the response
response = urllib2.urlopen(request)

# Extracts the response
html = response.read()

# Print it out
print html[/python]

你可以设置Request传出的数据,并发送到服务器(You can set the outgoing data on the Request to post it to the server.)。另外,你可以传递关于数据本身或者request请求本身的数据的附加信息(“metadata”)到服务器,这个信息会作为HTTP 头部(headers)发送。

如果你要以POST方式发送数据(POST data),你必须首先将数据创建到一个字典(dictionary)中。

确保你弄懂了下面代码(和上面的一段代码是连续的)

[python]# Prepare the data
query_args = { 'q':'query string', 'foo':'bar' }

# This urlencodes your data (that's why we need to import urllib at the top)
data = urllib.urlencode(query_args)

# Send HTTP POST request
request = urllib2.Request(url, data)

response = urllib2.urlopen(request)

html = response.read()

# Print the result
print html[/python]

用户代理(User Agents)

浏览器标识自身的方法是通过User-Agent header

默认情况下,urllib2标识自身为Python-urllib/x.y (其中,x和y分别代表Python发行版本的主、次版本号),这样会使网站感到迷惑,或者简单说,不能工作。

使用urllib2,你可以添加自己的urllib2头部。你想要这样做的一个理由是:有些网站不喜欢被程序浏览(browsed by programs)。(译注:使用urllib2的Python程序会默认把自己的标识设为Python-urllib/x.y,这就表明了这是一个Python程序,有些网站会阻止其他人的程序访问本站的资源)

如果你创建一个应用程序,这个应用程序会访问其他人的网站资源,在你的request请求中包含正真的用户代理信息是一件有礼貌的事,这样他们可以更容易识别出命中的资源。(If you are creating an application that will access other people’s web resources,it is  courteous to include real user agent information in your requests, so they can identify the source of the hits more easily.)

当你创建一个Request对象时,你可以添加你自己头部到一个字典中,在打开一个request请求之前,使用add_header()函数设置用户代理的值。

代码看起来会像这样:

[python]# Importing the module
import urllib2

# Define the url
url = 'http://www.google.com/#q=my_search'

# Add your headers
headers = {'User-Agent' : 'Mozilla 5.10'}

# Create the Request.
request = urllib2.Request(url, None, headers)

# Getting the response
response = urllib2.urlopen(request)

# Print the headers
print response.headers[/python]

你还可以通过add_header()函数添加头部。

语法为:Request.add_header(key, val) 【urllib2.Request.add_header

下面的代码,使用Mozilla 5.10 作为用户代理,web服务的日志文件中显示的也会是这个。

[python]import urllib2

req = urllib2.Request('http://192.168.1.2/')
req.add_header('User-agent', 'Mozilla 5.10')
res = urllib2.urlopen(req)
html = res.read()
print html[/python]

日志文件中会这样显示:“GET / HTTP/1.1″ 200 151 “-” “Mozilla 5.10″

 

urllib.urlparse

urlpase模块提供了分析URL字符串的函数

它提供了一个标准的接口,可以把URL字符串分解成几个可选的部分,称为组件(components),它们是(scheme, location, path, query 以及 fragment)

比如说你有一个url: http://www.python.org:80/index.html

  • sheme 就是 http
  • location 就是www.python.org:80
  • path 就是index.html
  • 没有queryfragment

最常用的函数是urljoinurlsplit

[python]import urlparse

url = "http://python.org"
domain = urlparse.urlsplit(url)[1].split(':')[0]
print "The domain name of the url is: ", domain[/python]

更多关于urlparse的信息,请参与官方文档.

urllib.urlencode

当你通过URL传递信息时,你需要确保它只使用了指定的允许使用的字符.允许使用的字符有字母表中所哟字母、数字以及少量特定的在URL字符串中有意义的字符。

最常用的编码字符是空格字符。只要你在URL中看到+号,你就会看见空格字符。它代表了空格字符。

+号作为一个特殊符号,它在URL中代表了一个空格。

参数可以通过编码并追加到URL中,来传递给服务器。

让我们看一下下面的示例代码

[python]import urllib
import urllib2

query_args = { 'q':'query string', 'foo':'bar' } # you have to pass in a dictionary

encoded_args = urllib.urlencode(query_args)
print 'Encoded:', encoded_args

url = 'http://python.org/?' + encoded_args
print urllib2.urlopen(url).read() [/python]

如果我现在把它打印出来,我会得到一个像这样的编码字符串:q=query+string&foo=bar

Python的urllencode函数接受variable/value  pairs,然后创建合适的转义的查询字符串(querystring)

[python]from urllib import urlencode

artist = "Kruder & Dorfmeister"
artist = urlencode({'ArtistSearch':artist})[/python]

artist变量等同于 ArtistSearch=Kruder+%26+Dorfmeister

出错处理(Error Handling)

这节出错处理的讲解基于Voidspace.org.uk 上一篇很好的文章Urllib2 - The Missing Manual

urlopen函数在不能处理一个response响应时抛出(raise)URLError错误。

HTTPErrorURLError的子类,在某些HTTP URLs中会被抛出。

URLError

通常,URLError的抛出是因为没有网络连接,或者指定的服务器不存在。

在这种情况下,抛出的exception异常会有一个名为’reason’的属性,这个属性是一个包含了错误代码和错误文本信息的元组。URLError的例子如下

[python]req = urllib2.Request('http://www.pretend_server.org')

try:
urllib2.urlopen(req)

except URLError, e:
print e.reason

#(4, 'getaddrinfo failed')[/python]

HTTPError

每一个来自服务器的HTTP response响应,都包含一个数字“状态码”(status code)

有时,该状态码表示服务器不能完成请求。默认的handlers会为你处理这些响应中一些(比如,如果response是一个重定向’redirection’,请求客户从另一个URL中获取文档,urllib2会为你处理这些)。对于那些不能处理的,urlopen会抛出一个HTTPError异常。典型的错误包括‘404’(page not found),’403’(request forbidden),’401’(authentication required)。

当错误抛出时,服务器会返回一个HTTP 错误码和一个出错页面。你可以使用HTTPError实例作为返回页面的response响应。这意味着它不仅有错误码属性,还可以有read、geturl、info等函数。

[python]req = urllib2.Request('http://www.python.org/fish.html')

try:
urllib2.urlopen(req)

except URLError, e:
print e.code
print e.read()[/python]

[python]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[/python]

请参阅下面的链接,以此获得对urllib2模块更多的理解。

资源和延伸阅读

http://pymotw.com/2/urllib2/
http://www.kentsjohnson.com/
http://www.voidspace.org.uk/python/articles/urllib2.shtml
http://techmalt.com/
http://www.hacksparrow.com/
http://docs.python.org/2/howto/urllib2.html
http://www.stackoverflow.com
http://www.oreillynet.com/

 

作者:JarvisChu
原文链接:(译)Python中如何使用urllib2模块
版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0

发表评论