• 爬虫(第二部分)


                          爬虫总结02(爬虫解析器:正则,xpath,BS)
    一:常用正则表达式解析
      单字符:
            . : 除换行以外所有字符
            [] :[aoe] [a-w] 匹配集合中任意一个字符
            d :数字  [0-9]
            D : 非数字
            w :数字、字母、下划线、中文
            W : 非w
            s :所有的空白字符包,括空格、制表符、换页符等等。等价于 [ f
    
    	v]。
            S : 非空白
        数量修饰:
            * : 任意多次  >=0
            + : 至少1次   >=1
            ? : 可有可无  0次或者1次
            {m} :固定m次 hello{3,}
            {m,} :至少m次
            {m,n} :m-n次
        边界:
            $ : 以某某结尾
            ^ : 以某某开头
        分组:
            (ab)
        贪婪模式: .*
        非贪婪(惰性)模式: .*?
    
        re.I : 忽略大小写
        re.M :多行匹配
        re.S :单行匹配
    
        re.sub(正则表达式, 替换内容, 字符串)

    二:xpath解析

      01:测试html数据:

    <html lang="en">
            <head>
                <meta charset="UTF-8" />
                <title>测试bs4</title>
            </head>
            <body>
                <div>
                    <p>百里守约</p>
                </div>
                <div class="song">
                    <p>李清照</p>
                    <p>王安石</p>
                    <p>苏轼</p>
                    <p>柳宗元</p>
                    <a href="http://www.song.com/" title="赵匡胤" target="_self">
                        <span>this is span</span>
                    宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a>
                    <a href="" class="du">总为浮云能蔽日,长安不见使人愁</a>
                    <img src="http://www.baidu.com/meinv.jpg" alt="" />
                </div>
                <div class="tang">
                    <ul>
                        <li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li>
                        <li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li>
                        <li><a href="http://www.126.com" alt="qi">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li>
                        <li><a href="http://www.sina.com" class="du">杜甫</a></li>
                        <li><a href="http://www.dudu.com" class="du">杜牧</a></li>
                        <li><b>杜小月</b></li>
                        <li><i>度蜜月</i></li>
                        <li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li>
                    </ul>
                </div>
            </body>
            </html>
    

      02:常用xpath表达式及符号说明:‘/’ 取文本

    属性定位:
        #找到class属性值为song的div标签
        //div[@class="song"]
    层级&索引定位:
        #找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a
        //div[@class="tang"]/ul/li[2]/a
    逻辑运算:
        #找到href属性值为空且class属性值为du的a标签
        //a[@href="" and @class="du"]
    模糊匹配:
        //div[contains(@class, "ng")]
        //div[starts-with(@class, "ta")]
    取文本:
        # /表示获取某个标签下的文本内容
        # //表示获取某个标签下的文本内容和所有子标签下的文本内容
        //div[@class="song"]/p[1]/text()
        //div[@class="tang"]//text()
    取属性:
        //div[@class="tang"]//li[2]/a/@href
    03:基本操作:
    #第一部导安装模块
     pip3 install lxml
    #第二步:测试前先倒入模块
     from lxml import etree
    
    使用的基本原理:将html文件文档转换成一个etree 对象,然后调用这个对象指定的方法来查找指定的节点
    方法一:
        tree=etree.HTML(doc)   #用网络数据转换成对象
    方法02:用读取本地文件转换成对象
        tree=etree.parse("test.html")
        print(">>",tree)  # <lxml.etree._ElementTree object at 0x0000002F7C68E708>

      操作例子:

    001: ret=tree.xpath("//a[@id='feng']/text()")
         print(ret) # ['凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘']
    
    002: ret=tree.xpath("//a[@id='feng']/@href")
         a标签下 id值为feng下的链接--> ['http://www.haha.com']
    
    003: ret=tree.xpath("//div[@class='tang']/ul/li/a/@href")
         ['http://www.baidu.com', 'http://www.163.com', 'http://www.126.com', 'http://www.sina.com', 'http://www.dudu.com', 'http://www.haha.com']
    
    004: ret=tree.xpath("//div[@class='tang']/ul/li/b/text()")  # ['杜小月']
         ret=tree.xpath("//a[@class='du' and @href='']/text()")  #['总为浮云能蔽日,长安不见使人愁']
    
    005: ret=tree.xpath("//a[@title='qin']/text()")
         ['秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山']
    
    006: ret=tree.xpath("//a[starts-with(@title,'qin')]/text()")
         ['清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村', '秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山']
         print(ret)
    三:BS解析(Beautiful Soup)
    ps: Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过    你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.
    Beautiful Soup会帮你节省数小时甚至数天的工作时间.你可能在寻找 Beautiful Soup3 的文档,Beautiful Soup 3 目前已经停止开发,
    官网推荐在现在的项目中使用Beautiful Soup 4

    01:安装BS

     pip3 install beautifusoup4

    02:解析器

     001:Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,如果我们不安装它,则 Python 会使用 Python默认的解析器,
            lxml 解析器更加强大,速度更快,推荐安装。
    
     002:另一个可供选择的解析器是纯Python实现的 html5lib , html5lib的解析方式与浏览器相同,可以选择下列方法来安装html5lib:
            pip3 install html5lib

    03:BS的使用方法:

     001:使用方法:
            a:导包:from bs4 import BeautifulSoup
            b:可以将一个本地的html文档或者网络的文件转换成一个BeautifuSoup对象,通过操作对象的属性方法来查找指定的节点内容
               --soup=BeautifulSoup(open("test.html(本地文件)","lxml")) 或者soup=BeautifulSoup("doc(网络数据)","lxml")
    
     002:打印soup对象内容为html文件中的内容
    04:BS的基本语法
      soup=BeautifulSoup(open("test.html)(本地文件)","lxml")
        (1)根据标签名查找
            - soup.a   只能找到第一个符合要求的标签
    
        (2)获取属性
            - soup.a.attrs  获取a所有的属性和属性值,返回一个字典
            - soup.a.attrs['href']   获取href属性
            - soup.a['href']   也可简写为这种形式
    
        (3)获取内容
            - soup.a.string
            - soup.a.text
            - soup.a.get_text()
            -【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容
    
        (4)find:找到第一个符合要求的标签
            - soup.find('a')  找到第一个符合要求的
            - soup.find('a', title="xxx")
            - soup.find('a', alt="xxx")
            - soup.find('a', class_="xxx")
            - soup.find('a', id="xxx")
    
        (5)find_all:找到所有符合要求的标签
            - soup.find_all('a')
            - soup.find_all(['a','b']) 找到所有的a和b标签
            - soup.find_all('a', limit=2)  限制前两个
    
        (6)根据选择器选择指定的内容
            - select:soup.select('#feng')
            - 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器
            - 层级选择器:
            div .dudu #lala .meme .xixi  下面好多级
            div > p > a > .lala          只能是下面一级
            【注意】select选择器返回永远是列表,需要通过下标提取指定的对象

    五:BS解析的语法案例操作

    案例源码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div class="c1">
       <!--<p>123</p>-->
       <!--<p>345</p>-->
       <div>
    
        </div>
    </div>
    <div>
    <p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b><span>123</span></p>
    <p class="story">Once upon a time there were three little sisters; and their names were
    <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>
    
    <p class="story">...</p>
    </div>
    </body>
    </html>
    
    案例代码
    View Code  
    
    
      ps重点:soup.p.text和soup.p.string的区别:
      例子:<p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b><span>123</span></p>
      print(soup.p.string)  # None
      print(soup.p.text)  # The Dormouse's story123
    
      >>总结:string在一个标签里面再套上其他标签的时候,只会打印None,text不管一个标签里面套上多少个标签,
         都会将这个标签里面所有的文本取出来
    操作步骤:  
    第一步:先导包,实例化一个对象出来
    from bs4 import BeautifulSoup
    实例化对象的两种方法:
    方法01:soup = BeautifulSoup(open("test00.html"), "lxml")
    方法02:# soup = BeautifulSoup(html_doc, "lxml")

     实际操作案例:

    01:Tag对象的操作
        001:查找第一个a标签
            print(">>", soup.a)  # <a>111</a>
            print(">>", soup.a.attrs)  # {'class': ['a1']}
    
    02:Tag对象的属性操作
        001:soup.a标签的类型:
            print("type是>>", type(soup.a))  # <class 'bs4.element.Tag'>
        002:Tag对象的属性操作
            print(soup.a.attrs["href"])  # 这个标签对象的链接 http://example.com/elsie
        003:Tag对象标签的class名
            print(soup.a.attrs["class"])  # ['sister']
        004:找出这个标签的id名字
            print(soup.a.attrs["id"])  # link1
        总结:----〉标签对象的属性操作的简单写法
            print(">>", soup.a["href"])  # http://example.com/elsie
    
    03:Tag对象的文本操作
        print(soup.a.text)  # Elsie
        print(soup.a.get_text())  # Elsie 对象有get方法
        print(soup.a.string)  # Elsie  #
    
    04:对象的find()和find_all()操作(find和find_all的详解(两者的参数说明是一样的,这里只取了find_all()为例子))
        01:find_all()  #找到文本中所有的 指定标签
          001:4种name参数过滤器
            第一种:
                例子01:
                ls = soup.find_all("a")  #name="a"
                print("ls>>", ls)  #结果是一个列表,可以进行循环
            第二种:
                例子02:
                ls = soup.find_all(["a", "p"])  # 找出所有的a标签和p标签 name=["a","p"]
                print(">>>++", ls)  # 结果是一个列表,可以进行循环
            第三种:
                例子03:
                import re
                print(">>>?",soup.find_all(re.compile("^b"))) #找出文本中所有以b开头的标签,body标签会被找出来,结果是一个列表
    
            第四种:
                例子04:
                def has_class_but_no_id(tag):
                    return tag.has_attr('class') and not tag.has_attr('id')
                print("...",soup.find_all(has_class_but_no_id)) # name=has_class_but_no_id
    
          002:attrs属性参数过滤器
            print(soup.find_all("a", attrs={"class": "sister","id": "link1"}))#[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
            属性参数过滤简写:
            print(soup.find_all("a",id="link3")) #[<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
    
          003:text文本参数过滤
            print(soup.find_all("a",text="Tillie")) #[<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
    
          004:limit参数
            print(soup.find_all("a",limit=2))  #只找文本中的前2个a标签
    
          005:recursive参数(递归)
            print("True>>",soup.find_all("a",recursive=True))  #recursive 深度可以一直找下去,直到找完文本中所有的a标签
            print("False",soup.find_all("a",recursive=False)) # 深度为零
    
          006:recursive深度产生局部查询
    
            案例01:找第一个div标签内部所有的标签,recurs默认是True,所以会将recursive内部所有同级的标签以及同级标签的字标签全部找出来
            print(soup.div.find_all())
    
            案例02:recursive设置为False,则找出第一个div标签内部所有的同级标签,同级标签的字标签不会被找出来
            print("recursive>>>>",soup.div.find_all(recursive=False))  #找第一个div标签内部
    
    04:selector操作
        ps:selector的标签查找操作和css选择器一样
     
  • 相关阅读:
    欧几里德算法
    int 和 string 相互转换(简洁版)
    骆驼吃香蕉
    链表反转 (Multi-method)
    二分查找 (最经典代码,及其边界条件的实践分析)
    mottoes
    欧拉函数,欧拉定理,费马小定理。
    深搜和广搜的对比
    Python基础
    马拉车求最大回文字串
  • 原文地址:https://www.cnblogs.com/one-tom/p/10457840.html
Copyright © 2020-2023  润新知