urllib的使用


前言

这是python自带的爬虫相关模块,但市面上有更好的BeautifulSoup模块和requests模块.如果是速成爬虫直接学习那两个模块用法即可,但requests模块是使用urllib搭建而成,如果时间不急,可以从底层看起.

urllib的使用

基本模块:

  • request:HTTP请求模块
  • error:异常处理模块
  • parse:工具模块,提供url处理方法
  • robotparser:识别网站的robot.txt文件

    requset模块

    urlopen

    import urllib.requset
    
    response = urlib.request.urlopen(url,data=None,[timeout,]*,cafile=None,capath=None,cadefault=False,context=None)
    参数解释
  • url: 网页地址
  • data: bytes类型的字节流编码

    data = bytes(urllib.parse.urlencode({'username':'admin'}),encoding = "utf-8")

  • timeout:超时时间设置,单位秒.
  • 其他参数:

    context:接受ssl.SSLContext类,用来设置SSL

    cafile/capath:设置CA证书和其路径,请求https链接有用

    cadefault:已经弃用

Request

import urllib.request
request = urllib.request.Request(url)
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))

Request使用Request对象传给urlopen,可读性更高,封装更好.

Request构造

request = urllib.request.Request(url,data=None,headers={},origin_req_host=None,unverifiable=False,method=None)
  • url:同urlopen
  • data:同urlopen
  • headers:传一个字典参数,作为请求头
  • origin_req_host:请求方的host名称或者IP地址
  • unverifiable:表示请求是否是无法验证的,默认为False,表示用户没有足够的权限来接受这个请求的结果
  • method:字符串参数,表示请求方法,如GET,POST,PUT,DELETE

    高级用法

    request的高级用法依托Handler实现.
    首先是所有Handler的父类BaseHandler,其提供了基本方法,如default_open,protocol_request等
    其几个子类如下
    • HTTPDefaultErrorHandler:用于处理HTTP响应错误,所有错误都会抛出HTTPError类型的异常
    • HTTPRedirectHandler:用于处理重定向
    • HTTPCookieProcessor:用于处理Cookie
    • ProxyHandler:用于设置代理,代理默认为空
    • HTTPPasswordMgr:用于密码管理,维护者用户名密码对照表
    • HTTPBasicAuthHandler:用于管理认证,如果一个链接在打开的时候需要认证,那么可以用这个解决认证问题.

另外一个比较重要的类是OpenerDirector,简称Opener.之前的urlopen方法就是一个Opener.Request类和urlopen类都是已经封装好的常用请求方法,如果需要高级用法则需要使用更加底层的实例来完成操作.

Opener类提供Open方法,该方法的返回的响应类型和urlopen方法一致.Opener类需要使用Handler类来构建.

验证

在访问一些服务器的时候,有些网页需要用户输入账号密码进行身份验证.这就是HTTP Basic Access Authentication.

爬虫借助HTTPBasicAuthHandler模块就能完成身份验证.

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

username = 'admin'
password = 'password'
url = ''

p = HTTPPasswordMgrWithDefaultRealm() 
p.addpassword(None,url,username,password) ##这个类是构建 用户名和密码 对一个地址的映射,这个映射可以是 url 也可以是 proxy 
auth_handler = HTTPBasicAuthHandler(p) ## HTTPBasicAuthHandler的构造方法需要提供一个HTTPPasswordMgr(密码管理 Password Management Object) 对象 如果不知道域/对域不需要关心,就使用 HTTPPasswordMgrwithDefaultRealm 对象,使用None作为构造参数,知道的话就使用realm代替None 
opener = build_opener(auth_handler) ## 构建了一个opener,可以使用这个opener去open url.如果这个opener是 网页验证,那么就是open url,如果是 代理验证,那么访问的时候,就是使用代理ip帮你访问(相当于Request封装再更底层)

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

代理

代理的逻辑同验证一样,先使用ProxyHandler建立代理,再使用build_opener方法建立opener,再使用这个opener打开你需要的web

from urllib.requset import ProxyHandler, build_opener, 
from urllib.error import URLError
proxy_Handler = ProxyHandler({'http':'http://',
                             'https':'https://'}) ## ProxyHandler类的构造需要一个字典
opener = build_opener(proxy_Handler)
try:
    response = opener.open(url)
    print(response.read().decode('utf-8'))
except URLError as e:
    print(e.reason)

但是如果碰到了代理验证的话,那么还是需要使用HTTPBasicAuthHandler

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

username = 'admin'
password = 'password'
proxyserver = "61.158.163.130:16816" // 此时代理地址直接使用IP地址的字符串
url = ''

p = HTTPPasswordMgrWithDefaultRealm() 
p.addpassword(None,proxyserver,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)

获取网站的Cookie,就是根据网站的响应头里面的 Set_Cookie的值来设置Cookie.

思路是构建CookieJar对象,再用这个对象创建opener,用这个opener打开网站,其响应的cookie会自动给CookieJar对象,通过直接访问CookieJar对象来获得Cookie.

from urlib.request import HTTPCookieProcessor,build_opener
from http.cookiejar import CookieJar

cookie = CookieJar()
handler = HTTPCookieProcessor(cookie)
opener = build_opener(handler)
response = opener.open(url)
for items in cookie:
    print(item.name + ':' + item.value)

如果需要保存cookie的话,那么需要使用MozillaCookieJar.它是CookieJar的子类,专门用于处理Cookie,比如Cookie的读取和保存,其将Cookie保存为Mozilla浏览器类型的Cookie,也就是在请求头中看到的格式.

from urlib.request import HTTPCookieProcessor,build_opener
from http.cookiejar import MozillaCookieJar

filename = 'cookie.txt'
cookie = MozillaCookieJar(filename)
handler = HTTPCookieProcessor(cookie)
opener = build_opener(handler)
response = opener.open(url)
cookie.save(ignore_discard = True,ignore_expires = True) ## ignore_discard 及时被弃用也将其保存下来,ignore_expires 及时已经过期也将其保存

同样的,如果是LWP(libwww-perl)格式,则使用

cookie = LWPCookieJar(filename)

那么,如何读取利用cookie?.下面是代码

from urllib.request import HTTPCookieProcessor,build_opener
from http.cookiejar import MozillaCookieJar

cookie = CookieJar()
cookie.load("cookie.txt",ignore_discard = True,ignore_expires = True)
handler = HTTPCookieProcessor(cookie)
opener = build_opener(handler)
response = opener.open(url)
print(response.read().decode('utf-8'))

异常处理

urllib.error定义了urllib.request库产生的异常

URLError

URLError来自urllib.error库,继承于OSError,是urllib.error异常模块的基类.它具有一个reason属性,返回错误原因.

import urllib.error

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

HTTPError

HTTPErrorURLError的子类,专门用来处理HTTP请求错误,例如认证请求失败.

import urllib.error

try:
    result = opener.open(url)
    html = result.read().decode('utf-8')
    print(html)
except HTTPError as e:
    print(e.reason,e.code,e.headers)
except URLError as e: ##如果不是HTTPError,则进入URLError捕获
    print(e.reason)

解析链接

urllib.parse块定义了处理URL的标准接口,例如实现URL各部分的抽取,合并已经连接转换.

urlparse

该方法实现URL的识别和分段

from urllib.parse import urlparse

result = urlparse('https://www.baidu.com/index.html;user?id=5#commemt')
print(type(result)) ##<class 'urllib.parse.ParseResult'>,是一个元组,可以使用索引或者序列号访问其中的元素
print(result) ## scheme,netloc,path,params,query fragment

可得标准链接格式:

scheme://netloc/path;params?query#fragment

urlparse含有三个参数,下面是解释

  • urlstring:待解析的url
  • scheme:默认的协议,如果url没有提供协议则会用这个代替
  • allow_fragment:是否忽略fragment

urlunparse

此方法用于构造url.参数必须是一个可迭代对象,长度必须为6,否则会抛出异常.

from urllib.parse import urlunparse

string = ["https","www.baidu.com","index.html","user","id=5","commemt"]

urlsplit

urlparse类似,只不过params不会单独出现,划分为path的一部分,返回结果是SplitResult,和ParseResult类似,既能索引,也可以序列访问.

urlunsplit

urlunparse类似,使用长度为5的可迭代对象.

urljoin

该方法需要两个参数,一个是base_url,一个是待修改的链接.该方法会分析base_url中的scheme,netlocpath.如果待修改的链接不含这三个部分中的一个,则补充上去.

urlencode

这个方法在GET方法中特别实用

from urllib.parse import urlencode

query = {
    'tn':'monline_3_dg',
    'ie':'utf-8',
    'wd':'python'
}

base_url = 'https://www.baidu.com?'
url = base_url + urlencode(query)
print(url) ## https://www.baidu.com?tn=monline_3_dg&ie=utf-8&wd=python

其作用就是把字典参数链接在url后面

parse_qs

反序列化方法,将query参数返回为字典

from urllib.parse import parse_qs

query = "tn=monline_3_dg&ie=utf-8&wd=python"
print(parse_qs(query)) ## query = {
                       ##    'tn':'monline_3_dg',
                       ##    'ie':'utf-8',
                       ##    'wd':'python'
                       ## } 

parse_qsl

将参数转化为元组组成的列表

from urllib.parse import parse_qsl

query = "tn=monline_3_dg&ie=utf-8&wd=python"
print(parse_qsl(query)) ## [('tn','monline_3_dg'),('ie','utf-8'),('wd','python')]

quote

将内容转化为URL编码格式.如果URL有中文参数,有可能乱码,所以需要quote将其转化为 URL编码

from url.parse import quote

keyword = "爬虫"
url = 'https://www.baidu.com/s?wd=' + quote(keyword)
print(url)

unquote

URL编码转成中文

分析Robot协议

Robot协议也叫机器人协议,全名网络爬虫排除标准(Robot Exclusion Protocal),用来告诉爬虫那些网页可以抓取,那些不行.通常命名为robot.txt,放在网站根目录.

爬虫在实际爬取时,会先检查是否存在’robot.txt’,如果有则遵从,没有的话就随意爬取.
下面是一个robot.txt的实例

User-Agent: * /对所有爬虫生效
Disallow: / #不允许爬取任何页面
Allow: /public/ #只能爬取public

robotparser

这个模块用于解析robot.txt文件,来判断是由有权利爬取这个网页.

urllib.robotparser.RobotFileParser(url = '') ## 可以不设置url,之后用set_url添加

以下是RobotFileParset常用方法

  • set_url:设置robot.txt文件链接.
  • read:读取文件并进行分析.这个方法包含读取和分析,所以一定要使用.
  • parse:解析文件,传入其中的参数是文件中某些行的内容.
  • can_fetch:需要两个参数,一个是User-Agent,一个是URL.判断是否能爬取.
  • mtime:返回上次抓取分析文件的时间,如果长时间爬取的话就需要获取最新的robot.txt文件来判断自己爬取的合法性.
  • modified:将当前时间设置为上次抓取分析文件的时间,在长时间爬取中很有用.

总结

这一节主要是urllib的使用,使用略显复杂,后面的requesets模块更加方便,但是对于自定义爬虫这很有用.
爬取逻辑分析:
判断是否需要验证和代理 -> 根据情况建立HTTPBasicAuthHandler(PasswordMgrWithDefaultRealm)或者ProxyHandler(字典) -> 根据Handler建立opener -> 爬取网页,同时记得捕获异常,根据异常修改爬虫. ->如果需要修改cookie,使用HTTPCookieProcessor(CookieJar类).


Author: Dovahkiin
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source Dovahkiin !
  TOC