初见 urllib 库

Python3 将 urllib 和 urllib2 统一为 urllib 库,来实现 HTTP 请求的发送。他包含了 4 个模块:requesterrorparserobotparse

request:最基本的 HTTP 请求模块,用来模拟发送 HTTP 请求。

error:处理 HTTP 请求错误,用来捕获请求错误异常信息。

parse:URL 处理的工具模块。

robotparse:识别网站的 robot.txt 文件,判断哪些网站可以爬哪些网站不能爬。

urllib.request 模块提供了发送请求的方法

urlopen() 

 

urlopen() API:

urlopen(url,data=None,[timeout,]*,cafile=None,capath=None,cadefault=False,context=None) 

其中 url 参数是必须的,表示请求的 url 。

data:可选,如果使用了这个参数,请求方式就不再是 GET 方式,而变成了 POST 请求,但是网络中传输的都是字节流数据,因此首先要用 bytes() 方法将该参数的数据转换成 bytes 类型。

timeout:可选,设置请求的超时时间,单位秒,超时就会抛出 urllib.error.URLError 异常。省略就使用全局默认时间,支持 HTTP,HTTPS,FTP 请求。

cafilecapath 用来指定 CA 文件和 CA 文件的路径。

 import urllib.parse    #导入 urllin 的 parse 模块
 import urllib.request  #导入 urllin 的 request 模块

 data = bytes(urllib.parse.urlencode({'name':'Tom'}),encoding='utf-8')
 response = urllib.request.urlopen('http://httpbin.org/post',data=data)
 print(response.read())

最终输出的结果为

bytes() 方法将参数转化为字节流(bytes),第一个参数要是 str 类型,第二个参数指定编码格式(utf-8)。使用 urllib.parse.urlencode() 方法将字典转化为 str 类型。可以看到,POST 请求的参数存到了 form 字段中。

Request()

 

上面是基本的的 urlopen() 方法的使用,如果要在请求中加入 Headers 信息,就需要利用更强大的 Request 类来构建。利用 Request 类可以构建单独的请求对象,之后将各个请求对象加入到队列中,要发出请求就从队列中依次取出请求对象,就可以很方便地处理请求。

request API:

class Request(url,data=None,headers={},origin_req_host=None,unverifiable=False,method=None)

url :必需参数,表示的是请求 URL,其他都是可选参数。

data:和 urlopen() 方法中的 data 参数一样,且同样要转换为 bytes 类型。

headers:字典形式添加请求头信息,可以在构造 Request 请求对象的时候添加,也可以用请求对象的 add_header() 添加。请求头信息一般设置的就是 用户代理 User-Agent 用来伪装浏览器。

origin_req_host:请求方的 host 名称或者 IP 地址。

 from urllib import parse,request

 url = 'http://httpbin.org/post'
 headers = {
     'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) 
 Chrome/63.0.3239.132 Safari/537.36',
     'Host':'httbin.org'
 }
 data = {'name':'Tom'}

 data = bytes(parse.urlencode(data),encoding = 'utf-8')
 req = request.Request(url,data = data,headers = headers,method = 'POST')
 respon = request.urlopen(req)
 print(respon.read())

运行结果如下

先构造 Request 请求对象,再将请求对象作为 urlopen() 的参数发出请求。可以看到,data 信息存在了 form 字段中,Headers 信息存在了 headers 字段中,并且修改了请求头中的 UA 和 host 信息。

也可以使用 req.add('User-Agent','UA信息') 的方式添加请求头中的信息。

Handler 和 Opener

 

上面通过构造 Request 对象发出请求可以很方便的添加 Headers 信息,但是有时会要添加 Cookies 或者要处理用户验证(输入用户密码)等问题,就需要更高级的 Handler 和 Opener 了。

Handler 可以理解为专门处理某种类型问题的处理器,比如处理 Cookies 的,处理登录验证的,处理代理的处理器等。Opener 可以认为是由某种处理器创建的打开器,由于是由处理某种问题的处理器创建的打开器,这种打开器就可以解决这种问题,Opener 可以使用 open() 方法,返回的类型和 urlopen() 是一样的。urlopen() 实际就是 urllib 为我们提供的一个 Opener。

Handler 的基类是 urllib.request.BaseHandler 类,其他各种 Handler 继承这个基类,一些常见的 handler 有:

HTTPCookieProcessor:用于处理 Cookies 。

ProxyHandler:用于设置代理。

HTTPPasswordMgr:用于处理用户登录的用户名和密码。

HTTPBasicAuthHandler:用于管理认证,如果打开某个链接需要认证,就是用这个 Handler。

更多的 Handler 可以参考

 https://docs.python.org/3/library/urllib.request.html#urllib.request.BaseHandler

如果打开一个连接提示需要输入用户名和密码,就可以使用 HTTPBasicAuthHandler 来完成验证。

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

 username = 'username'
 password = 'pwd'
 url = 'http://localhost:8000'

 p = HTTPPasswordMgrWithDefaultRealm() # 创建处理验证的实例,存放验证需要的用户名,密码等信息
 p.add_password(None,url,username,password)
 auth_handler = HTTPBasicAuthHandler(p) # 用带有请求参数(用户名,密码,url的)处理验证实例构建 Handler
 opener = build_opener(auth_handler) # 通过 build_opener() 方法传入 Handler 对象构建来 opener 对象

 try:
     result = opener.open(url)  # 使用 opener 的 open() 方法请求 url
     html = result.read().decode('utf-8')
     print(html) 
 except URLError as e:
     print(e.reason)  # 打印错误信息

HTTPBasicAuthHandler 的参数是 HTTPPasswordMgrWithDefaultRealm 对象,这个对象中包含了用于处理验证的用户名,密码等信息,通过传给专门用于处理验证的 Handler 类 HTTPPasswordMgrWithDefaultRealm 构建出了处理验证的 Handler 对象,利用 Handler 对象来构建 Opener。由此可以知道,使用 Handler 和 Opener 利用处理器来处理比较复杂的问题的一般方法为:

通过给 Handler 类传入参数构造 Handler 对象,再通过 build_opener() 方法利用 Handler 对象来实例化 Opener 对象,这样的 Opener 对象就已经可以处理(或者说已经处理了)相应的问题,最后就可以利用 Opener 对象的 open() 方法去请求目标 url 了。

同样的,如果要使用代理,添加代理信息,就需要使用代理相关的 Handler,给它传入代理参数,构造 Handler 对象。

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

 p_handler = ProxyHandler({
     'http':'http://127.0.0.1:8800',
     'https':'http://127.0.0.1:8800',
 })
 opener = build_opener(p_handler)

 html = opener.open('https://www.baidu.com')
 print(html.read().decode('utf-8'))

处理 Cookies 问题就需要使用 Cookies 相关的 Handler 类也就是 HTTPCookieProcesser

 from urllib.request import HTTPCookieProcessor
 from http.cookiejar import CookieJar

 cookie = CookieJar()  # 构造 CookieJar 的实例
 cookie_handler = HTTPCookieProcessor(cookie) # 通过 CookieJar 对象构造处理 cookies 的 Handler
 opener = build_opener(cookie_handler)

 response = opener.open('http://www.baidu.com') # 打开 url 后就会获得服务器返回的 cookies 并保存在对象 cookie 中
 for item in cookie: 
     print(item.name,item.value)

如果要将获得的 cookies 保存到本地,就需要使用 CookieJar 的子类 MozillaCookieJar,用来处理 cookies 和文件相关的事件,包括 cookie 的保存和读取。这是将 cookies 保存为 Mozilla 型浏览器的格式。

 filename = 'cookies.txt'
 cookie = http.cookiejar.CookieJar(filename)
 cookie_handler = urllib.request.HTTPCookieProcessor(cookie)
 handler = build_opener(cookie_handler)
 resp = handler.open('http://www.baidu.com') # 访问 url 后获得服务器返回的 Cookies 并保存在 cookie 对象中
 cookie.save() # 通过 cookie 这个对象调用 save() 方法将其中的 Cookies 保存到本地,路径名之前已经声明

另外,LWPCookieJar 同样可以保存 Cookies,但是格式和 MozillaCookieJar 不一样。

本地 Cookies 的读取要用到 cookie 对象的 load() 方法,因此首先要有 cookie 对象。

 cookie = http.cookiejar.LWPCookieJar()
 cookie.load('cookie.txt')
 handler = urllib.request.HTTPCookieProcessor(cookie)
 opener = urllib.request.build_opener(handler)
 resp = opener.open('http://www.baidu.com')
 print(resp.read().decode('utf-8'))

处理异常

 

urllib 的 error 模块定义了 request 模块产生的异常。

URLError 类是 error 模块的基类,由 request 模块产生的异常都可以通过捕获这个类来处理。通过 reason 属性可以打印异常信息。HTTPError 类是 URLError 类的子类,用于处理 HTTP 请求错误,他有三个属性:codereasonheaders 分别打印 错误码错误原因(和父类 reason 相同)以及请求头。捕获异常时,一般是先捕获子类异常,再捕获父类异常。

这里值得注意的是:reason 属性有时候返回的是字符串(Not Found...),有时候返回的是一个对象(超时返回 socket.timeout 类的对象),可以使用 isinstance(A,B) 方法判断 A 是否是 B 类型。

连接解析

 

urllib 的 parse 模块提供了很多连接解析的方法,包括链接各部分的 抽取,合并,链接转换等,更多的连接解析方法可以参考 urllib 官网的 parse 模块:

https://docs.python.org/3/library/urllib.parse.html

Robots 协议

 

urllib 的 robotsparse 模块可以对网站的 Robots 协议进行分析。这个协议主要就是告诉爬虫和搜索引擎哪些页面可以爬取哪些页面不能爬,一般放在网站的根目录下,他通过定义 User-AgentAllowDisallow 字段来规定了爬取的规则。当然也有的网站没有 Robots 协议,这部分用的不多,没怎么去研究~~~





评论

  1. #1

    dUoxKpta 2019-09-06 01:15:04
    dUoxKpta

  2. #2

    WEmXeAbt 2019-09-05 22:19:21
    WEmXeAbt

  3. #3

    zuLdJdBo 2019-09-05 19:42:00
    zuLdJdBo