zoukankan      html  css  js  c++  java
  • Python之urllib库详解

    urllib 是 Python 标准库中用于网络请求的库。

    该库有四个模块,分别是:

    urllib.request

    urllib.error

    urllib.parse

    urllib.robotparser

    1 发起请求

    模拟浏览器发起一个 HTTP 请求,我们需要用到 urllib.request 模块。urllib.request 的作用不仅仅是发起请求, 还能获取请求返回结果。发起请求,单靠 urlopen() 方法就可以叱咤风云。我们先看下 urlopen() 的 API:

    urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None,context=None)
    • data 是 bytes 类型的内容,可通过 bytes()函数转为化字节流。它也是可选参数。使用 data 参数,请求方式变成以 POST 方式提交表单。使用标准格式是application/x-www-form-urlencoded
    • timeout 参数是用于设置请求超时时间。单位是秒。
    • cafilecapath代表 CA 证书和 CA 证书的路径。如果使用HTTPS则需要用到。
    • context参数必须是ssl.SSLContext类型,用来指定SSL设置
    • 该方法也可以单独传入urllib.request.Request对象
    • 该函数返回结果是一个http.client.HTTPResponse对象。
    使用 urllib.request.urlopen() 去请求百度贴吧,并获取到它页面的源代码。
    import urllib.request
    
    url = "http://tieba.baidu.com"
    response = urllib.request.urlopen(url)
    html = response.read()         # 获取到页面的源代码
    print(html.decode('utf-8'))    # 转化为 utf-8 编码

    1.2 设置请求超时

    有些请求可能因为网络原因无法得到响应。因此,我们可以手动设置超时时间。当请求超时,我们可以采取进一步措施,例如选择直接丢弃该请求或者再请求一次。

    import urllib.request
    
    url = "http://tieba.baidu.com"
    response = urllib.request.urlopen(url, timeout=1)
    print(response.read().decode('utf-8'))

    1.3 使用 data 参数提交数据

    在请求某些网页时需要携带一些数据,我们就需要使用到 data 参数。

    import urllib.parse
    import urllib.request
    
    url = "http://www.baidu.com/"
    params = {
      'name':'TTT',
      'author':'Miracle'
    }
    
    data = bytes(urllib.parse.urlencode(params), encoding='utf8')
    response = urllib.request.urlopen(url, data=data)
    print(response.read().decode('utf-8'))

    params 需要被转码成字节流。而 params 是一个字典。我们需要使用 urllib.parse.urlencode() 将字典转化为字符串。再使用 bytes() 转为字节流。最后使用 urlopen() 发起请求,请求是模拟用 POST 方式提交表单数据。

    注意:当url地址含有中文或者“/”的时候,这是就需要用做urlencode一下编码转换。urlencode的参数是词典,它可以将key-value这样的键值对转换成我们想要的格式

    1.4 使用 Request

    由上我们知道利用 urlopen() 方法可以发起简单的请求。但这几个简单的参数并不足以构建一个完整的请求,如果请求中需要加入headers(请求头)、指定请求方式等信息,我们就可以利用更强大的Request类来构建一个请求。
    按照国际惯例,先看下 Request 的构造方法:

    urllib.request.Request(url, data=None, headers={}, origin_req_host=None,
    unverifiable=False, method=None)
    • data 参数跟 urlopen() 中的 data 参数用法相同。
    • headers 参数是指定发起的 HTTP 请求的头部信息。headers 是一个字典。它除了在 Request 中添加,还可以通过调用 Reques t实例的 add_header() 方法来添加请求头。
    • origin_req_host 参数指的是请求方的 host 名称或者 IP 地址。
    • unverifiable 表示请求是否是无法验证的,默认False。意思就是说用户没有足够权限来选择接收这个请求的结果。例如我们请求一个HTML文档中的图片,但是我们没有自动抓取图像的权限,我们就要将 unverifiable 的值设置成 True。
    • method 参数指的是发起的 HTTP 请求的方式,有 GET、POST、DELETE、PUT等
    1.4.1 简单使用 Request

    使用 Request 伪装成浏览器发起 HTTP 请求。如果不设置 headers 中的 User-Agent,默认的User-AgentPython-urllib/3.5。可能一些网站会将该请求拦截,所以需要伪装成浏览器发起请求。我使用的 User-Agent 是 Chrome 浏览器。

    #修改User-Agent为chrome的UA进行伪装
    import urllib.request
    
    url = "http://tieba.baidu.com/"
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
    }
    request = urllib.request.Request(url=url, headers=headers)
    response = urllib.request.urlopen(request)
    print(response.read().decode('utf-8'))

    1.4.2 Request 高级用法

    如果我们需要在请求中添加代理、处理请求的 Cookies,我们需要用到HandlerOpenerDirector

    1) Handler
    Handler 的中文是处理者、处理器。 Handler 能处理请求(HTTP、HTTPS、FTP等)中的各种事情。它的具体实现是这个类 urllib.request.BaseHandler。它是所有的 Handler 的基类,其提供了最基本的Handler的方法,例如default_open()、protocol_request()等。
    继承 BaseHandler 有很多个,我就列举几个比较常见的类:

    • ProxyHandler:为请求设置代理
    • HTTPCookieProcessor:处理 HTTP 请求中的 Cookies
    • HTTPDefaultErrorHandler:处理 HTTP 响应错误。
    • HTTPRedirectHandler:处理 HTTP 重定向。
    • HTTPPasswordMgr:用于管理密码,它维护了用户名密码的表。
    • HTTPBasicAuthHandler:用于登录认证,一般和 HTTPPasswordMgr 结合使用。
    2) OpenerDirector
    对于 OpenerDirector,我们可以称之为 Opener。我们之前用过 urlopen() 方法,实际上它就是 urllib 为我们提供的一个Opener。那 Opener 和 Handler 又有什么关系?opener 对象是由 build_opener(handler) 方法来创建出来 。我们需要创建自定义的 opener,就需要使用 install_opener(opener)方法。值得注意的是,install_opener 实例化会得到一个全局的 OpenerDirector 对象。

    1.5 使用代理

    我们已经了解了 opener 和 handler,接下来我们就通过示例来深入学习。第一个例子是为 HTTP 请求设置代理
    有些网站做了浏览频率限制。如果我们请求该网站频率过高。该网站会被封 IP,禁止我们的访问。所以我们需要使用代理来突破这“枷锁”。

    import urllib.request
    
    url = "http://tieba.baidu.com/"
    headers = {
        'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 Chrome/56.0.2924.87 Safari/537.36'
    }
    
    proxy_handler = urllib.request.ProxyHandler({
        'http': 'web-proxy.oa.com:8080',
        'https': 'web-proxy.oa.com:8080'
    })
    opener = urllib.request.build_opener(proxy_handler)
    urllib.request.install_opener(opener)
    
    request = urllib.request.Request(url=url, headers=headers)
    response = urllib.request.urlopen(request)
    print(response.read().decode('utf-8'))        
    1.6 认证登录

    有些网站需要携带账号和密码进行登录之后才能继续浏览网页。碰到这样的网站,我们需要用到认证登录。我们首先需要使用 HTTPPasswordMgrWithDefaultRealm() 实例化一个账号密码管理对象;然后使用 add_password() 函数添加账号和密码;接着使用 HTTPBasicAuthHandler() 得到 hander;再使用 build_opener() 获取 opener 对象;最后使用 opener 的 open() 函数发起请求。

    第二个例子是携带账号和密码请求登录博客园,代码如下:

    import urllib.request
    url = "http://cnblogs.com/xtznb/"
    user = '奇迹'
    password = 'password'
    pwdmgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
    pwdmgr.add_password(None,url,user,password)
    
    auth_handler = urllib.request.HTTPBasicAuthHandler(pwdmgr)
    opener = urllib.request.build_opener(auth_handler)
    response = opener.open(url)
    print(response.read().decode('utf-8'))
    1.7 Cookies设置

    如果请求的页面每次需要身份验证,我们可以使用 Cookies 来自动登录,免去重复登录验证的操作。获取 Cookies 需要使用 http.cookiejar.CookieJar() 实例化一个 Cookies 对象。再用 urllib.request.HTTPCookieProcessor 构建出 handler 对象。最后使用 opener 的 open() 函数即可。

    第三个例子是获取请求百度贴吧的 Cookies 并保存到文件中,代码如下:

    import http.cookiejar
    import urllib.request
    
    url = "http://tieba.baidu.com/"
    fileName = 'cookie.txt'
    
    cookie = http.cookiejar.CookieJar()
    handler = urllib.request.HTTPCookieProcessor(cookie)
    opener = urllib.request.build_opener(handler)
    response = opener.open(url)
    
    f = open(fileName,'a')
    for item in cookie:
        f.write(item.name+" = "+item.value+'
    ')
    f.close()

    1.8 HTTPResponse

    从上面的例子可知, 使用 urllib.request.urlopen() 或者 opener.open(url) 返回结果是一个 http.client.HTTPResponse 对象。它具有 msg、version、status、reason、debuglevel、closed等属性以及read()、readinto()、getheader(name)、getheaders()、fileno()等函数。

     

    2 错误解析

    发起请求难免会出现各种异常,我们需要对异常进行处理,这样会使得程序比较人性化。
    异常处理主要用到两个类,urllib.error.URLErrorurllib.error.HTTPError

    • URLError
      URLError 是 urllib.error 异常类的基类, 可以捕获由urllib.request 产生的异常。
      它具有一个属性reason,即返回错误的原因。

    捕获 URL 异常的示例代码:

    import urllib.request
    import urllib.error
    
    url = "http://www.google.com"
    try:
        response = request.urlopen(url)
    except error.URLError as e:
        print(e.reason)
    • HTTPError HTTPError 是 UEKRrror 的子类,专门处理 HTTP 和 HTTPS 请求的错误。它具有三个属性。

      1)code:HTTP 请求返回的状态码。

      2)reason:与父类用法一样,表示返回错误的原因。

      3)headers`:HTTP 请求返回的响应头信息。

    获取 HTTP 异常的示例代码, 输出了错误状态码、错误原因、服务器响应头

    import urllib.request
    import urllib.error
    
    url = "http://www.google.com"
    try:
        response = request.urlopen(url)
    except error.HTTPError as e:
       print('code: ' + e.code + '
    ')
       print('reason: ' + e.reason + '
    ')
       print('headers: ' + e.headers + '
    ')

     2.urllib.response 

    (在使用urlopen()方法或者opener的open()方法发起请求后,获得的结果是一个response对象。这个对象有一些方法和属性,可以让我们对请求返回的结果进行一些处理。)

    geturl()  : 返回获取的真实的URL,这个很有用,因为 urlopen(或者 opener 对象使用的)或许会有重定向。获取的 URL 或许跟请求 URL 不同。

    info() : 这个返回对象的字典对象,该字典描述了获取的页面情况。通常是服务器发送的特定头 headers。

    read():获取响应返回的数据,只能使用一次。

    getcode():获取服务器返回的状态码。

    getheaders():获取返回响应的响应报头。

    3.urllib.parse
    (urllib.parse是urllib中用来解析各种数据格式的模块)

    1. urllib.parse.quote
    在url中,是只能使用ASCII中包含的字符的,也就是说,ASCII不包含的特殊字符,以及中文等字符都是不可以在url中使用的。而我们有时候又有将中文字符加入到url中的需求,例如百度的搜索地址:https://www.baidu.com/s?wd=南北。?之后的wd参数,则是我们搜索的关键词。那么我们实现的方法就是将特殊字符进行url编码,转换成可以url可以传输的格式,urllib中可以使用quote()方法来实现这个功能。

    from urllib import parse
    keyword = '南北'
    parse.quote(keyword)
    =======>>'%E5%8D%97%E5%8C%97'
    
    #如果需要将编码后的数据转换回来,可以使用unquote()方法。
    parse.unquote('%E5%8D%97%E5%8C%97')
    =======>>'南北'

    2. urllib.parse.urlencode

    在访问url时,我们常常需要传递很多的url参数,而如果用字符串的方法去拼接url的话,会比较麻烦,所以urllib中提供了urlencode这个方法来拼接url参数。

    from urllib import parse 
    params = {'wd': '南北', 'code': '1', 'height': '188'}  
    parse.urlencode(params)
     
    =======>>'wd=%E5%8D%97%E5%8C%97&code=1&height=188'

    4.urllib.error

    在urllib中主要设置了两个异常,一个是URLError,一个是HTTPErrorHTTPErrorURLError的子类。

    HTTPError还包含了三个属性:

    • code:请求的状态码
    • reason:错误的原因
    • headers:响应的报头
    from urllib.error import HTTPError 
    try:
        request.urlopen('https://www.jianshu.com') 
    except HTTPError as e:
        print(e.code)
    
    403

    一个使用代理的例子:

    proxy_handler = urllib.request.ProxyHandler({'http':
    'http://www.example.com:3128/'})
    proxy_auth_handler = urllib.request.ProxyBasicAuth()
    proxy_auth_handler.add_password('realm', 'host', 'username', 'password')
    
    opener = urllib.request.build_opener(proxy_handler, proxy_auth_handler)
    opener.open('http://www.example.com/login.html')

    添加HTTP请求头部:

    import urllib.request
    req = urllib.request.Request('http://www.example.com/')
    req.add_header('Referer', 'http://www.python.org/')
    r = urllib.request.urlopen(req)

    更改User-agent:

    import urllib.request
    opener = urllib.request.build_opener()
    opener.addheaders = [('User-agent', 'Mozilla/5.0')]
    opener.open('http://www.example.com/')

    三、Python3.X中使用整合后的urllib

    Python2.x 有这些库名可用: urllib,urllib2,urllib3,httplib,httplib2,requestsPython3.x 有这些库名可用: urllib,urllib3,httplib2,requests

    若只使用Python3.x,记住有个urllib的库就行了。Pyhton2.x和Python3.x都有urllib3和requests, 它们不是标准库。urllib3提供线程安全连接池和文件post等支持,与urllib及urllib2的关系不大。requests 自称HTTP for Humans,使用更简洁方便。

    Python3.x中将urllib2合并到了urllib,之后此包分成了以下几个模块:

        urllib.request 用于打开和读取URL

        urllib.error 用于处理前面request引起的异常

        urllib.parse 用于解析URL

        urllib.robotparser用于解析robots.txt文件

    Python3.x中,随着urllib2合入urllib,一些常用的方法也发生了变化:2

        在Python2.x中使用import urlparse——在Python3.x中会使用import urllib.parse

        在Python2.x中使用urllib2.urlopen或urllib.urlopen(已弃用)——在Python3.x中会使用urllib.request.urlopen

        在Python2.x中使用urllib2.Request——在Python3.x中会使用urllib.request.Request

        在Python2.x中使用urllib.quote——在Python3.x中会使用urllib.request.quote

        在Python2.x中使用urllib.urlencode——在Python3.x中会使用urllib.parse.urlencode

        在Python2.x中使用cookielib.CookieJar——在Python3.x中会使用http.CookieJar

        异常处理:在Python2.x中使用urllib2.URLError,urllib2.HTTPError——在Python3.x中会使用urllib.error.URLError,urllib.error.HTTPError

    注:在Python3.3后urllib2已经不能再用,所有urllib2全部用urllib.request来代替。

    PUT一个请求:

    import urllib.request 
    DATA=b'some data' 
    req = urllib.request.Request(url='http://localhost:8080', data=DATA, method='PUT') 
    with urllib.request.urlopen(req) as f: 
        pass 
    print(f.status) 
    print(f.reason)

    基本的HTTP认证:

    import urllib.request 
    
    auth_handler = urllib.request.HTTPBasicAuthHandler() 
    auth_handler.add_password(realm='PDQ Application', uri='https://mahler:8092/site-updates.py', user='klem', passwd='kadidd!ehopper') opener = urllib.request.build_opener(auth_handler)
    urllib.request.install_opener(opener)
    urllib.request.urlopen('http://www.example.com/login.html')

    指定proxy:

    import urllib.request 
    proxies = {'http': 'http://proxy.example.com:8080/'} 
    opener = urllib.request.FancyURLopener(proxies)
    with opener.open("http://www.python.org") as f: 
      f.read().decode('utf-8')

    不使用proxy, 覆盖环境变量的proxy:

    import urllib.request
    opener = urllib.request.FancyURLopener({}) 
    with opener.open("http://www.python.org/") as f:
        f.read().decode('utf-8')
  • 相关阅读:
    如何基于Azure平台实现MySQL HA(方法论篇)
    如何对Azure磁盘性能进行测试
    Azure底层架构的初步分析
    聊聊Azure的安全性
    关于Azure带宽的测试
    JavaScript 优化
    SQL时间段查询
    win7+64位+Oracle+11g+64位下使用PLSQL+Developer+的解决办法
    putty 使用方法,中文教程
    怎样才能专心工作
  • 原文地址:https://www.cnblogs.com/xtznb/p/10960396.html
Copyright © 2011-2022 走看看