• 爬虫与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 + '
    ')
    有志者,事竟成,破釜沉舟,百二秦关终属楚; 苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
  • 相关阅读:
    织梦内容模型自定义字段设置一个随机数
    网页禁止右键查看源码屏蔽键盘事件
    面试官:如何防止 Java 源码被反编译?我竟然答不上来。。
    Elastic Job 同城主备、同城双活,高可用必备~
    再见,Spring Security OAuth!!
    怎么让 Linux 进程在后台运行?
    30 个 ElasticSearch 调优知识点,都给你整理好了!
    Spring Boot 2.5.4 发布,2.2.x 正式结束使命!
    移动端与服务器端之间的 token 怎么设计?
    最新数据库排行出炉,SQL Server 暴跌。。
  • 原文地址:https://www.cnblogs.com/luyj00436/p/15389918.html
Copyright © 2020-2023  润新知