• 爬虫系列(三) urllib的基本使用


    一、urllib 简介

    urllib 是 Python3 中自带的 HTTP 请求库,无需复杂的安装过程即可正常使用,十分适合爬虫入门

    urllib 中包含四个模块,分别是

    • request:请求处理模块
    • parse:URL 处理模块
    • error:异常处理模块
    • robotparser:robots.txt 解析模块

    以下我们将会分别讲解 urllib 中各模块的使用方法,但是由于篇幅问题,本文只会涉及模块中比较常用的内容

    详细内容可以参考官方文档:https://docs.python.org/3.7/library/urllib.html

    二、urllib 使用

    在开始讲解前,先给大家提供一个用于测试的网站,http://www.httpbin.org/

    这个网站可以在页面上返回所发送 请求 的相关信息,十分适合练习使用

    好了,下面正式开始!

    1、request 模块

    request 模块是 urllib 中最重要的一个模块,一般用于 发送请求和接收响应

    (1)urlopen 方法

    urllib.request.urlopen()
    

    urlopen 方法无疑是 request 模块中最常用的方法之一,常见的参数说明如下:

    • url:必填,字符串,指定目标网站的 URL

    • data:指定表单数据

      该参数默认为 None,此时 urllib 使用 GET 方法 发送请求

      当给参数赋值后,urllib 使用 POST 方法 发送请求,并在该参数中携带表单信息(bytes 类型)

    • timeout:可选参数,用来指定等待时间,若超过指定时间还没获得响应,则抛出一个异常

    该方法始终返回一个 HTTPResponse 对象,HTTPResponse 对象常见的属性和方法如下:

    • geturl():返回 URL
    • getcode():返回状态码
    • getheaders():返回全部响应头信息
    • getheader(header):返回指定响应头信息
    • read():返回响应体(bytes 类型),通常需要使用 decode('utf-8') 将其转化为 str 类型

    例子1:发送 GET 请求

    >>> import urllib.request
    >>> url = 'http://www.httpbin.org/get'
    >>> response = urllib.request.urlopen(url)
    >>> type(response)
    # <class 'http.client.HTTPResponse'>
    >>> response.geturl()
    # 'http://www.httpbin.org/get'
    >>> response.getcode()
    # 200
    >>> response.getheaders()
    # [('Connection', 'close'), ('Server', 'gunicorn/19.9.0'), ('Date', 'Sat, 11 Aug 2018 01:39:14 GMT'), ('Content-Type', 'application/json'), ('Content-Length', '243'), ('Access-Control-Allow-Origin', '*'), ('Access-Control-Allow-Credentials', 'true'), ('Via', '1.1 vegur')]
    >>> response.getheader('Connection')    
    # 'close'
    >>> print(response.read().decode('utf-8'))
    # {
    #   "args": {}, 
    #   "headers": {
    #     "Accept-Encoding": "identity", 
    #     "Host": "www.httpbin.org", 
    #     "User-Agent": "Python-urllib/3.7"
    #   }, 
    #   "origin": "183.6.159.80, 183.6.159.80", 
    #   "url": "https://www.httpbin.org/get"
    # }
    

    例子2:发送 POST 请求

    urllib.parse.urlencode():进行 URL 编码,实际上是将 dict 类型数据转化成 str 类型数据

    encode('utf-8'):将 str 类型数据转化成 bytes 类型数据

    >>> import urllib.request
    >>> import urllib.parse
    >>> url = 'http://www.httpbin.org/post'
    >>> params = {
        'from':'AUTO',
        'to':'AUTO'
    }
    >>> data = urllib.parse.urlencode(params).encode('utf-8')
    >>> response = urllib.request.urlopen(url=url,data=data)
    >>> html =  response.read().decode('utf-8')
    >>> print(html)
    # {
    #   "args": {}, 
    #   "data": "", 
    #   "files": {}, 
    #   "form": { # 这是我们设置的表单数据
    #     "from": "AUTO", 
    #     "to": "AUTO"
    #   }, 
    #   "headers": {
    #     "Accept-Encoding": "identity", 
    #     "Connection": "close", 
    #     "Content-Length": "17", 
    #     "Content-Type": "application/x-www-form-urlencoded", 
    #     "Host": "www.httpbin.org", 
    #     "User-Agent": "Python-urllib/3.6"
    #   }, 
    #   "json": null, 
    #   "origin": "116.16.107.180", 
    #   "url": "http://www.httpbin.org/post"
    # }
    

    (2)Request 对象

    实际上,我们还可以给 urllib.request.open() 方法传入一个 Request 对象作为参数

    为什么还需要使用 Request 对象呢?因为在上面的参数中我们无法指定 请求头部,而它对于爬虫而言又十分重要

    很多网站可能会首先检查请求头部中的 USER-AGENT 字段来判断该请求是否由网络爬虫程序发起

    但是通过修改请求头部中的 USER_AGENT 字段,我们可以将爬虫程序伪装成浏览器,轻松绕过这一层检查

    这里提供一个查找常用的 USER-AGENT 的网站:

    urllib.request.Request()
    

    参数说明如下:

    • url:指定目标网站的 URL
    • data:发送 POST 请求时提交的表单数据,默认为 None
    • headers:发送请求时附加的请求头部,默认为 {}
    • origin_req_host:请求方的 host 名称或者 IP 地址,默认为 None
    • unverifiable:请求方的请求无法验证,默认为 False
    • method:指定请求方法,默认为 None
    >>> import urllib.request
    >>> url = 'http://www.httpbin.org/headers'
    >>> headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
    }
    >>> req = urllib.request.Request(url, headers=headers, method='GET')
    >>> response = urllib.request.urlopen(req)
    >>> html = response.read().decode('utf-8')
    >>> print(html)
    # {
    #   "headers": {
    #     "Accept-Encoding": "identity", 
    #     "Connection": "close", 
    #     "Host": "www.httpbin.org", 
    #     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36" 这是我们设置的 User-Agent
    #   }
    # }
    

    什么是 Cookie?

    Cookie 是指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据

    ① 获取 Cookie

    >>> import urllib.request
    >>> import http.cookiejar
    >>> cookie = http.cookiejar.CookieJar()
    >>> cookie_handler = urllib.request.HTTPCookieProcessor(cookie)
    >>> opener = urllib.request.build_opener(cookie_handler)
    >>> response = opener.open('http://www.baidu.com')
    >>> for item in cookie:
        	print(item.name + '=' + item.value)
            
            
    # BAIDUID=486AED46E7F22C0A7A16D9FE6E627846:FG=1
    # BDRCVFR[RbWYmTxDkZm]=mk3SLVN4HKm
    # BIDUPSID=486AED46E7F22C0A7A16D9FE6E627846
    # H_PS_PSSID=1464_21106_26920
    # PSTM=1533990197
    # BDSVRTM=0
    # BD_HOME=0
    # delPer=0
    

    ② 使用 Cookie

    >>> import urllib.request
    >>> import http.cookiejar
    >>> # 将 Cookie 保存到文件
    >>> cookie = http.cookiejar.MozillaCookieJar('cookie.txt')
    >>> cookie_handler = urllib.request.HTTPCookieProcessor(cookie)
    >>> opener = urllib.request.build_opener(cookie_handler)
    >>> response = opener.open('http://www.baidu.com')
    >>> cookie.save(ignore_discard=True,ignore_expires=True)
    >>> # 从文件读取 Cookie 并添加到请求中
    >>> cookie = http.cookiejar.MozillaCookieJar()
    >>> cookie = cookie.load('cookie.txt',ignore_discard=True,ignore_expires=True)
    >>> cookie_handler = urllib.request.HTTPCookieProcessor(cookie)
    >>> opener = urllib.request.build_opener(cookie_handler)
    >>> response = opener.open('http://www.baidu.com')
    >>> # 此时已经得到带有 Cookie 请求返回的响应
    

    (4)使用代理

    对于某些网站,如果同一个 IP 短时间内发送大量请求,则可能会将该 IP 判定为爬虫,进而对该 IP 进行封禁

    所以我们有必要使用随机的 IP 地址来绕开这一层检查,这里提供几个查找免费的 IP 地址的网站:

    注意,免费的代理 IP 基本上十分不稳定,而且还可能随时更新,所以最好自己写一个爬虫去维护

    >>> import urllib.request
    >>> import random
    >>> ip_list = [
        {'http':'61.135.217.7:80'},
        {'http':'182.88.161.204:8123'}
    ]
    >>> proxy_handler = urllib.request.ProxyHandler(random.choice(ip_list))
    >>> opener = urllib.request.build_opener(proxy_handler)
    >>> response = opener.open('http://www.httpbin.org/ip')
    >>> print(response.read().decode('utf-8'))
    # {
    #   "origin": "61.135.217.7"
    # }
    

    2、parse 模块

    parse 模块一般可以用于处理 URL

    (1)quote 方法

    当你在 URL 中使用中文时,你会发现程序会出现莫名其妙的错误

    >>> import urllib.request
    >>> url = 'https://www.baidu.com/s?wd=爬虫'
    >>> response = urllib.request.urlopen(url)
    # UnicodeEncodeError: 'ascii' codec can't encode characters in position 10-11: ordinal not in range(128)
    

    这时,quote 方法就可以派上用场了,它使用转义字符替换特殊字符,从而将上面的 URL 处理成合法的 URL

    >>> import urllib.parse
    >>> url = 'https://www.baidu.com/s?wd=' + urllib.parse.quote('爬虫')
    >>> url
    # 'https://www.baidu.com/s?wd=%E7%88%AC%E8%99%AB'
    

    (2)urlencode 方法

    urlencode 方法在上面的文章中曾经用到过,不知道大家还有没有印象,这里我们再重新回顾一遍

    简单来说,urlencode 方法就是将 dict 类型数据转化为符合 URL 标准的 str 类型数据,请看演示:

    >>> import urllib.parse
    >>> params = {
        'from':'AUTO',
        'to':'AUTO'
    }
    >>> data = urllib.parse.urlencode(params)
    >>> data
    # 'from=AUTO&to=AUTO'
    

    (3)urlparse 方法

    urlparse 方法用于解析 URL,返回一个 ParseResult 对象

    该对象可以认为是一个六元组,对应 URL 的一般结构:scheme://netloc/path;parameters?query#fragment

    >>> import urllib.parse
    >>> url = 'http://www.example.com:80/python.html?page=1&kw=urllib'
    >>> url_after = urllib.parse.urlparse(url)
    >>> url_after
    # ParseResult(scheme='http', netloc='www.example.com:80', path='/python.html', params='', query='page=1', fragment='urllib')
    >>> url_after.port
    # 80
    

    3、error 模块

    error 模块一般用于进行异常处理,其中包含两个重要的类:URLErrorHTTPError

    注意,HTTPError 是 URLError 的子类,所以捕获异常时一般要先处理 HTTPError,常用的格式如下:

    >>> import urllib.request
    >>> import urllib.error
    >>> import socket
    >>> try:
    	response = urllib.request.urlopen('http://www.httpbin.org/get', timeout=0.1)
    except urllib.error.HTTPError as e:
    	print("Error Code: ", e.code)
    	print("Error Reason: ", e.reason)
    except urllib.error.URLError as e:
    	if isinstance(e.reason, socket.timeout):
    		print('Time out')
    else:
    	print('Request Successfully')
        
    # Time out
    

    【参考资料】

    【爬虫系列相关文章】

    版权声明:本博客属于个人维护博客,未经博主允许不得转载其中文章。
  • 相关阅读:
    寒武纪芯片——有自己的SDK,支持tf、caffe、MXNet
    专车降价滴滴快车使命终结?
    滴滴代驾骑虎难下 司机1人23部手机刷单
    柳青:再见!滴滴打车 其实这里面都是故事
    “专车”监管意见最快本月公布
    不少专车司机考虑退出
    专车新规或下周发布,估计有大量司机流失
    英媒:滴滴和优步每年烧钱64亿
    约租车管理办法近期公布 数量或受地方政府管控
    Uber上海公司被司机打上门
  • 原文地址:https://www.cnblogs.com/wsmrzx/p/9461233.html
Copyright © 2020-2023  润新知