• 八、urllib库的基本使用


    1、基本使用

      所谓网页抓取,就是把url地址中指定的网络资源从网络流中读取出来,保存到本地。

    2、urlopen

      urlopen的参数是一个url地址时

    # 导入urllib.rquest库
    from urllib import request
    
    # 向指定的url发送请求,并返回服务器响应的类文件对象
    response = request.urlopen("https://www.baidu.com")
    
    # 类文件对象支持文件对象的操作方法,如read()方法读取文件全部内容,返回字符串
    html = response.read()
    
    print(html)

    3、Request

      当增加http报头时,必须创建一个Request实例来作为urlopen()的参数,而需要访问的url地址则作为Request实例的参数。

    from urllib import request
    
    # url作为Request()方法的参数,构造并返回一个Request对象
    request_=request.Request("http://www.baidu.com")
    
    # Request对象作为urlopen()方法的参数,发送给服务器并接受响应
    response=request.urlopen(request_)
    
    # 返回类文件对象
    html = response.read().decode()
    
    print(html)

      新建Request实例,除了必须要有url参数之外,还可以设置在另外两个参数:

      (1)data(默认空):是伴随url提交的数据(比如要通过post提交的数据),同时http请求将从get方式改为post方式。

      (2)headers(默认空):是一个字典,包含了需要发送的http报头的键值对。

    4、User-Agent

      浏览器是互联网世界上公认被允许访问网页的身份,如果我们希望我们的爬虫程序更像一个真实用户,那我们第一步,就是需要伪装成一个被公认的浏览器。用不同的浏览器在发送请求的时候,会有不同的User-Agent头。 urllib默认的User-Agent头为:Python-urllib/x.y(x和y是Python主版本和次版本号,例如 Python-urllib/2.7)。

    from urllib import request
    
    url = "https://www.baidu.com"
    
    headers = {
          "User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36",
    }
    
    # url连同headers,一起构造Request请求,这个请求将附带浏览器的user-agent
    request_ = request.Request(url,headers=headers)
    
    # 向服务器发送这个请求
    response = request.urlopen(request_)
    
    html = response.read()
    print(html)

    5、添加更多的Header信息

      在HTTP Request中加入特定的Header,来构造一个完整的HTTP请求消息。

      5.1 添加一个特定的header

    from urllib import request
    
    headers = {
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36",
    }
    
    url = "https://www.baidu.com"
    
    request_ = request.Request(url,headers=headers)
    
    # 可以通过调用Request.add_header()添加/修改一个特定的header
    request_.add_header("Connection","keep-alive")
    
    # 可以通过Request.get_header()来查看header信息
    ret = request_.get_header(header_name="Connection")
    # print(ret)    --->>>>>>  keep-alive
    
    response = request.urlopen(request_)
    
    print(response.code) # 可以查看响应状态码
    
    html = response.read().decode()
    
    print(html)

      5.2 随机添加/修改User-Agent

        User-Agent大全:http://useragentstring.com/pages/useragentstring.php

    from urllib import request
    import random
    
    url = "https://www.baidu.com"
    
    # http://useragentstring.com/pages/useragentstring.php
    ua_list = [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
        "Mozilla/5.0 (X11; Ubuntu; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2919.83 Safari/537.36",
        "Mozilla/5.0 (X11; Ubuntu; Linux i686 on x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2820.59 Safari/537.36",
    ]
    
    user_agent = random.choice(ua_list)
    
    request_ = request.Request(url)
    
    # 通过Request.add_header()添加/修改一个特定的header
    request_.add_header("User-Agent",user_agent)
    
    # get_header()的字符串参数,第一个字母大写,后面的全部小写
    ret = request_.get_header("User-agent")
    print(ret)
    
    response = request.urlopen(request_)
    
    print(response.read().decode())

    6、urllib默认只支持HTTP/HTTPS的GET和POST方法

      6.1 urllib.parse.urlencode()

        编码工作使用urllib.parse的urlencode()函数,帮我们将key:value这样的键值对转换成"key=value"这样的字符串,解码工作可以使用urllib.parse的unquote()函数。

    from urllib import request,parse
    
    word = {
        "wd":"人生"
    }
    
    # 通过urllib.urlencode()方法,将字典键值对按url编码转换,从而能被web服务器接受
    
    ret = parse.urlencode(word)
    
    print(ret)
    # wd=%E4%BA%BA%E7%94%9F
    
    # 通过parse.unquote()方法,把url编码字符串,转换回原先字符串
    ret_ = parse.unquote(ret)
    
    print(ret_) 
    # wd=人生

        一般HTTP请求提交数据,需要编码成url编码格式,然后作为url的一部分,或者作为参数传到Request对象中。

      6.2 GET方式

        GET请求一般用于我们向服务器获取数据,比如用百度搜索关键字

    from urllib import request,parse
    
    url = "https://www.baidu.com/s?{}"
    
    word = {
        "wd":"学习"
    }
    
    word_ = parse.urlencode(word) # 转换成url编码格式(字符串)
    
    new_url = url.format(word_)
    print(new_url)
    
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
    }
    
    request_ = request.Request(new_url,headers=headers)
    
    response = request.urlopen(request_)
    
    print(response.read())

      6.3 POST方式

        data是一个字典,里面是匹配的键值对。

        发送POST请求时,需要特别注headers的一些属性:

        (1)Content-Length: 144: 是指发送的表单数据长度为144,也就是字符个数是144个。

        (2)Content-Type: application/x-www-form-urlencoded : 表示浏览器提交 Web 表单时使用,表单数据会按照 name1=value1&name2=value2 键值对形式进行编码。

        (3)X-Requested-With: XMLHttpRequest :表示Ajax异步请求。

      6.4 获取AJAX加载的内容

        有些网页内容使用AJAX加载,这种数据无法直接对网页url进行提取。  

        但是AJAX一般返回的是JSON,只要对AJAX地址进行POST或GET,就能返回JSON数据。

        (1)GET方式是直接以链接形式访问,链接中包含了所有的参数,服务器端用Request.QueryString获取变量的值。如果包含了密码的话是一种不安全的选择,不过你可以直观地看到自己提交了什么内容。

        (2)POST则不会在网址上显示所有的参数,服务器端用Request.Form获取提交的数据,在Form提交的时候。但是HTML代码里如果不指定 method 属性,则默认为GET请求,Form中提交的数据将会附加在url之后,以?分开与url分开。

      6.5 处理HTTPS请求SSL证书验证

        遇到`URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)>`,需要单独处理SSL证书,让程序忽略SSL整数验证错误,即可正常访问。

    import urllib
    # 1. 导入Python SSL处理模块
    import ssl
    
    # 2. 表示忽略未经核实的SSL证书认证
    context = ssl._create_unverified_context()
    
    url = "..."
    
    headers = {...}
    
    request = urllib.request.Request(url, headers = headers)
    
    # 3. 在urlopen()方法里 指明添加 context 参数
    response = urllib.request.urlopen(request, context = context)
    
    print (response.read().decode())

      6.6 关于CA

        CA(Certificate Authority)是数字证书认证中心的简称,是指发放、管理、废除数字证书的受信任的第三方机构,如北京数字认证股份有限公司上海市数字证书认证中心有限公司等...

        CA的作用是检查证书持有者身份的合法性,并签发证书,以防证书被伪造或篡改,以及对证书和密钥进行管理。

    7、Handler处理器和自定义opener

      (1)opener是urllib.request.OpenerDirector的实例,urlopen是一个特殊的opener(模块帮我们构建好的)

      (2)基本的urlopen()方法不支持代理、cookie等其他的HTTP/HTTPS高级功能。如果要支持这些功能,则需要做以下步骤:

        1)使用相关的`Handler处理器`,来创建特定功能的处理器对象

        2)通过`urllib.request.build_opener()`方法使用这些处理器对象,创建自定义`opener`对象

        3)使用自定义的`opener`对象,调用`open()`方法发送请求

      (3)如果程序里所有的请求都使用自定义的opener,可以使用`urllib.request.install_opener()`将自定义的`opener`对象定义为全局`opener`,表示如果之后凡是调用urlopen,都将使用这个`opener`。

      7.1 简单的自定义opener()

    from urllib import request
    
    # 构建一个HTTPHandler处理器对象,支持处理HTTP请求
    http_handler = request.HTTPHandler()
    
    # 构建一个HTTPSHandler处理器对象,支持处理HTTPS请求
    #https_handler = request.HTTPSHandler()
    
    # 调用urllib.request.build_opener()方法,创建支持处理HTTP请求的opener对象
    opener = request.build_opener(http_handler)
    
    # 构建Request请求
    request_ = request.Request('https://www.baidu.com')
    
    # 调用自定义opener对象的open()方法,发送request请求
    response = opener.open(request_)
    
    # 获取服务器响应内容
    print(response.read().decode())

        这种方式发送请求得到的结果,和使用urllib.request.urlopen()发送HTTP/HTTPS请求得到的结果是一样的。

        如果在 HTTPHandler()增加 debuglevel=1参数,还会将 Debug Log 打开,这样程序在执行的时候,会把收包和发包的报头在屏幕上自动打印出来,方便调试,有时可以省去抓包的工作。    

    # 仅需要修改的代码部分:
    
    # 构建一个HTTPHandler 处理器对象,支持处理HTTP请求,同时开启Debug Log,debuglevel 值默认 0
    http_handler = urllib.request.HTTPHandler(debuglevel=1)
    
    # 构建一个HTTPSHandler 处理器对象,支持处理HTTPS请求,同时开启Debug Log,debuglevel 值默认 0
    https_handler = urllib.request.HTTPSHandler(debuglevel=1)

      7.2 ProxyHandler处理器(代理设置)

    from urllib import request
    
    # 构建代理Hander
    HttpProxy_Handler = request.ProxyHandler({"http":"127.0.0.1:80"}) 
    
    # 通过urllib.request.build_opener()方法使用这些代理Handler对象,创建自定义opener对象
    
    opener = request.build_opener(HttpProxy_Handler)
    
    request_ = request.Request(url)
    
    # 此时只有使用opener.open()发送请求才使用自定义的代理,而urlopen()则不会使用代理
    response = opener.open(request_)
    
    # 通过request.install_opener()应用到全局,之后不管是opener.open()还是urlopen()都能使用代理
    
    request.install_opener(opener)
    
    response = urlopen(request_)
    
    print(response.read().decode())

      7.3 Cookie

        Cookie是指某些网站服务器为了辨别用户身份和进行Session跟踪,而存储在用户浏览器上的文本文件,Cookie可以保持登录信息到用户下次与服务器的会话。

        7.3.1 Cookie原理

          HTTP是无状态的面向连接的协议,为了保持连接状态,引入了Cookie机制,Cookie是http消息头中的一种属性,包括:

    Cookie名字(Name)
    Cookie的值(Value)
    Cookie的过期时间(Expiers/Max-Age)
    Cookie作用路径(Path)
    Cookie所在域名(Domain)
    使用Cookie进行安全连接(Secure)

          前两个参数是Cookie应用的必要条件,另外,还包括Cookie大小(Size,不同的浏览器对Cookie个数及大小限制是有差异的)

          Cookie有变量名和值组成,根据Netscape公司的规定,Cookie格式如下:

    Set-Cookie: NAME=VALUE;Expires=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE

        7.3.2 Cookie应用

          Cookies在爬虫方面最典型的应用是判定注册用户是否已经登录网站,用户可能会得到提示,是否在下一次进入此网站时保留用户信息以便简化登录手续。

    # 获取一个有登录信息的Cookie模拟登陆
    
    import urllib
    
    # 1. 构建一个已经登录过的用户的headers信息
    headers = {
        "Host":"www.renren.com",
        "Connection":"keep-alive",
        "Upgrade-Insecure-Requests":"1",
        "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
        "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
        "Accept-Language":"zh-CN,zh;q=0.8,en;q=0.6",
        "Referer":"http://www.renren.com/SysHome.do",
        # 便于终端阅读,表示不支持压缩文件
        # Accept-Encoding: gzip, deflate, sdch,
    
        # 重点:这个Cookie是保存了密码无需重复登录的用户的Cookie,这个Cookie里记录了用户名,密码(通常经过RAS加密)
        "Cookie": "anonymid=j3jxk555-nrn0wh; depovince=BJ; _r01_=1; JSESSIONID=abcnLjz9MSvBa-3lJK3Xv; ick=3babfba4-e0ed-4e9f-9312-8e833e4cb826; jebecookies=764bacbd-0e4a-4534-b8e8-37c10560770c|||||; ick_login=84f70f68-7ebd-4c5c-9c0f-d1d9aac778e0; _de=7A7A02E9254501DA6278B9C75EAEEB7A; p=91063de8b39ac5e0d2a57500de7e34077; first_login_flag=1; ln_uact=13146128763; ln_hurl=http://head.xiaonei.com/photos/0/0/men_main.gif; t=39fca09219c06df42604435129960e1f7; societyguester=39fca09219c06df42604435129960e1f7; id=941954027; xnsid=8868df75; ver=7.0; loginfrom=null; XNESSESSIONID=a6da759fe858; WebOnLineNotice_941954027=1; wp_fold=0"
    }
    
    # 2. 通过headers里的报头信息(主要是Cookie信息),构建Request对象
    urllib.request.Request("http://www.renren.com/941954027#", headers = headers)
    
    # 3. 直接访问renren主页,服务器会根据headers报头信息(主要是Cookie信息),判断这是一个已经登录的用户,并返回相应的页面
    response = urllib.request.urlopen(request)
    
    # 4. 打印响应内容
    print (response.read().decode())

          但是这样做太过复杂,我们先需要在浏览器登录账户,并且设置保存密码,并且通过抓包才能获取这个Cookie。

        7.3.4 Cookiejar库和HTTPCookieProcessor处理器

          在python中处理Cookie,一般是通过cookiejar模块和urllib模块的HTTPCookieProcessor处理器类一起使用。

          `Cookiejar模块:主要作用是提供用于存储cookie的对象`

          `HTTPCookieProcessor处理器:主要作用是处理这些cookie对象,并构建handler对象`

        7.3.5 cookiejar库

          这个模块主要的对象有Cookiejar、FileCookieJar、MozillaCookieJar、LWPCookieJar。

          CookieJar:管理HTTP cookie值、存储HTTP请求生成的cookie、向传出的HTTP请求添加cookie的对象。整个cookie都存储在内存中,对CookieJar实例进行垃圾回收后cookie也将丢失。

    from urllib import request 
    import http.cookiejar
    # 构建一个Cookiejar对象实例来保存cookie
    
    #CookieJar:管理HTTP cookie值、存储HTTP请求生成的cookie、向传出的HTTP请求添加cookie的对象。整个cookie都存储在内存中,对CookieJar实例进行垃圾回收后cookie也将丢失
    cookiejar_ = http.cookiejar.CookieJar()
    
    # 使用HTTPCookieProcessor()来创建cookie处理器对象,参数为cookiejar()对象
    handler = request.HTTPCookieProcessor(cookiejar_)
    
    # 通过request.build_opener()来构建opener
    opener = request.build_opener(handler)
    
    # 以get方式访问页面,访问之后会自动保存cookie到cookiejar中
    opener.open('http://www.baidu.com')
    
    # 按照标准格式将保存的Cookie打印出来
    cookieStr = str()
    
    for item in cookiejar_:
        cookiejar = cookieStr+item.name+"="+item.value+";"
    
    print(cookieStr)

          模拟登陆时要注意:

          (1)登录一般都会先有一个HTTP GET,用于拉取一些信息及获得Cookie,然后再HTTP POST登录

          (2)HTTP POST登录的链接有可能是动态的,从GET返回的信息中获取

          (3)password 有些是明文发送,有些是加密后发送。有些网站甚至采用动态加密的,同时包括了很多其他数据的加密信息,只能通过查看JS源码获得加密算法,再去破解加密,非常困难。

  • 相关阅读:
    Device eth0 does not seem to be present, delaying initialization(解决克隆CentOS6.3虚拟机后网卡设备无法启动问题)
    CI整合Smarty
    修改crontab默认的编辑器
    添加数据之后不跳页面显示一个漂亮的提示信息(非ajax提交数据)
    jsp连接mysql数据库
    PHP使用CURL详解
    内、外部号码范围配置
    更改SAP的字段翻译
    SAP 应用服务负载均衡的实现
    SAP中禁止特定用户更改密码
  • 原文地址:https://www.cnblogs.com/nuochengze/p/12858684.html
Copyright © 2020-2023  润新知