urllib初探

Posted rajxie

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了urllib初探相关的知识,希望对你有一定的参考价值。

 

urllib库


 

简介

urllib是python内置的HTTP请求库。它包含以下4个模块

  • request : 最基本的HTTP请求模块。用于模拟发送请求。
  • error : 异常处理模块。用于捕获异常,排除错误对程序正常进行的干扰。
  • parse : 工具模块。用于处理URL,如拆分、合并、解析。
  • robotparser : 主要用于识别网站的robot.txt文件(爬虫协议,并判断哪些资源可供爬取)。

通过urllib库来获取网页内容是一个福音。我们只需关心请求的链接是什么需要传的参数是什么如何设置可选的请求头即可,而无需深入到底层了解它到底是怎么传输和通信的。

 

使用

构造请求

使用urllib的request模块构造HTTP请求,实现请求的发送并获取响应。

1. urlopen()

urlopen的API:urllib.request.urlopen(urldata=None[timeout]*cafile=Nonecapath=Nonecadefault=Falsecontext=None)

  • 第一个参数url: 用于请求URL
  • 第二个参数data: 用于在请求中附加数据。(附加数据的请求一般被认为是POST方式的请求,因为只有POST才需要提交一些表单(data form)信息。否则就是GET方式
  • 第三个参数timeout: 用于设置超出时间(单位秒),支持HTTP、HTTPS、 FTP请求。指定该参数,若请求在设置的时间内得不到响应,则抛出异常。不指定使用全局默认时间。
  • 其他参数: 

 

url参数:

技术分享图片

  • ① 将urllib.request模块导入当前的工作环境中
  • ② 使用urlopen()方法,构造一个HTTP请求赋值给response变量(HTTP请求的作用是:实现请求的发送并获取响应)
  • ③ 使用type()方法,发现response变量为一个HTTPResponse类型的对象
  • ④ 通过对象名.read()方法就可以得到返回的网页内容了。

 

通过②③,我们知道了在urlopen()函数里传入一个URL,将返回一个HTTPResponse类型的对象。对象就包含一些属性和方法,对吧?哈哈

read()、readinto()、getheader(name)、getheaders()、fileno()等方法;msg、version、status、reason、debuglevel、closed等属性。

 

技术分享图片

技术分享图片

  • 调用status属性,得到该对象的状态码;
  • 调用getheaders()方法,得到返回内容的全部头部信息;
  • 调用getheader(name)方法,得到特定部分的头部信息了。

注意:getheaders()是复数形式,返回头部的全部信息;getheader(name)是单数的,表示按需获取。  

 

对比

库名urllib库requests库
构造请求 request.urlopen(url) get(url)
响应状态 status status_code
响应内容 read() text
加入Headers等信息 先行构建一个Request类型的对象,并使之作为request.urlopen()方法的参数 直接在get()方法中使用headers参数

如何理解使用urllib获取的响应体是使用read()方法来解析?姑且将其获得的响应体看作一个file-like对象对文件使用read()方法自然说得过去了。

 

 

data参数:如果传递了这个参数,则请求方式不再是GET方式,而是POST方式。该参数为bytes类型,需使用bytes()方法转化。

技术分享图片

传递的参数出现在了form字段中,说明是表单提交。这是一个POST请求确证凿凿。

 

timeout参数:用于设置超时时间。若请求超出了设置的这个时间尚未获取响应,将抛出异常。不指定则会使用全局默认时间。

  出现异常:

技术分享图片

技术分享图片

  捕获异常:

技术分享图片

 

其他参数:

cafile和capath分别指定CA证书和它的路径,在请求HTTPS链接是会有用。

cadefault参数现已弃用,其默认值为False。

context参数则必须为ssl.SSLContext类型,用来指定SSL设置。

 

 

2. Request

urlopen()方法可以实现最基本的请求的发起,但这个请求并不完整。如果请求中需要加入Headers等信息,就需要通过Request类来构建了

通过构造Request数据结构,一方面可以将请求独立为一个对象,另一方面我们也可以更加灵活地配置参数。这颇有点囊括宇宙的意味。

Request的API:urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)

  • 第一个参数url: 用于请求URL
  • 第二个参数data: bytes类型内容。若为字典,可先用urllib.parse.urlencode()方法编码为字符串。
  • 第三个参数headers: 请求头。通过headers(字典类型)直接构造,或通过请求实例的add_header()方法构造。
  • 第四个参数origin_req_host: 请求方的host名称或IP地址。
  • 第五个参数unverifiable: 布尔类型,表示请求是否是无法验证的。默认False即有足够的权限来接收这个请求的权限)。
  • 第六个参数method: 字符串类型,表示请求使用的方法。如GET、POST等。

除了第一个参数为必选的之外,其余均为可选参数。

 

上面是很教条化的东西。下面,让我们看两个例子吧。

第一个例子:

  ① 先导入urllib.request模块;

  ② 再通过向urllib.request模块中的Request类传入一个URL构建一个请求实例;

  ③ 之后,我们再将请求对象作为urlopen()方法的参数来获取服务器的响应;

  ④ 最后,打印出请求的内容。

整个流程分为:URL构建请求对象→ 传入请求对象获取响应 → 输出响应内容

技术分享图片

第二个例子:

  ① 先导入urllib.request模块和urllib.parse模块;

  ② 确定url——使用赋值的方式,将url具体化。直接传入urlopen()也无碍,这里是为了防止api的书写过长;

  ③ 构建一个请求头(通过User-Agent可以模拟任何的浏览器,防止爬虫身份的暴露);

  ④ 构建一个字典存储表单的信息。由于该参数要求为字节流格式,我们还需要分两步走:

    先将之序列化——使用urllib.parse模块的urlencode()方法,

    再将之转换为字节流编码格式的内容——使用bytes()函数

  ⑤ 准备齐全就可以开始构建一个Request类的实例了。下面的例子将之赋值给request

  ⑥ 最后,将请求对象传入urllib.request模块的urlopen()方法,成功获取了服务器的响应并打印出响应内容。

技术分享图片

技术分享图片

 

3. 高级用法 

上面我们所构建的请求,对于一些更为高级的操作(如登录认证,代理设置,Cookies处理等等)就显得无能为力了。为此,引入了HandlerOpener,以便深入一层进行配置(通过使用底层的实例来完成了)。

(1) Handler对应BaseHandler类(所有其他Handler的父类):

 (处理器之意,正所谓“术业”chu li qi 有专攻:有处理登录验证的,有处理Cookies的,有处理代理设置的)。 

  • HTTPDefaultErrorHandler: 用于处理HTTP响应错误,错误都会抛出HTTPError类型的异常。
  • HTTPRedirectHandler: 用于处理重定向。
  • HTTPCookieProcessor: 用于处理Cookies。
  • ProxyHandler: 用于设置代理,默认代理为空。
  • HTTPPasswordMgr: 用于管理密码,即维护用户名和密码组成的表。
  • HTTPBasicAuthHandler: 用于管理验证。

 

(2) Operner对应OpenerDirector类:

Opener可以使用open()方法,返回类型和urlopen()一致。

PS:之前使用的Request和urlopen()方法,是一个默认的opener(相当类库为我们封装好了的常用的请求方法)。 

 

(3) Opener与Handler的关系:使用Handler来构建Opener(实例化一个Opener, 然后再通过它调用一些handler实例)。

  • build_opener: 默认添加了数个handlers。同时作为一个提供快速添加或重写默认handlers的途径。
  • install_opener: 使一个opener对象作为全局的默认opener,即urlopen()

 

下面,来观望几个例子:

验证

from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener
from urllib.error import URLError

username = username
password = password
url = http://localhost:5000/

p = HTTPPasswordMgrWithDefaultRealm()
p.add_password(None, url, username, password)
auth_handler = HTTPBasicAuthHandler(p)
opener = build_opener(auth_handler)

try:
    result = opener.open(url)
    html = result.read().decode(utf-8)
    print(html)
except URLError as e:
    print(e.reason)

这个例子使用了一个add_password之后的HTTPPasswordMgrWithDefaultRealm对象,作为参数构造了一个HTTPBasicAuthHandler实例,即处理验证的Handler。接着将该Handler传给build_opener()方法构建一个Opener。一旦这个Opener发送请求,则代表验证成功。

 

代理

from urllib.request import ProxyHandler, build_opener
from urllib.error import URLError

proxy_handler = ProxyHandler({
    http: http://127.0.0.1:5000,
    https: https://127.0.0.1:5000
})
opener = build_opener(proxy_handler)
try:
    response = opener.open(https://www.baidu.com)
    print(response.read().decode(utf-8))
except URLError as e:
    print(e.reason)

 

 

Cookies

import http.cookiejar, urllib.request
from urllib.error import URLError

cookie = http.cookiejar.CookieJar()
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)

try:
    response = opener.open(http://www.baidu.com)
except URLError as e:
    print(e.reason)

for item in cookie:
    print(item.name + = + item.value)

 

 

处理异常

urllib.error模块定义了由request模块产生的异常。也就是说,若程序出现了问题,request模块会抛出error模块中定义的异常。

URLError类: 继承自OSError类,是error异常的基类。因此,由request模块产生的异常都可以通过这个类来处理。

(有一个属性)

  • reason: 返回错误的原因。

HTTPError类:  URLError类的子类,专门用于处理HTTP请求错误,比如认证失败等。

(有三个属性)

  • code: 返回HTTP状态码。
  • reason: 返回错误的原因。
  • headers: 返回请求头。

注意:有时,reason属性返回的不一定是字符串,也可能是一个对象。

import urllib.request
import urllib.error
import socket

try:
    response = urllib.request.urlopen(https://www.baidu.com, timeout=0.01)
except urllib.error.URLError as e:
    print(type(e.reason))
    if isinstance(e.reason, socket.timeout):
        print(TIME OUT)

 

总结

以上的介绍,主要涉及到urllib库中的urllib.request和urllib.error模块。

urllib.request模块主要用于构造请求。使用urlopen()可以构造基本的请求,使用Request类构建更为完整的请求,使用Handler和Opener类可以构造更为高级的请求。

  • urlopen()主要用到的参数有url、data、timeout,这里需要注意的是data参数应当为bytes类型。
  • Request()则将请求独立为一个对象,使能灵活地配置参数,主要用到的有url、data、headers、method。
  • Handler和Opener类则是将请求深入地进行配置,主要是将某一特定的handler作为build_opener()的参数构建一个Opener,接着使用open()方法则可以打开链接了。

后两者与urlopen()的关系:

  • 由于Request()实例化之后是供urlopen()作为参数使用,因而两者在参数上有所交叉是无可厚非的;
  • 而urlopen()是urllib为我们提供的一个默认的Opener,因而对于Opener使用open()返回的类型与urlopen()的一致也不必感到诧异。

 

urllib.error模块主要用于处理urllib.request模块产生的异常。其中URLError类异常是HTTPError类的基类,在处理时应当先使用范围较小的异常类进行处理,再涵盖范围较大的。

 

本文参考:《Python3 网络爬虫开发实战》

以上是关于urllib初探的主要内容,如果未能解决你的问题,请参考以下文章

爬虫初探之urllib.request

pythonrequests模块初探

python3爬虫初探

初探JSP与LEeclipse

python3爬虫初探之文件保存

Python练习册 第 0013 题: 用 Python 写一个爬图片的程序,爬 这个链接里的日本妹子图片 :-),(http://tieba.baidu.com/p/2166231880)(代码片段