• urllib库


    urllib是python内置的网络库

    一.urllib的主要功能

    urllib分为4个模块
    1.request:最基本的HTTP请求模块,可以用来发送HTTP请求,并接收服务端的响应数据。这个过程就像在浏览器地址栏输入URL,然后按下Enter键一样
    2.error:异常处理模块,如果出现请求错误,可以捕获这些异常,然后根据实际情况,进行重试或者直接忽略,或进行其他操作。
    3.parse:工具模块,提供了很多处理URL的API,如拆分、解析、合并
    4.robotparser:主要用来识别网站的robots.txt文件,然后判断哪些文件可以抓取,哪些文件不可以抓取

    二:发送请求与获得响应

    1.get请求

    import urllib.request
    
    # urlopen可以用http也可以用https
    response=urllib.request.urlopen('https://www.jd.com')
    # 输出响应的数据类型
    print('response的类型:',type(response))
    # 输出响应状态码、响应消息、和HTTP版本
    print('status:',response.status,' msg:',response.msg,' version:', response.version)
    # 输出所有的响应头信息
    print('headers:',response.getheaders())
    # 输出Content-Type信息
    print('headers.Content-Type',response.getheader('Content-Type'))
    # 输出url链接返回响应的HTML代码
    print(response.read().decode('utf-8'))
    

    2.post请求

    import urllib.request
    # urlencode方法将字典类型的表单转换为字符串形式的表单
    data=bytes(urllib.parse.urlencode({'name':'Bill','age':30}),encoding='utf-8') # data参数是字节类型byte()来处理
    response=urllib.request.urlopen('http://httpbin.org/post',data=data) # 发送POST请求用data参数命名
    print(response.read().decode('utf-8')) # 这里并不需要显示指出是POST请求,缘由是这个url是测试HTTP POST请求的网址
    

    3.请求超时

    import urllib.request
    import socket
    import urllib.error
    try:
        response=urllib.request.urlopen('http://httpbin.org/get',timeout=0.1) # 由于绝大网站不太可能在0.1秒内
        # 响应客户端的请求,所以超时
    except urllib.error.URLError as e:
        if isinstance(e.reason,socket.timeout):
            print('超时')
    print("继续爬虫其他的工作")
    

    4.加入User-Agent和Host请求头和自定义请求头who

    from urllib import request,parse
    # 定义要提交HTTP请求的URL
    url = 'http://httpbin.org/post'
    
    # 定义HTTP请求头,其中who是自定义的请求字段
    headers = {
        'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36',
        'Host':'httpbin.org',
    
    
        'who':'Python Scrapy'
    }
    # 定义表单数据
    dict = {
        'name':'Bill',
        'age':30
    }
    # 将表单数据转化为bytes形式
    data = bytes(parse.urlencode(dict),encoding='utf-8')
    # 创建request对象,通过request类的构造方法指定了表单数据和HTTP请求头
    req = request.Request(url = url,data=data,headers=headers,method="POST")
    # urlopen函数通过request对象向服务端发送HTTP POST
    response=request.urlopen(req)
    print(response.read().decode('utf-8'))
    

    5.设置中文请求头

    from urllib import request
    from urllib.parse import unquote,urlencode
    import base64
    
    # base64.b64encode编码 ;base64.b64decode解码
    
    url = 'http://httpbin.org/post'
    headers = {
        'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36',
        'Host':'httpbin.org',
        'Chinese1':urlencode({'name':'李宁'}),
        # 设置中文HTTP请求头,用base64编码格式
        'MyChinese':base64.b64encode(bytes('这是中文HTTP请求头',encoding='utf-8')),
        'who':'Python Scrapy'
    }
    dict = {
        'name':'Bill',
        'age':30
    }
    data = bytes(urlencode(dict),encoding='utf-8')
    req = request.Request(url = url,data=data,headers=headers,method="POST")
    # 通过add_header方法添加中文HTTP请求头,url编码格式
    req.add_header('Chinese2',urlencode({"国籍":"中国"}))
    response=request.urlopen(req)
    # 获得服务端的响应信息
    value = response.read().decode('utf-8')
    print(value)
    import json
    # 将返回值转化为json对象
    responseObj = json.loads(value)
    # 解码url编码的HTTP请求头
    print(unquote(responseObj['headers']['Chinese1']))
    print(unquote(responseObj['headers']['Chinese2']))
    print(str(base64.b64decode(responseObj['headers']['Mychinese']),'utf-8'))
    

    6.请求基础验证页面

    6.1编写个支持验证页面的Web服务器

    这个web服务器可以生成一个表单验证,只有通过这个验证才能访问下一个页面。表单验证也是基础验证,是HTTP验证的一种

    from flask import Flask  # 
    from flask import request
    import base64
    app = Flask(__name__)
    # 判断客户端是否提交了用户名和密码,如果未提交,设置状态码为401,并设置WWW-Authenticate响应头
    # auth:Authorization请求头字段的值,response:响应对象
    
    def hasAuth(auth,response):
        if auth == None or auth.strip() == "":
            # 设置响应状态码为401
            response.status_code = 401
            # 设置响应头的WWW-Authenticate字段,其中localhost是需要验证的范围
            response.headers["WWW-Authenticate"] = 'Basic realm="localhost"'
            # 返回False,表示客户端未提交用户名和密码
            return False
        return True
    
    # 根路由
    @app.route("/") # 这个函数是把传输的密码可以用编码的方式写入headers头中,这里是Authorization中
    def index():
        # 创建响应对象,并指定未输入用户名和密码(单击"取消”按钮)或输入错误后的返回内容
        response = app.make_response('username or password error')
        # 输出所有的HTTP请求头
        print(request.headers)
        # 得到Authorization请求头的值
        auth = request.headers.get('Authorization') 
        # 得到Authorization请求头的值
        print('得到Authorization请求头的值:',auth) 
        if hasAuth(auth, response):   # 把请求头的值和response放进这个函数中
            # 将用户名和密码按Base64编码格式解码,这里按空格拆分成两个值,第一个是Basic,第二个是Base64编码后的用户名和密码
    
            auth = str(base64.b64decode(auth.split(' ')[1]),'utf-8')
            # 用户名和密码之间用冒号(:)分隔,所以需要将他们拆开
            values = auth.split(':')
            # 获取用户名
            username = values[0]
            #获取密码
            password = values[1]
            print('username:',username) # 他们又是从哪获取密码的呢
            print('password:',password)
            # 判断用户名和密码是否正确,如果正确,返回success
            if username == 'bill' and password == '1234':
                return "success"
        return response
    
    
    if __name__ == '__main__':
        app.run()
    

    6.2用户名和密码通过HTTP请求头的Authorization字段发送给服务器

    from urllib import request
    import base64
    
    
    url = 'http://localhost:5000'
    headers = {
        'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36',
        'Host':'localhost:5000',
        'Authorization': 'Basic ' + str(base64.b64encode(bytes('bill:1234','utf-8')),'utf-8'),
    
    }
    req = request.Request(url = url,headers=headers,method="GET")
    response=request.urlopen(req)
    print(response.read().decode('utf-8'))
    

    6.3采用HTTPPasswordMgrWithDefaultRealm对象封装请求字段数据

    from urllib.request import HTTPPasswordMgrWithDefaultRealm,HTTPBasicAuthHandler,build_opener
    from urllib.error import URLError
    username = 'bill'
    password = '1234'
    url = 'http://localhost:5000'
    
    p = HTTPPasswordMgrWithDefaultRealm() # HTTPPasswordMgrWithDefaultRealm对象封装请求字段数据
    # 封装realm,url、用户名和密码
    p.add_password('localhost',url,username,password)
    auth_handler = HTTPBasicAuthHandler(p) # HTTPBasicAuthHandler用于处理管理认证
    # 发送http请求
    opener = build_opener(auth_handler)
    
    try:
        result = opener.open(url)
        # 获取服务端响应数据
        html = result.read().decode('utf-8')
        print(html)
    except URLError as e:
        print(e.reason)
    

    7.搭建代理与使用代理(创建ProxyHandler对象,并指定HTTP和HTTPS代理的IP和端口号)

    from urllib.error import URLError
    from urllib.request import ProxyHandler,build_opener
    
    
    # 创建ProxyHandler对象,并指定HTTP和HTTPS代理的IP和端口号
    proxy_handler = ProxyHandler({
        #'http':'http://103.100.96.174:53281',
        'http':'http://182.86.191.16:24695',
        'https':'https://182.86.191.16:24695'
    })
    
    opener = build_opener(proxy_handler)
    try:
        #response = opener.open('http://blogjava.net')
        response = opener.open('https://www.jd.com')
        print(response.read().decode('utf-8'))
    except URLError as e:
        print(e.reason)
    

    8.Cookie的读写过程

    8.1用Falsk编写一个Web服务器

    该Web服务器读取客户端发送过来的Cookie,以及将Cookie写入客户端

    from flask import Flask # flask果然是小巧可扩展
    from flask import request
    app = Flask(__name__)
    @app.route("/readCookie")
    def readCookie():
        print(request.cookies) # 这个是读取刚刚写入的Cookie,或者还可以从用户的请求中读取Cookie
        print(request.cookies.get('MyCookie'))
        return "hello world"
    
    @app.route("/writeCookie") # route后跟着的因该是url路径
    def writeCookie():
        response = app.make_response('write cookie')
        response.set_cookie("id", value="12345678") # 这里竟然可以直接写入cookie
        return response
    if __name__ == '__main__':
        app.run()
    

    8.2获取Cookie

    urllib获取Cookie真的很麻烦
    首先读取Cookie需要创建http.cookiejar.CookieJar类的实例a,然后再创建urllib.request.HTTPCookieProcessor类的实例b,并将a作为实例b的参数传进。而build_opener的参数就是实例b,所以,当build_open从服务端响应某个数据时就会读取服务端发送过来的Cookie然后保存在实例a中,返回的是个字典

    import http.cookiejar
    import  urllib.request
    # 创建CookieJar对象
    cookie = http.cookiejar.CookieJar()
    # 创建HTTPCookieProcessor对象
    handler = urllib.request.HTTPCookieProcessor(cookie)
    opener = urllib.request.build_opener(handler) # build_opener从服务器端获取响应数据时就会读取服务端发送过来的Cookie
    # 给http://www.baidu.com发送请求,并获得响应数据
    response = opener.open('http://www.baidu.com') # open()中传入url就可以获取响应了
    print('------http://www.baidu.com--------')
    # 输出服务器端发送的所有Cookie
    for item in cookie:
        print(item.name + '=' + item.value)
    # 下面的代码用同样的方式访问CookieServer,并输出返回的Cookie
    print('------http://127.0.0.1:5000/writeCookie--------')
    cookie = http.cookiejar.CookieJar()
    handler = urllib.request.HTTPCookieProcessor(cookie)
    opener = urllib.request.build_opener(handler)
    response = opener.open('http://127.0.0.1:5000/writeCookie')
    for item in cookie:
        print(item.name + '=' + item.value)
    

    8.3读取Cookie并把Cookie保存起来

    可以用MozillaCookieJar类和LWPCookieJar类再获得Cookie的同时讲Cookie分别保存成Mozilla浏览器格式和libwww-perl(LWP)格式,再创建MozillaCookieJar类和LWPCookieJar类的实例过程中需要传入Cookie文件名。其他的使用方法与.CookieJar类基本一样

    import http.cookiejar
    import urllib.request
    filename1 = 'cookies5.txt' 
    filename2 = 'cookies4.txt'
    # 创建MozillaCookieJar对象
    cookie1 = http.cookiejar.MozillaCookieJar(filename1) # 这个可以自动创建文件
    # 创建LWPCookieJar对象
    cookie2 = http.cookiejar.LWPCookieJar(filename2)
    
    
    handler1 = urllib.request.HTTPCookieProcessor(cookie1)
    handler2 = urllib.request.HTTPCookieProcessor(cookie2)
    opener1 = urllib.request.build_opener(handler1)
    opener2 = urllib.request.build_opener(handler2)
    opener1.open('http://www.baidu.com')
    opener2.open('http://www.baidu.com')
    # 将Cookie保存成MozillaCookieJar格式
    cookie1.save(ignore_discard=True,ignore_expires=True)
    # 将Cookie保存成LWPCookieJar格式
    cookie2.save(ignore_discard=True,ignore_expires=True)
    

    8.4创建一个Cookie.txt文件,并自定义2个Cookie,然后通过load方法装在Cookie.txt文件中的Cookie

    import http.cookiejar
    import urllib.request
    filename = 'cookies.txt'
    cookie = http.cookiejar.LWPCookieJar()
    # 装载cookies.txt文件,由于使用了LWPCookieJar读取Cookie,所以Cookie文件必须是LWP格式
    cookie.load('cookies.txt',ignore_discard=True,ignore_expires=True)
    handler = urllib.request.HTTPCookieProcessor(cookie)
    opener = urllib.request.build_opener(handler)
    response = opener.open('http://127.0.0.1:5000/readCookie')
    print(response.read().decode('utf-8'))
    

    三.异常处理

    1.URLError

    from urllib import request,error # 异常类都在urllib的error模块中定义
    
    try:
        response = request.urlopen('http://www.jd123.com/test.html')
    except error.URLError as e:
        print(e.reason) # Not Found
    
    
    try:
        response = request.urlopen('https://geekori.com/abc.html')
    except error.URLError as e:
        print(e.reason) # Not Found
    
    
    try:
        response = request.urlopen('https://geekori123.com/abc.html')
    except error.URLError as e:
        print(e.reason) # [Errno 11001] getaddrinfo failed
    
        
    try:
        response = request.urlopen('https://bbbccc.com',timeout=2)
    except error.URLError as e:
        print(e.reason) # [Errno 11001] getaddrinfo failed
    

    2.HTTPError

    from urllib import request,error
    import socket
    try:
        response = request.urlopen('http://www.jd123.com/test.html')
    except error.HTTPError as e:
        print(type(e.reason))
        print(e.reason,e.code,e.headers)
    try:
        response = request.urlopen('https://www.baidu.com',timeout=0.01)
    except error.HTTPError as e:
        print('=====')
        print('error.HTTPError:', e.reason) # 这个语句没有抛出
    except error.URLError as e:
        # <class 'socket.gaierror'> gaierror后端抛出的异常这个报错直接是域名错了,url不存在
        print(type(e.reason)) 
        print('error.URLError:', e.reason) # error.URLError: timed out
        if isinstance(e.reason,socket.timeout):
            print('超时错误')
    
    

    四。解析链接

    1.拆分与合并URL

    urlparse函数用于拆分URL,也就是将URL分解成不同的部分
    urlunparse合并函数

    from urllib.parse import urlparse,urlunparse
    
    # urlparse用于拆分URL
    result = urlparse('https://search.jd.com/Searchprint;hello?keyword=Python从菜鸟到高手&enc=utf-8#comment')
    
    print(type(result),result)
    print('--------分割线----------')
    # 将url拆成6部分
    print('scheme:',result.scheme) # scheme: https
    print('netloc:',result.netloc) # netloc: search.jd.com
    print('path:',result.path)  #path: /Searchprint
    print('params:',result.params) # params: hello
    print('query:',result.query) # query: keyword=Python从菜鸟到高手&enc=utf-8
    print('fragment:',result.fragment) # fragment: comment
    print('-----------------')
    result = urlparse('search.jd.com/Searchprint;hello?keyword=Python从菜鸟到高手&enc=utf-8#comment',scheme='ftp',allow_fragments=False)
    
    print('scheme:',result.scheme) # scheme: ftp
    print('fragment:',result.fragment) # 表示false则表示忽略fragment部分,默认参数值是True
    
    print('----------------')
    data = ['https','search.jd.com','Searchprint','world','keyword=Python从菜鸟到高手&enc=utf-8','comment']
    # urlunparse函数合并url不同的部分
    print(urlunparse(data)) # https://search.jd.com/Searchprint;world?keyword=Python从菜鸟到高手&enc=utf-8#comment
    

    2.另一种拆分与合并URL

    urlsplit函数与urlparse函数类似,只是将path与params看作一个整体,也就是urlsplit函数会将url拆分为5部分。
    urlunsplit函数与urlunparse函数类似,只不过需要指定一个包含5个元素的可迭代对象,而urlunparse函数需要包含6个元素的可迭代对象。

    from urllib.parse import urlsplit,urlunsplit
    
    # 将Url拆成5部分
    result = urlsplit('https://search.jd.com/Searchprint;hello?keyword=Python从菜鸟到高手&enc=utf-8#comment')
    
    print('scheme:',result.scheme)
    print('netloc:',result.netloc)
    print('path:',result.path)# 少了params 与parse()函数相比
    print('query:',result.query)
    print('fragment:',result.fragment)
    print('-----------------')
    # 将Url拆成5部分,并指定默认的scheme,以及不考虑fragment部分
    result = urlsplit('search.jd.com/Searchprint;hello?keyword=Python从菜鸟到高手&enc=utf-8#comment',scheme='ftp',allow_fragments=False)
    
    print('scheme:',result.scheme) # scheme可选参数,如果url没有带协议(https、httpftp等),那么scheme参数的值就会作为默认协议。该参数默认值为空字符串
    print('fragment:',result.fragment)
    
    print('----------------')
    data = ['https','search.jd.com','Searchprint;world','keyword=Python从菜鸟到高手&enc=utf-8','comment']
    
    print(urlunsplit(data)) # 合并url可以把
    

    3.连接URL

    from urllib.parse import urljoin
    
    """
    urljoin函数的第一个参数是base_url,是一个基URL,
    只能设置scheme、netloc和path;第二个参数是url,
    如果第二个参数不是一个完整的url,则会将第二个参数的值加到第一个参数后面,自动添加/
    如果第二个参数是完整的url就直接返回他
    
    """
    # 输出https://www.jd.com/index.html
    print(urljoin('https://www.jd.com','index.html'))
    # 输出https://www.taobao.com
    print(urljoin('https://www.jd.com','https://www.taobao.com'))
    # 输出https://www.taobao.com/index.html
    print(urljoin('https://www.jd.com/index.html','https://www.taobao.com/index.html'))
    # 输出https://www.jd.com/index.php?name=Bill&age=30
    print(urljoin('https://www.jd.com/index.php','?name=Bill&age=30'))
    # 输出https://www.jd.com/index.php?name=Bill
    print(urljoin('https://www.jd.com/index.php?value=123','?name=Bill'))
    

    4.url编码(urlencode)

    urljoin函数连接来组成完整的URL

    from urllib.parse import urlencode,urljoin
    # urlencode参数对URL进行编码,对中文的url非常有用
    # 中文转码后的格式是%xx 其中xx表示的是2位16进制数
    params = {
        'name':'王军',
        'country':'China',
        'age':30
    }
    
    base_url = 'https://www.google.com?'
    #url = base_url + urlencode(params)
    url = urljoin(base_url,'?' + urlencode(params))
    print(url)
    

    5.解码与编码(quote和unquote)

    from urllib.parse import quote,unquote
    keyword = '李宁'
    url = 'https://www.baidu.com/s?wd=' + quote(keyword)
    print(url)
    url = unquote(url)
    print(url)
    

    五。Robots协议

    待补(具体详情)

    1.RobotFileParser解析robots.txt文件

    from urllib.robotparser import RobotFileParser # 解析robots.txt文件
    from urllib import request
    robot = RobotFileParser()
    
    
    url = 'https://www.jianshu.com/robots.txt'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36',
        'Host': 'www.jianshu.com',
    }
    req = request.Request(url=url, headers=headers)
    
    # 抓取robots.txt文件的内容,并提交给parse方法进行分析
    robot.parse( request.urlopen(req).read().decode('utf-8').split('
    '))
    # 输出True
    print(robot.can_fetch('*','https://www.jd.com')) # can_fetch方法判断网站中的某一个url更具Robots协议是否有权抓取
    # 输出True
    print(robot.can_fetch('*','https://www.jianshu.com/p/92f6ac2c350f'))
    # 输出False
    print(robot.can_fetch('*','https://www.jianshu.com/search?q=Python&page=1&type=note'))
    
    
    努力拼搏吧,不要害怕,不要去规划,不要迷茫。但你一定要在路上一直的走下去,尽管可能停滞不前,但也要走。
  • 相关阅读:
    Linux显示文件内容常用命令
    Linux文件权限和更改权限
    数据存储及恢复的基本原理
    使用jemter发送HTTPS请求
    运行Jmeter时,出现java.util.prefs.WindowsPreferences <init>异常警告
    Server08AD域安装以及推送
    SVN服务器和客户端搭建
    selenium常见操作
    TestNG 入门教程
    ant+TestNG-xslt生成selenium测试报告
  • 原文地址:https://www.cnblogs.com/wkhzwmr/p/15224775.html
Copyright © 2020-2023  润新知