美文网首页
03_基本库的使用

03_基本库的使用

作者: Arale_zh | 来源:发表于2019-04-02 09:35 被阅读0次

    urllib库

    • python2中,由urllib和urllib2两个库来发送请求,python3中没有urllib2,统一为urllib
    • urllib的几个模块
      • request:最基本的http请求模块,
      • error: 异常处理的模块
      • parse:工具模块,提供了许多url处理方法,比如拆分、解析、合并等
      • robotparser:识别网络的robot.txt文件
    • request模块下的几个方法类
      • urlopen(url,data,timeoit)
        • url:必传,请求资源的地址
        • data:可选,必须是字节流格式,使用此方法后不再是get请求,而是post请求
        • timeout:设定超时时间
        from urllib import request, parse, error
        
        # urlopen(url, data)
        resp = request.urlopen("http://shuyantech.com/api/cndbpedia/avpair?q=%E6%B8%85%E5%8D%8E%E5%A4%A7%E5%AD%A6")  # 一个http响应对象
        res = resp.read()  # 返回值为bytes编码对象
        res = res.decode("utf-8")  # 对其解码
        print(res)
        
        # data: 像url中动态传参数,使用此方法后不再是get请求,而是post请求
        params = {"q":"清华大学"}  # 定义参数
        # urlencode(dict)将参数字典转化为字符串
        data = parse.urlencode(params)  # q=%E6%B8%85%E5%8D%8E%E5%A4%A7%E5%AD%A6
        # bytes(str,encode)将字符串转化为字节流类型,并制定编码格式
        data = bytes(data, encoding="utf8")  # b'q=%E6%B8%85%E5%8D%8E%E5%A4%A7%E5%AD%A6'
        resp = request.urlopen("http://shuyantech.com/api/cndbpedia/avpair?", data)
        res = resp.read() # b'{"status": "ok", "ret": [["\xe4\xb8\xad\xe6\x96\x87\xe5\x90\x8d", "\xe6\xb8\x85\xe5\x8d\x8e\xe5\xa4\xa7\xe5\xad\xa6"],
        res = res.decode("utf-8")  # {"status": "ok", "ret": [["中文名", "清华大学"],
        print(res)
        
        # timeout,设置超时时间,单位为秒
        try:
            resp = request.urlopen("http://shuyantech.com/api/cndbpedia/avpair?q=%E6%B8%85%E5%8D%8E%E5%A4%A7%E5%AD%A6", timeout=0.01)
            print(resp)  # urllib.error.URLError: <urlopen error timed out>
        except error.URLError as e:
            print(e.reason)  # timed out
            # isinstance,判断对象是否为已知类型,与type的区别,isinstance() 会认为子类是一种父类类型,考虑继承关系,type则不考虑继承关系
            import socket
            if isinstance(e.reason, socket.timeout):
                print("超时了")
        
      • Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False,method=None)
        • url:必传,请求的资源地址
        • data:必须是bytes(字节流)类型的
        • headers:字典形式,构造请求头信息,例如User-Agent
        • method:字符串,指定请求方式
        • origin_req_host:请求方的host和ip
        • unverifiable:验证用户有没有权限接受请求结果
        from urllib import request, parse
        url = "http://httpbin.org/post"
        data = {
            "name":"Request"
        }
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36",
            "Host": "httpbin.org"
        }
        method = "POST"
        # 构造请求信息
        req = request.Request(method=method, url=url, headers=headers, data=bytes(parse.urlencode(data), encoding="utf8") )
        resp = request.urlopen(req)
        res = resp.read().decode("utf-8")
        print(res)
        
      • Handler各种处理器和opener
        • HTTPBasicAuthHandler:用于管理认证,当一个连接打开时,需要登录,可以用它来解决认证问题
        • HTTPCookieProcessor:用于处理cookie
        • HTTPPasswordMgr:用于管理密码,维护了用户名和密码的表
        • HTTPRedirectHandler:用于重定向
        • ProxyHandler:用于设置代理,默认代理为空
        from urllib.request import ProxyHandler, build_opener
        from urllib.error import URLError
        
        url = "https://www.baidu.com"
        
        # 实例化代理
        p_handler = ProxyHandler({
            "http":"http://39.134.66.14:8080",
            "https":"https://218.38.52.132:80"
        })
        opener = build_opener(p_handler)  # build_opener(实例化的handler处理器)
        
        try:
            res = opener.open(url)
            html = res.read().decode("utf-8")
            print(html)
        except URLError as e:
            print(e.reason)
        
    • error:异常处理,定义了由request模块产生的错误
      • URLError:error模块的基类,由request模块产生的异常都可以通过这个类捕获,存在reason属性
      • HTTPError: URLError的子类,专门处理HTTP请求错误 属性code:返回的HTTP状态码,reason:错误原因 headers:返回请求头
      # 一个完整的异常捕获例子
       from urllib import error,request
       try:
           resp = request.urlopen("http://cuiqingcai.com/index.html")
       except error.HTTPError as e:
           print("返回的状态码%s" % e.code)
           print("返回的错误原因%s" % e.reason)
           print("返回的请求头%s" % e.headers)
       except error.URLError as e:
           print("异常原因%s" % e.reason)
       else:
           print("成功")
      

    -parse:解析链接,实现url各部分的抽取、合并、以及链接的转换

    • urlparse:实现url的分段和识别,分成六段 scheme://netloc/path;params?query#fragment
      • scheme:表示协议
      • netloc:表示域名
      • path:表示访问路径
      • params:代表参数,;后
      • query:代表查新条件,?后
      • fragment:表示锚点,#后
      • urlparse(url, scheme,allow_fragments)
        • url:必填,待解析的url
        • scheme:默认的协议,假如传入的连接没带协议,会采取这个默认的协议
        • allow_fragments:是否忽略锚点部分,值为布尔类型
    • urlunparse:根据参数,生成链接,参数为可迭代对象,且长度为6
    • urlsplit: 与urlparse一样,参数也形同解析url,分成五段,将params与path部分合并
      • urlsplit(url, scheme,allow_fragments)
    • urlunsplit: 参数为可迭代对象,且长度为5
    • urljoin:生成链接,效果同urlunparse和urlunsplit,但此方法不需要长度
      • urljoin(base_url,str) 将两个参数合并对base_url的协议、域名、路径进行补充,base_url其他三个部分则不起作用
    • urlencode:将字典对象序列化成符合url参数格式的字符串,一般往url传参中用
    • parse_qs:将url中的参数转成字典
    • parse_qsl:将url中的参数转化为元组组成的列表
    • quote:将数据转化为url格式的编码,一般参数为中文的时候使用
    • unquote:将url格式的编码进行解码
    ```
    from urllib import parse
    res = parse.urlparse("http:www.baidu.com/index.html;user?id=5#comment")
    # 返回结果为元组,res[0],res.scheme
    print(res, res[0], res.scheme)  # ParseResult(scheme='http', netloc='', path='www.baidu.com/index.html', params='user', query='id=5', fragment='comment')
    
    data = ["http", "www.baidu.com", "index.html", "user", "d=5", "comment"]
    res = parse.urlunparse(data)
    print(res)  # http://www.baidu.com/index.html;user?d=5#comment
    
    res = parse.urlsplit("http:www.baidu.com/index.html;user?id=5#comment")
    print(res)  # SplitResult(scheme='http', netloc='', path='www.baidu.com/index.html;user', query='id=5', fragment='comment')
    
    data = ["http", "www.baidu.com", "index.html", "d=5", "comment"]
    res = parse.urlunsplit(data)
    print(res)  # http://www.baidu.com/index.html?d=5#comment
    
    res = parse.urljoin("http://www.baidu.com", "index.html")
    print(res)  # http://www.baidu.com/index.html ,注意合并的规则
    
    data= {
        "name":"bob",
        "age":18
    }
    res = parse.urlencode(data, encoding="utf8")
    print(res)  # name=bob&age=18
    
    res = parse.parse_qs("http:www.baidu.com/index.html;user?id=5&name=3")
    print(res)  # {'user?id': ['5'], 'name': ['3#comment']}
    
    res = parse.parse_qsl("http:www.baidu.com/index.html;user?id=5&name=3")
    print(res)  # [('user?id', '5'), ('name', '3')]
    
    q= "张三"
    res = "http:www.baidu.com/index.html?q=%s " % parse.quote(q)  # 编码
    print(res)  # http:www.baidu.com/index.html?q=%E5%BC%A0%E4%B8%89
    res = parse.unquote(res)  # 解码
    print(res)  # http:www.baidu.com/index.html?q=张三
    ```
    
    • robotparse:分析网站的robot协议
      • robots.txt:网站爬虫协议,全称网络爬虫排除标准,一般存放于网站的根目录下
      • 返回的内容:
        • user-agent:设置可以爬取网站的爬虫名称
        • disallow:设置哪些路径不能爬取
        • allow:设置哪些路径可以爬取
      # 京东的爬虫协议
      # url: https://www.jd.com/robots.txt
      User-agent: *   # 任何爬虫都可以爬
      Disallow: /?* 
      Disallow: /pop/*.html 
      Disallow: /pinpai/*.html?* 
      User-agent: EtaoSpider 
      Disallow: / 
      User-agent: HuihuiSpider 
      Disallow: / 
      User-agent: GwdangSpider 
      Disallow: / 
      User-agent: WochachaSpider 
      Disallow: /
      
      • RobotFileParser(url="") # 根据网站的robot协议来判断爬虫是否有权限爬取
        • set_url():设置robots.txt文件的连接
        • read():读取robots.txt文件并分析,无返回值,必须调用
        • parse():解析robots.txt文件
        • can_fetch(User-agent, url):返回值为布尔类型,判断此user-agent是否可以爬取此url
        • mtime():返回值为上次抓取分析robots的时间
        • modified():将当前时间设置为上次抓取的时间
      from urllib import robotparser
      
      rp = robotparser.RobotFileParser()  # 实例化分析类
      rp.set_url("https://www.jd.com/robots.txt")  # 添加robots地址
      rp.read()  # 读取robot协议
      print(rp.can_fetch("*", "https://www.jd.com/")) # 判断当前爬虫是否可以爬取, True
      print(rp.mtime())  # 上次抓取的时间 1553685029.0578604
      print(rp.modified())  # 设置抓取的时间 none
      

    requests的使用

    1. 基本用法
      • Get请求 requests.get("url", "params", "headers")
        • url:请求资源的地址
        • params:传入的参数
        • headers:请求头,反扒的一种措施
      • Post请求 requests.post("url", "params", "headers")
        • url:请求资源的地址
        • params:传入的参数
        • headers:请求头,反扒的一种措施
      • 响应属性信息
        • text:返回的文本数据
        • content:二进制格式的数据,例如音频、视频、图片的
        • status_code:返回的状态码
        • headers:返回的响应头
        • cookies:cookies信息
        • url:请求的url信息
        • history: 请求历史
       import requests
      
       # get请求 requests.get(url, params, headers)
       url = "http://httpbin.org/get"  # 请求的url
       # 请求参数
       params = {
           "name":"Arale",
           "age":25
       }
       # 请求头
       headers = {
           "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36"
       }
       # 发送get请求,得到响应
       resp = requests.get(url, params=params, headers=headers)
       print(resp.url)  # 打印请求的url 参数在url http://httpbin.org/get?name=Arale&age=25
       
       # post请求 requests.post(url, data, headers)
       url = "http://httpbin.org/post"  # 请求的url
       # 发送post请求
       resp = requests.post(url, data=params, headers=headers)
       print(resp.url)  # 打印请求的url 参数在请求体中 http://httpbin.org/post
       
       # 响应属性方法
       print(resp.text)  # 打印str文本数据
       print(resp.content)  # 处理二进制数据,例如图片
       print(resp.url)  # http://httpbin.org/post
       print(resp.headers)  # {'Access-Control-Allow-Credentials': 'true', 'Access-Control-Allow-Origin': '*', 'Content-Encoding': 'gzip', 'Content-Type': 'application/json', 'Date': 'Thu, 28 Mar 2019 01:53:32 GMT', 'Server': 'nginx', 'Content-Length': '343', 'Connection': 'keep-alive'}
       print(resp.cookies)  # <RequestsCookieJar[]>
       print(resp.status_code)  # 200
       print(resp.history)  # []
      
    2. 高级用法
      • 上传文件
       # 上传文件
       files = {
           "file": open("01_urllib的使用.py", "rb")
       }
       resp = requests.post(url, files=files)  # 注意key必须为files否则报错
       print(resp.text)  # 返回内容会多一个files字段
      
      • cookies的使用
        • 以简书为例,写文章的页面需要登陆后才能看见,拿到网站登录后的cookie,再去请求,以达到维持登录状态的效果。
       # cookie的使用
       headers = {
           # 此cookie为登录网站后的cookie,
           "Cookie": "Hm_lvt_0c0e9d9b1e7d617b3e6842e85b9fb068=1553742403; sajssdk_2015_cross_new_user=1; locale=zh-CN; read_mode=day; default_font=font2; remember_user_token=W1sxMjE1NTM2Ml0sIiQyYSQxMSRmZEdzaHlpLnFsYnZpMG9PbFRQLk91IiwiMTU1Mzc0MjQxMC44MTg2OTc3Il0%3D--48708ad37562cd9a12cfaac066b92cc24e4305d3; _m7e_session_core=167a540dc0e51fd3bb10e0e502e174de; __yadk_uid=8uaAcl2jljk5KfYwGemwVKFoMN89sBuC; Hm_lpvt_0c0e9d9b1e7d617b3e6842e85b9fb068=1553742450; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%22169c243959d13-00d4259c8ce7dd-7a1b34-1296000-169c243959e606%22%2C%22%24device_id%22%3A%22169c243959d13-00d4259c8ce7dd-7a1b34-1296000-169c243959e606%22%2C%22props%22%3A%7B%7D%2C%22first_id%22%3A%22%22%7D",
           "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36",
           "Referer": "https://www.jianshu.com/writer"
       }
       url = "https://www.jianshu.com/writer#/notebooks/35136025/notes/43035331"
       resp = requests.get(url, headers=headers)
       print(resp.status_code)  # 设置cookie,可以访问需要登录才能看见的页面200
       # 查看cookie,并可以得到cookie的key value
       cookie = requests.get("https://www.baidu.com/").cookies
       print(cookie)
       for k, v in cookie.items():
           print(k + "=" + v)
      
      • session会话维持
        • Session():用来维持同一个会话,使用其实例化的对象进行请求
         # session:维持会话
          session = requests.Session()  # 实例化session类,使请求为同一示例,即维持同一会话
          session.get("https://www.httpbin.org/cookies/set/arale/123456")
          resp = session.get("https://www.httpbin.org/cookies")
          print(resp.text)
        
      • ssl证书认证
        • requests中有个参数verify,默认weiTrue,会自动验证网站的证书
        # ssl证书的验证,verify参数默认为True
          try:
              resp = requests.get("https://inv-veri.chinatax.gov.cn/")
              print(resp.status_code)  # requests.exceptions.SSLError会报错,默认会验证CA证书
          except Exception as e:
              # from requests.packages import urllib3
              # urllib3.disable_warnings()  # 忽略警告
              import logging
              logging.captureWarnings(True)  # 捕获警告到日志的方式忽略警告
              resp = requests.get("https://inv-veri.chinatax.gov.cn/", verify=False)  # 不去验证证书
              print(resp.status_code)
        
      • 代理的设置
      # 代理ip的设置
       proxies = {
           "http":"http://47.107.227.104:8888",
       }
       resp = requests.get("https://www.baidu.com/", proxies=proxies)
       print(resp.status_code)
      
      • 超时设置
      # 设置超时
       try:
           resp = requests.get("https://www.baidu.com/", timeout=0.001)
           print(resp.status_code)  # requests.exceptions.ConnectTimeout
       except Exception as e:
           print(e)
      
      • 身份认证
      # 传入auth=(元组)
      resp = requests.get("url", auth=("user", "pwd")
      
      • prepared requests对象
        • 引入Request对象
          s = requests.Session()  # 实例化session对象
          req = requests.Request("get", "https://www.baidu.com/")  # 构造请求对象 
          pre = s.prepare_request(req)  # 通过session准备请求数据
          resp = s.send(pre)  # 发送请求数据,返回响应
          print(resp.status_code)
        

    正则表达式

    • 常用方法
      • match(re, str):从开头开始匹配,如果开头不符合,则匹配失败
      • search(re,str):扫描整个字符串,返回第一个符合条件的结果,没有匹配到,则返回none
      • findall(re,str):查找整个字符串,返回所有匹配到的结果
      • sub(re,要替换的内容,str):替换匹配到的数据
      • compile(re):将匹配规则编译成正则表达式对象,以达到复用的效果
    • 返回结果为sre_match对象,有两个方法group()\span()
      • group():得到结果的内容
      • span():得到匹配到的范围,即结果字符串在原字符窜中的位置范围。
    • 分组:即字符串截取,用()包裹好想要提取的子字符串,调用group()方法,并传入分组索引即可得到,索引从1开始
    • 通用匹配:., . 表示除换行符之外的任意字符,表示匹配前面字符0或多个
    • 贪婪与非贪婪:.* 表示贪婪模式,会尽可能的匹配多个导致匹配结果不准确,.?表示非贪婪模式,尽可能匹配更少的,注意:非贪婪模式放在字符串结尾,可能会匹配不到*
    • 修饰符:第三个参数,做修饰用
      • re.S:表示匹配包括换行符在内的所有字符
      • re.I:表示对大小写不敏感
    • 转移符: \,用来转义特殊字符
    import re
    
    str = "Extra stings Hello 123456 world_This is a Regex Demo Exrea stings"
    
    # + 表示一个或多了
    # .*?表示非贪婪模式
    # \w{10}匹配字母数字下划线10个,{4,10}贪婪模式,会取10个
    # ()分组字符串提取
    result = re.match(r"^extra.*?(\d+)\s(\w{10})", str, re.I)
    
    print(result.group())  # 匹配结果的内容
    print(result.span())  # 结果字符串在原字符串中的位置范围
    print(result.group(1))  # 取出第一个分组结果
    print(result.group(2))
    

    爬取猫眼电影

    • 使用requests第三方库,请求网站,用正则解析页面,将解析结果写入excel
    import requests
    import re
    import time
    import xlwt
    
    
    # 爬取网页
    def get_page(url, headers):
        resp = requests.get(url, headers)
        return resp.text
    
    
    # 解析返回的结果
    def parse_res(res):
        '''<dd>
            <i class="board-index board-index-1">1</i>
            <a href="/films/1203" title="霸王别姬" class="image-link" data-act="boarditem-click" data-val="{movieId:1203}">
              <img src="//s0.meituan.net/bs/?f=myfe/mywww:/image/loading_2.e3d934bf.png" alt="" class="poster-default">
              <img data-src="https://p0.meituan.net/movie/223c3e186db3ab4ea3bb14508c709400427933.jpg@160w_220h_1e_1c" alt="乱世佳人" class="board-img" />
            </a>
            <div class="board-item-main">
              <div class="board-item-content">
                <div class="movie-item-info">
                    <p class="name"><a href="/films/1203" title="霸王别姬" data-act="boarditem-click" data-val="{movieId:1203}">霸王别姬</a></p>
                    <p class="star">
                        主演:张国荣,张丰毅,巩俐
                    </p>
                    <p class="releasetime">上映时间:1993-01-01</p>
                </div>
                <div class="movie-item-number score-num">
                    <p class="score">
                        <i class="integer">9.</i>
                        <i class="fraction">5</i>
                    </p>
                </div>
              </div>
            </div>
           </dd>
        '''
        par = re.compile(r'<dd>.*?'
                         r'<i.*?>(\d+)</i>'
                         r'.*?data-src="(.*?)"'
                         r'.*?class="name"><a .*?>(.*?)</a>'
                         r'.*?class="star">(.*?)</p>'
                         r'.*?releasetime">(.*?)</p>'
                         r'.*?class="integer">(.*?)</i>'
                         r'.*?class="fraction">(.*?)</i>'
                         r'.*?</dd>', re.S)
        items = re.findall(par, res)  # 返回list
        for item in items:
            # 利用生成器返回数据,或者构造元组,存放在list中用return返回
            # TODO 返回这样格式是写入excel需要
            yield [
                item[0],
                item[1],
                item[2],
                item[3].strip()[3:],
                item[4][5:],
                item[5]+item[6]
            ]
    
    
    # 写入文件
    def write_to_excel(items):
        # 创建一个excel
        excel = xlwt.Workbook()
        # 添加一个工作区
        sheet = excel.add_sheet("电影排名")
        # 构造表头信息
        head = ["序号", "海报", "名称", "主演", "上映时间", "评分"]
        # 将头部信息写入excel表头
        for index, value in enumerate(head):
            sheet.write(0, index, value)
        # 将内容写入excel
        for row, item in enumerate(items, 1):  # 行数据
            for col in range(0, len(item)):  # 列数据
                sheet.write(row, col, item[col])
    
        excel.save("./猫眼电影排名.xlsx")
    
    
    # 主程序入口
    def main(offset):
        url = "https://maoyan.com/board/4?offset=" + str(offset)
        headers = {
            "User-Agent": '''Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
                            AppleWebKit/537.36(KHTML, like Gecko) Chrome
                            /73.0.3683.75 Safari/537.36'''
        }
        res = get_page(url, headers)  # 请求url
        items = parse_res(res)  # 解析结果,返回生成器
        print(items.__next__())  # python3改为__next__(),之前版本为next()
        return items  # 返回解析后的结果,生成器
    
    
    
    if __name__ == "__main__":
        items = []
        offset = None
        for i in range(0, 10):
            item= main(i*10)  # 分页爬取
            items += list(item)  # 将每页结果进行拼接
            time.sleep(1)  # 每页休眠一秒钟,反扒措施
        write_to_excel(items)  # 将所有结果一次性写入文件,不一次一次写,因为会覆盖
    

    相关文章

      网友评论

          本文标题:03_基本库的使用

          本文链接:https://www.haomeiwen.com/subject/qncwbqtx.html