zoukankan      html  css  js  c++  java
  • 爬虫与Python:(三)基本库的使用——1.网络请求库之urllib()

    本文主要讲解Python3中的urllib库的用法。urllib是Python标准库中用于网络请求的库。该库有4个模块,分别是:urllib.request、urllib.error、urllib.parse和urllib.robotparser。其中urllib.request和urllib.error两个库在爬虫程序中使用比较频繁。

    本文目录如下:

    1. urlopen()
    2. 简单抓取网页
    3. 设置请求超时
    4. 使用data参数提交数据
    5. Request
    6. 简单的使用Request
    7. Request高级用法
    8. 使用代理
    9. 认证登录
    10. Cookie设置
    11. HTTPResponse
    12. 错误解析

    1. urlopen()

    模拟浏览器发起一个HTTP请求,需要用到urllib.request模块。urllib.request的作用不仅是发起请求,还能获取请求返回结果。下面先看一下urlopen()的API。

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

    参数和说明如下:

    参数 说明
    url string类型的地址,也就是要访问的url,例如:http://www.baidu.com。
    data bytes类型的内容,可通过bytes()函数转换为字节流,它也是可选参数。使用data参数,请求方式变成以post方式提交表单。使用标准格式是:application/x-www-form-urlencoded。
    timeout 参数用于设置请求超时时间,单位是秒。
    cafile/capath 参数代表CA证书和CA证书路径,如果适用HTTPS则需要用到。
    context 参数必须是ssl.SSLContext类型,用来指定SSL设置。
    cadefault 参数已弃用,可以略去。
    • urlopen()可以单独传入urllib.request.Request对象。
    • urlopen()返回的结果是一个http.client.HTTPResponse对象。
    • 实际使用过程中, 用得最多的参数是url和data。

    2. 简单抓取网页

    下面来看一个简单的示例,使用urlib.request.urlopen()去请求百度贴吧,并获取它的页面源代码。运行代码如下:

    1 import urllib.request
    2 
    3 url = 'https://tieba.baidu.com/'
    4 response = urllib.request.urlopen(url)
    5 html = response.read()     # 获取页码的源码
    6 print(html.decode('gbk')) # 转化为GBK编码

    运行结果如下:

      通过以上示例可以知道,使用 urlib.request.urlopen() 方法,传入网址,就可以成功获取到网页的页面源码。

    3. 设置请求超时

    有时,在访问网页是常常会遇到这样的情况——由于计算机网络或者对方服务器崩溃等原因,导致请求迟迟无法得到响应。同样地,程序去请求的时候,也会遇到这样的问题,因此,可以手动设置超时。当请求超时的时候,可以采取进一步的措施,或再次请求。因此,urlopen()中可以通过timeout设置超时响应时间。

    以下代码在url参数后添加了一个timeout设置,如果超过1s就舍弃它或重新获取网页。

    1 import urllib.request
    2 
    3 url = 'https://tieba.baidu.com/'
    4 response = urllib.request.urlopen(url , timeout=1)
    5 html = response.read()     # 获取页码的源码
    6 print(html.decode('gbk')) # 转化为GBK编码

    4. 使用data参数提交数据

    有的页面可以通过data传递一些其他的内容。data参数是可选的,如果添加data,需要它是字节流编码格式的内容,即bytes类型,通过bytes()函数可以进行转换,另外,如果传递了data参数,那么它的请求方式就不再是GET方式,而是通过POST方式。那么,他们是如何传递参数的呢?

    data需要被转换为字节流。而data是一个字典,需要使用 urllib.request.urlencode() 将字典转化为字符串,再使用bytes()函数转换为字节流。最后使用urlopen()发起请求,请求时模拟用POST方式提交数据。

    1 import urllib.parse
    2 import urllib.request
    3 
    4 url = 'http://httpbin.org/post'
    5 data =bytes(urllib.parse.urlencode({'word':'hello'}).encode('utf-8'))
    6 response = urllib.request.urlopen(url , data = data)
    7 print(response.read())

    运行后控制台会输出:

    5. Request

    通过urlopen()方法可以发起简单的请求,但它的几个简单的参数并不足以构建一个完整的请求。如果请求中需要加入headers(请求头)、指定请求方式等信息,那么久可以利用更强大的Request类来构建一个请求。下面来看一下Request请求的构造方法。

    urllib.request.Request(
        url,
        data=None,
        headers={},
        origin_req_host= None,
        unverifiable=False,
        method=None
    )

    Request请求的参数和描述如下:

    参数 数据类型 必填 描述
    url string 请求链接
    data bytes 与urlopen()的data的参数相同,请求表单的数据
    hearders   指定发起的HTTP请求的头部信息。headers是一个字典,它除了在Request中添加外,还可以通过调用Request实例的add_header()方法来添加请求头
    origin_req_host string 请求方法host的名称或IP地址
    unverifiable
    boolean 这个请求是否无法验证的,默认值False。意思是说用户没有足够的权限来选择接收这个请求的结果。例如,我们请求一个HTML文档中的图片,但是我们没有自动抓取图像的权限,我们就要将unverifiable的值设置成True。
    method string 发起请求的方式,有GET、POST、DELETE和PUT等。

    6. 简单使用Request

    了解Request参数后,下面就来简单地使用他来请求百度贴吧这个网址。

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

    运行代码如下:

    1 import urllib.request
    2 
    3 url = 'https://tieba.baidu.com/'
    4 hearders = {
    5     "User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36'
    6 }
    7 request = urllib.request.Request(url=url , headers= hearders)
    8 response = urllib.request.urlopen(request)
    9 print(response.read().decode('gbk'))

    运行结果如下:

     这里涉及到 User-Agent 头部信息的获取,可以使用谷歌浏览器随便打开一个网站,然后按【F12】进行调试界面,切换到【Network】选项卡刷新页面,随意选择一个请求,如图所示,即可找到需要的“User-Agent”,将其复制过来就可以了。

    7. Request高级用法

    如果需要在请求中添加代理、处理请求的Cookie,那么就需要用到Handler 和OpenerDirector两个知识点。

    7.1 Handler

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

    1. ProxyHandler:为请求设置代理。
    2. HTTPCookieProcessor: 处理HTTP请求的Cookie。
    3. HTTPDefaultErrorHandler: 处理HTTP响应错误。
    4. HTTPRedirectHandler : 处理HTTP响应重定向。
    5. HTTPPasswordMgr:用于密码管理,它维护了用户名密码的表。
    6. HTTPBasicAuthHandler : 用于登录认证,一般和HTTPPasswordMgr结合使用。

    7.2 OpenerDirector

    OpenerDirector ,也可以成为Opener。之前用过的urlopen()方法,实际上就是urlib提供一个Opener。那么Opener和Handler又有什么关系呢?Opener对象有 build_opener(handler) 方法创建出来的。创建自定义的Opener,就需要使用install_opener(opener)方法。值得注意的是,install_opener实例化会得到一个全局的OpenerDirector对象。

    8. 使用代理

    为什么需要使用代理?有些网站做了浏览器频率限制,如果请求频率过高,该网站就会封IP,禁止我们访问,所以就需要使用代理来突破这个“枷锁”。

     1 # 使用代理
     2 import urllib.request
     3 
     4 url = 'https://tieba.baidu.com/'
     5 hearders = {
     6     "User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36'
     7 }
     8 proxy_header = urllib.request.ProxyHandler({
     9    'http':'212.200.246.24:80',
    10    'https':'116.63.93.172:8081'
    11 });
    12 opener = urllib.request.build_opener(proxy_header)
    13 urllib.request.install_opener(opener)
    14 
    15 request = urllib.request.Request(url=url , headers= hearders)
    16 response = urllib.request.urlopen(request)
    17 print(response.read().decode('gbk'))

    通过以上代码可知,可以调用 ProxyHandler 方法设置代理,模拟成多个不同的客户端,成功“欺骗”网站,获取不同数据。

    在实际项目中,如果需要大量使用代理IP,可到专门做代理的IP供应商处购买,虽然晚上有大量免费的,但是大都不稳定。

    9. 认证登录

    有些网站需要携带账号和密码进行登录之后才能继续浏览网页。遇到这样的网站,就需要用到认证登录。认证登录步骤思路如下:

    1. 使用HTTPPasswordMgrWithDefaultRealm()实例化一个账号密码管理对象;
    2. 使用add_password()函数添加账号和密码;
    3. 使用HTTPBasicAuthHandler()得到Handler;
    4. 使用build_opener()获取Opener对象;
    5. 使用Opener的open函数发起请求。

    下面以携带账号和密码登录的百度贴吧为例,代码如下:

     1 # 认证登录
     2 import urllib.request
     3 
     4 url = 'https://tieba.baidu.com/'
     5 user = 'test_user'          # 运行时用了真实账号,这里指代一下
     6 password = 'test_password'  # 运行时用了真实账号,这里指代一下
     7 pwdmgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()   # 实例化账号密码管理对象
     8 pwdmgr.add_password(None ,url, user , password) # 添加账号密码
     9 auth_handler = urllib.request.HTTPBasicAuthHandler(pwdmgr) # 获取handler
    10 opener = urllib.request.build_opener((auth_handler))    # 得到Opener对象
    11 
    12 response = opener.open(url)
    13 print(response.read().decode('gbk'))

     控制台的运行结果与上文一致,这里省略了它。

    10. Cookie设置

    如果请求页面每次都需要身份验证,那么就可以使用Cookie来自动登录,免去重复验证的操作。获取Cookie需要 http.cookiejar.CookieJar() 实例化一个Cookie对象,再用 urlib.request.HTTPCookieProcessor 构建出Handler对象,最后使用Opener的open()函数即可。下面以获取请求百度贴吧的Cookie为例,代码如下:

     1 # Cookie设置
     2 import http.cookiejar
     3 import urllib.request
     4 
     5 url = 'https://tieba.baidu.com/'
     6 fileName = 'cookie.txt'
     7 
     8 cookie = http.cookiejar.CookieJar()
     9 handler = urllib.request.HTTPCookieProcessor(cookie)
    10 opener = urllib.request.build_opener(handler)
    11 response = opener.open(url)
    12 
    13 f =  open(fileName ,'a')
    14 for item in cookie:
    15     f.write(item.name +"=" + item.value + '
    ')
    16 f.close()

    运行完成后,文件的同级目录即可生成“cookie.txt”文件,记录保存的cookie。

    11. HTTPResponse

    从前面的例子可知,使用urlib.request.urlopen()或opener.open(url)返回结果是一个HTTPResponse对象。http.client.HTTPResponse对象包含msg、version、status、reasson、debuglevel、closed等属性及read()、readinto()、getheader(name)、getheaders()、fileno()等函数。

    12. 错误解析

    发起请求难免会出现各种异常,因此需要对异常进行处理,异常处理主要由两个类:urlib.error.URLErrorurlib.error.HTTPError。

    12.1 URLError

    URLError是urlib.error异常类的基类,可以用于捕获有urlib.request产生的异常。它具有一个属性reason,即返回错误的原因。捕获URL异常的代码示例如下:

    1 import urllib.request
    2 import urllib.error
    3 
    4 url = 'http://www.google.com'   # 正常国内网络下,谷歌无法连接
    5 
    6 try:
    7     response = urllib.request.urlopen(url)
    8 except urllib.error.URLError as e:
    9     print(e.reason)

    这里执行了捕获异常的代码,控制台运行结果如下:

    12.2 HTTPError

     HTTPError是UEKRoor的子类,专门处理HTTP和HTTPS请求的结果。它具有以下3个属性:

    • code: HTTP请求返回的状态码:
    • renson:与基类用法一样,表示返回错误的原因:
    • headers:HTTP请求返回的响应信息。

    获取HTTP异常的示例代码(输出类错误状态码、错误原因、服务器响应头)如下:

     1 # HTTPError
     2 import urllib.request
     3 import urllib.error
     4 
     5 url = 'http://www.google.com'   # 正常国内网络下,谷歌无法连接
     6 
     7 try :
     8     response = urllib.request.urlopen(url)
     9 except urllib.error.HTTPError as e:
    10     print('code:' + e.code + '
    ')
    11     print('reason' + e.reason + '
    ')
    12     print('headers' + e.headers + '
    ')
    有志者,事竟成,破釜沉舟,百二秦关终属楚; 苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
  • 相关阅读:
    杭电 Problem
    杭电Problem 5053 the sum of cube 【数学公式】
    杭电 Problem 2089 不要62 【打表】
    杭电 Problem 4548 美素数【打表】
    杭电 Problem 2008 分拆素数和 【打表】
    杭电 Problem 1722 Cake 【gcd】
    杭电 Problem 2187 悼念512汶川大地震遇难同胞——老人是真饿了【贪心】
    杭电Problem 1872 稳定排序
    杭电 Problem 1753 大明A+B
    东北林业大 564 汉诺塔
  • 原文地址:https://www.cnblogs.com/luyj00436/p/15389918.html
Copyright © 2011-2022 走看看