zoukankan      html  css  js  c++  java
  • 爬虫(三)—— BeautifulSoup模块获取元素

    BeautifulSoup

    一、BeautifulSoup简介

    Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库。它能够通过转换器实现惯用的文档导航、查找、修改文档的方式。Beautiful Soup 3 目前已经停止开发,官网推荐在现在的项目中使用Beautiful Soup 4, 移植到BS4。

    二、安装模块

    # 安装 Beautiful Soup
    pip install beautifulsoup4
    
    # 安装解析器
    pip install lxml
    

    三、解析器

    下表列出了主要的解析器,以及它们的优缺点,官网推荐使用lxml作为解析器,因为效率更高。 在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib, 因为那些Python版本的标准库中内置的HTML解析方法不够稳定。

    解析器使用方法优势劣势
    Python标准库 BeautifulSoup(markup, "html.parser")
    • Python的内置标准库
    • 执行速度适中
    • 文档容错能力强
    • Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差
    lxml HTML 解析器 BeautifulSoup(markup, "lxml")
    • 速度快
    • 文档容错能力强
    • 需要安装C语言库
    lxml XML 解析器

    BeautifulSoup(markup, ["lxml", "xml"])

    BeautifulSoup(markup, "xml")

    • 速度快
    • 唯一支持XML的解析器
    • 需要安装C语言库
    html5lib BeautifulSoup(markup, "html5lib")
    • 最好的容错性
    • 以浏览器的方式解析文档
    • 生成HTML5格式的文档
    • 速度慢
    • 不依赖外部扩展

    四、Beautiful Soup的使用

    html_doc = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title"><b>The Dormouse's story</b></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>
    """
    # 容错处理,文档的容错能力指的是在html代码不完整的情况下,使用该模块可以识别该错误。
    # 使用BeautifulSoup解析上述代码,能够得到一个 BeautifulSoup 的对象,并能按照标准的缩进格式的结构输出
    from bs4 import BeautifulSoup
    soup=BeautifulSoup(html_doc,'lxml') #具有容错功能
    res=soup.prettify() #处理好缩进,结构化显
    print(res)
    

    五、查找元素

    1、遍历文档树

    # 遍历文档树:即直接通过标签名字选择,特点是选择速度快,但如果存在多个相同的标签则只返回第一个
    html_doc = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b></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>
    """
    
    from bs4 import BeautifulSoup
    # 获取BeautifulSoup对象
    soup=BeautifulSoup(html_doc,'lxml')
    
    print(soup.p)     # 存在多个相同的标签则只返回第一个
    print(soup.a)     # 存在多个相同的标签则只返回第一个
    
    # 1. 获取标签的名称
    print(soup.p.name)
    
    # 2. 获取标签的属性
    print(soup.p.attrs)
    
    # 3. 获取标签的内容
    print(soup.p.string)     # p下的文本只有一个时,取到,否则为None
    print(soup.p.strings)      # 拿到一个生成器对象, 取到p下所有的文本内容,可以转换为list
    print(soup.p.text)       # 取到p下所有的文本内容
    for line in soup.stripped_strings:    # 去掉空白
        print(line)
    
    # 4. 嵌套选择
    print(soup.head.title.string)
    print(soup.body.a.string)
    
    
    # 5. 子节点、子孙节点
    print(soup.p.contents)      # p下所有子节点
    print(soup.p.children)      # 得到一个迭代器,包含p下所有子节点
    for i,child in enumerate(soup.p.children):
        print(i,child)
    
    print(soup.p.descendants) 	# 获取子孙节点,p下所有的标签都会选择出来
    for i,child in enumerate(soup.p.descendants):
        print(i,child)
    
    # 6. 父节点、祖先节点
    print(soup.a.parent)  		# 获取a标签的父节点
    print(soup.a.parents) 	    # 找到a标签所有的祖先节点,父亲的父亲,父亲的父亲的父亲...
    
    
    # 7. 兄弟节点
    print(soup.a.next_sibling) 		# 下一个兄弟
    print(soup.a.previous_sibling) 		# 上一个兄弟
    
    print(list(soup.a.next_siblings)) 		# 下面的兄弟们=>生成器对象
    print(soup.a.previous_siblings) 		# 上面的兄弟们=>生成器对象
    

    2、搜索文档树

    (1)五种过滤器

    字符串正则表达式列表True方法

    # 过滤器结合find() 和 find_all()方法使用查找元素
    html_doc = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b>
    </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>
    """
    
    from bs4 import BeautifulSoup
    soup=BeautifulSoup(html_doc,'lxml')
    
    # 1.字符串
    print(soup.find_all('b'))
    
    # 2.、正则表达式
    # 利用re.compile()使用正则
    import re
    print(soup.find_all(re.compile('^b')))   # 找出b开头的标签,结果有body和b标签
    
    # 3.列表:
    # 如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回.下面代码找到文档中所有<a>标签和<b>标签:
    print(soup.find_all(['a','b']))
    
    # 4.True
    # 可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点
    print(soup.find_all(True))
    for tag in soup.find_all(True):
        print(tag.name)
    
    # 5.方法
    # 如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数 ,如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则反回 False
    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))
    
    # 匿名函数
    print(soup.find_all(lambda tag: True if tag.has_attr("class") and tag.has_attr("id") else False))
    

    (2)find_all( name , attrs , recursive , text , **kwargs )

    # 1、name: 搜索name参数的值可以使任一类型的 过滤器 ,字符窜,正则表达式,列表,方法或是 True .
    print(soup.find_all(name=re.compile('^t')))
    
    # 2、keyword: key=value的形式,value可以是过滤器:字符串 , 正则表达式 , 列表, True .
    print(soup.find_all(id=re.compile('my')))
    print(soup.find_all(href=re.compile('lacie'),id=re.compile('d'))) #注意类要用class_
    print(soup.find_all(id=True))    # 查找有id属性的标签
    
    # 有些tag属性在搜索不能使用,比如HTML5中的 data-* 属性:
    data_soup = BeautifulSoup('<div data-foo="value">foo!</div>','lxml')
    # data_soup.find_all(data-foo="value") #报错:SyntaxError: keyword can't be an expression
    # 但是可以通过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的tag:
    print(data_soup.find_all(attrs={"data-foo": "value"}))
    # [<div data-foo="value">foo!</div>]
    
    # 3、按照类名查找,注意关键字是class_,class_=value,value可以是五种选择器之一
    print(soup.find_all('a',class_='sister')) #查找类为sister的a标签
    print(soup.find_all('a',class_='sister ssss')) #查找类为sister和sss的a标签,顺序错误也匹配不成功
    print(soup.find_all(class_=re.compile('^sis'))) #查找类为sister的所有标签
    
    # 4、attrs
    print(soup.find_all('p',attrs={'class':'story'}))
    
    # 5、text: 值可以是:字符,列表,True,正则
    print(soup.find_all(text='Elsie'))
    print(soup.find_all('a',text='Elsie'))
    
    # 6、limit参数:如果文档树很大那么搜索会很慢.如果我们不需要全部结果,可以使用 limit 参数限制返回结果的数量.效果与SQL中的limit关键字类似,当搜索到的结果数量达到 limit 的限制时,就停止搜索返回结果
    print(soup.find_all('a',limit=2))
    
    # 7、recursive:调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False
    print(soup.html.find_all('a'))
    print(soup.html.find_all('a',recursive=False))
    

    (3)find( name , attrs , recursive , text , **kwargs )

    唯一的区别是 find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回结果.
    find_all() 方法没有找到目标是返回空列表, find() 方法找不到目标时,返回 None .
    print(soup.find("nosuchtag"))
    # None
    
    soup.head.title 是 tag的名字 方法的简写.这个简写的原理就是多次调用当前tag的 find() 方法
    

    (4)CSS选择器(select('.class'))

    #该模块提供了select方法来支持css,详见官网:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#id37
    html_doc = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title">
        <b>The Dormouse's story</b>
        Once upon a time there were three little sisters; and their names were
        <a href="http://example.com/elsie" class="sister" id="link1">
            <span>Elsie</span>
        </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>;
        <div class='panel-1'>
            <ul class='list' id='list-1'>
                <li class='element'>Foo</li>
                <li class='element'>Bar</li>
                <li class='element'>Jay</li>
            </ul>
            <ul class='list list-small' id='list-2'>
                <li class='element'><h1 class='yyyy'>Foo</h1></li>
                <li class='element xxx'>Bar</li>
                <li class='element'>Jay</li>
            </ul>
        </div>
        and they lived at the bottom of a well.
    </p>
    <p class="story">...</p>
    """
    from bs4 import BeautifulSoup
    soup=BeautifulSoup(html_doc,'lxml')
    
    # 1. CSS选择器
    # select 返回的是一个列表
    print(soup.p.select('.sister'))
    print(soup.select('.sister span'))
    print(soup.select('#link1'))
    print(soup.select('#link1 span'))
    print(soup.select('#list-2 .element.xxx'))
    
    print(soup.select('#list-2')[0].select('.element'))  # 可以一直select,但其实没必要,一条select就可以了
    
    # 2. 获取属性
    print(soup.select('#list-2 h1')[0].attrs)
    
    # 3. 获取内容
    print(soup.select('#list-2 h1')[0].get_text())
    
  • 相关阅读:
    Java RunTime Environment (JRE) or Java Development Kit (JDK) must be available in order to run Eclipse. ......
    UVA 1597 Searching the Web
    UVA 1596 Bug Hunt
    UVA 230 Borrowers
    UVA 221 Urban Elevations
    UVA 814 The Letter Carrier's Rounds
    UVA 207 PGA Tour Prize Money
    UVA 1592 Database
    UVA 540 Team Queue
    UVA 12096 The SetStack Computer
  • 原文地址:https://www.cnblogs.com/linagcheng/p/10311181.html
Copyright © 2011-2022 走看看