Articles

Python's urllib

urllib

Python 2的urllib使用非常简单,urllib.urlopen(url)这短短的一句话就可以打开一个页面,并返回页面的内容。Python 2.3中,此API加入了对代理服务器的支持,2.6将其标记为deprecated,并建议使用urllib2.urlopen(),Python 3则彻底删除了这个API。

urllib.urlopen()默认使用urllib.FancyURLopener去打开一个URL。HTTP header中,User-Agent使用的是类似Python-urllib/1.17这样的字符串。可以通过继承FancyURLopener来替换这一信息。但似乎没有直接的办法来添加额外的HTTP header。

urllib还提供了一些工具类API,例如urllib.urlencode(query)可以用来生成GET请求后面的查询参数。urllib.quote(string)可以对特殊字符进行转意。

官方文档中说,urllib只支持HTTP 0.9和1.0。

urllib2

相对于urllib来说,urllib2的功能要强大很多。urllib2.urlopen(url)中的URL可以是一个地址,也可以是一个urllib2.Request对象。我们可以通过Request.add_header(key, val)为一个HTTP请求添加想要的header。也可以通过Request.set_proxy(host, type)为一个请求设置代理。

urllib2.urlopen()使用urllib2.OpenerDirector去打开一个URL。从名字可以看出,它已经不仅仅是一个opener了,而是一个director,负责指导、协调打开URL的整个过程。我们可以通过urllib2.build_opener[handler, ...]来创建一个OpenerDirector。参数中的这些handler会被串在一起,在打开URL的过程中,相应的handler会被调用。默认情况下,ProxyHandlerHTTPHandler等一些重要的handler会被自动加在所有handler的前面。通过提供一个自定义的ProxyHandler,并将其添加到opener中去,就可以让后续的所有请求使用该代理服务器。

urllib2并没有提供额外的工具类API,所以urllib2的目的不是完全取代urllib,而只是对urllib中的不足进行改进。

urllib2支持HTTP 1.1,Python 2.7中,默认的User-Agent是Python-urllib/2.7。

urllib3

Python 3大刀阔斧地对Python 2中的urllib和urllib2进行了整合,并重新命名为urllib。

  • urllib.request中包含了urlopen()Request等用于发送请求的API,它基本上等同于urllib2
  • urllib.error中包含了urllib.request可能抛出的各种异常
  • urllib.parse其实就是Python 2中urllib里的那些工具类API,例如urlencode。此外还加入和更多的URL处理相关的API
  • urllib.robotparser用于解析robot.txt

{% dot graph.svg digraph G { subgraph cluster0 { label="Python2";

  subgraph cluster1 {
    label="urllib";
    labeljust=l;
    urlopen1 [label="urlopen()"]
    urlencode1 [label="urlencode()"]
    quote1 [label="quote()"];
    opener1 [label="FancyURLopener"]
  }

  subgraph cluster2 {
    labeljust=l;
    label="urllib2";
    urlopen2 [label="urlopen()"]
    opener2 [label="OpenerDirector"]
    Request2 [label="Request"];
  }
}

subgraph cluster3 {
  label="Python3";
  labelloc=b;

  subgraph cluster4 {
    label="urllib.request";
    labelloc=b;
    labeljust=l;
    urlopen3 [label="urlopen()"]
    opener3 [label="OpenerDirector"]
    Request3 [label="Request"];
  }

  subgraph cluster5 {
    label="urllib.parse";
    labelloc=b;
    labeljust=l;
    urlencode3 [label="urlencode()"]
    quote3 [label="quote()"]
  }
}

urlencode1 -> urlencode3;
quote1 -> quote3;
urlopen1 -> urlopen2 [style=dotted]
urlopen2 -> urlopen3;
opener1 -> opener2 [style=dotted]
opener2 -> opener3;
Request2 -> Request3;

} %}

可见,Python 3的urllib结构清晰,但缺点是,它不能与Python 2兼容。

如果是新项目或者初次使用urllib,建议还是直接使用Python 3的urllib吧,避免了Python 2中urllib和urllib2混合使用的麻烦。