美文网首页
BeautifulSoup文档学习3-搜索文档树

BeautifulSoup文档学习3-搜索文档树

作者: JA_Cobra | 来源:发表于2020-03-13 12:09 被阅读0次

    搜索文档树

    示例文档

    >>> html_doc = """<html><head><title>睡鼠的故事</title></head>
    <body>
    <p class="title"><b>睡鼠的故事</b></p>
    
    <p class="story">从前有三位小姐姐,她们的名字是:
    <a href="http://example.com/elsie" class="sister" id="link1">埃尔西</a>,
    <a href="http://example.com/lacie" class="sister" id="link2">莱斯</a>和
    <a href="http://example.com/tillie" class="sister" id="link3">蒂尔莉</a>;
    她们住在一个井底下面。</p>
    
    <p class="story">...</p>
    """
    >>> from bs4 import BeautifulSoup
    >>> soup = BeautifulSoup(html_doc, 'html.parser')
    

    几种过滤器

    以下的过了长期贯穿了所有的搜索API函数,它们可以被使用在标签的名称、属性和文本这些上面

    字符串

    ​ 最简单的过滤器就是字符串,在搜索方法中传入一个字符串参数,BeautifulSoup会查找与字符串匹配的内容,下面的例子用于查找文档中的所有的<b>标签:

    >>> soup.find('b')
    <b>睡鼠的故事</b>
    

    ​ 如果传入的是字节码参数,BeautifulSoup将会假设这个编码为UTF-8编码,为了避免出错,可以直接传入一个Unicode编码

    正则表达式

    ​ 如果传入正则表达式作为参数,BeautifulSoup将会以正则表达式的match()方法来匹配内容。下面的示例中将找出所有以b开头的标签:

    >>> import re
    >>> for tag in soup.find_all(re.compile("^b")):
            print(tag.name)
    
    body
    b
    

    列表

    ​ 如果传入列表参数,BeautifulSoup会将与列表中的任意元素进行匹配,返回匹配的内容。。下面的代码可以找到文档中所有的<a><b>标签:

    >>> soup.find_all(["a", "b"])
    [<b>睡鼠的故事</b>, <a class="sister" href="http://example.com/elsie" id="link1">埃尔西</a>, <a class="sister" href="http://example.com/lacie" id="link2">莱斯</a>, <a class="sister" href="http://example.com/tillie" id="link3">蒂尔莉</a>]
    

    True

    Ture值可以匹配任意值,下面代码查找所有的标签,但是不会返回字符串的节点:

    >>> for tag in soup.find_all(True):
            print(tag.name)
    
    html
    head
    title
    body
    p
    b
    p
    a
    a
    a
    p
    

    函数

    如果没有适合的过滤器,可以自己定义一个函数,**该函数只接受一个元素作为参数**。如果这个方法返回`True`表示当前元素匹配并且被找到,否则返回`False`
    

    ​ 下面这个函数用于匹配那些包含class属性但不包含id属性的标签:

    >>> def has_class_but_no_id(tag):
            return tag.has_attr('class') and not tag.has_attr('id')
    

    ​ 将这个函数作为参数传入find_all()方法,将得到所有的<p>标签:

    >>> soup.find_all(has_class_but_no_id)
    [<p class="title"><b>睡鼠的故事</b></p>, <p class="story">从前有三位小姐姐,她们的名字是:
    <a class="sister" href="http://example.com/elsie" id="link1">埃尔西</a>,
    <a class="sister" href="http://example.com/lacie" id="link2">莱斯</a>和
    <a class="sister" href="http://example.com/tillie" id="link3">蒂尔莉</a>;
    她们住在一个井底下面。</p>, <p class="story">...</p>]
    

    ​ 返回结果中只有<p>标签没有<a>标签(上面出现的<a>是包含在<p>中的),因为<a>标签中还定义了id,没有返回<html><head>,因为<html><head>没有class属性。

    ​ 如果传入一个函数来过滤一个像href这样的特定属性,传入函数的参数将式属性值,而不是整个标签。下面的函数可以找到所有拥有href属性但不包含lacie字符串的标签:

    >>> def not_lacie(href):
            return href and not re.compile("lacie").search(href)
    
    >>> soup.find_all(href=not_lacie)
    [<a class="sister" href="http://example.com/elsie" id="link1">埃尔西</a>, <a class="sister" href="http://example.com/tillie" id="link3">蒂尔莉</a>]
    

    find_all()

    find_all(name, attrs, recrursive, string, limit, **kwargs)

    find_all()方法搜索当前tag下的所有子节点,并判断是否符合过滤器的条件。

    name参数

    ​ 通过name参数,可以指定名字来查找标签。最简单的用法如下:

    >>> soup.find_all("title")
    [<title>睡鼠的故事</title>]
    

    ​ 前面提过的过滤器的均可作为name参数的值:字符串、正则表达式、列表、函数或者一个布尔类型的值True

    keyword参数

    ​ 如果一个指定名字的参数不是搜索内置的(name, attrs, recursive, string, limit)参数名,搜索时会把该参数当做指定tag的属性来搜索。

    ​ 比如传入一个名为id的参数,BeautifulSoup将会搜索每一个tag的id属性:

    >>> soup.find_all(id="link2")
    [<a class="sister" href="http://example.com/lacie" id="link2">莱斯</a>]
    

    ​ 如果传入一个名为href的参数,BeautifulSoup将会搜索每个tag的href属性:

    >>> soup.find_all(href=re.compile("elsie"))
    [<a class="sister" href="http://example.com/elsie" id="link1">埃尔西</a>]
    

    ​ 搜索指定名字的属性时可以使用的参数值包括:字符串、正则表达式、列表、函数和True

    ​ 下面的例子在文档树中查找所有包含id属性的tag,无论id是什么值都会匹配:

    >>> soup.find_all(id=True)
    [<a class="sister" href="http://example.com/elsie" id="link1">埃尔西</a>, <a class="sister" href="http://example.com/lacie" id="link2">莱斯</a>, <a class="sister" href="http://example.com/tillie" id="link3">蒂尔莉</a>]
    

    注意:有些tag属性在搜索中不能使用,比如HTML5中的data-*属性。但是可以通过将这些属性放入一个字典中,然后传入attrs关键字参数来实现:

    >>> data_soup = BeautifulSoup('<div data-foo="value">foo!</div>', "html.parser")
    >>> data_soup.find_all(data-foo="value")
    SyntaxError: keyword can't be an expression
    
    >>> data_soup.find_all(attrs={"data-foo": "value"})
    [<div data-foo="value">foo!</div>]
    

    根据CSS进行搜索

    ​ 按照CSS类名搜索标签的功能非常实用,但由于表示CSS类名的关键字class在Python中是保留字,所以使用class作为参数会出错,在BS中可以通过class_参数搜索有指定CSS类名的标签:

    >>> soup.find_all("a", class_="sister")
    [<a class="sister" href="http://example.com/elsie" id="link1">埃尔西</a>, <a class="sister" href="http://example.com/lacie" id="link2">莱斯</a>, <a class="sister" href="http://example.com/tillie" id="link3">蒂尔莉</a>]
    

    ​ 根关键字参数一样,class_参数也支持不同类型的过滤器:字符串、正则表达式、函数或者True

    >>> soup.find_all(class_=re.compile("itl"))
    [<p class="title"><b>睡鼠的故事</b></p>]
    >>> 
    >>> def has_six_characters(css_class):
            return css_class is not None and len(css_class) == 6
    
    >>> soup.find_all(class_=has_six_characters)
    [<a class="sister" href="http://example.com/elsie" id="link1">埃尔西</a>, <a class="sister" href="http://example.com/lacie" id="link2">莱斯</a>, <a class="sister" href="http://example.com/tillie" id="link3">蒂尔莉</a>]
    

    注意

    • 标签的class属性支持同时有多个值,按照CSS类名搜索标签时,可以分别搜索表中的每一个CSS类名。

    • 搜索class属性时也可以指定完全匹配的CSS值

    • 如果CSS的值与文档的不一致,将会导致结果搜索不到

    • 如果希望搜索结果同时匹配两个以上的CSS类名,应该使用CSS选择器:

      >>> css_soup.select("p.strikeout.body")
      [<p class="body strikeout"></p>]
      

    string参数

    ​ 通过string参数可以搜索标签中的文本标签。与name参数一样,string参数接受字符串、正则表达式、列表、函数或者直接一个布尔类型值True

    示例

    >>> soup.find_all(string="埃尔西")
    ['埃尔西']
    >>> 
    >>> soup.find_all(string=["蒂尔莉", "埃尔西", "莱斯"])
    ['埃尔西', '莱斯', '蒂尔莉']
    >>> 
    >>> soup.find_all(string=re.compile("睡鼠"))
    ['睡鼠的故事', '睡鼠的故事']
    >>> 
    >>> def is_the_only_string_within_a_tag(s):
            """如果字符串是其父标签的唯一子节点,则返回 True。"""
            return (s == s.parent.string)
    
    >>> soup.find_all(string=is_the_only_string_within_a_tag)
    ['睡鼠的故事', '睡鼠的故事', '埃尔西', '莱斯', '蒂尔莉', '...']
    

    ​ 尽管string参数是用于搜索字符串的,但是可以与其他的参数混合起来使用,下面的代码BS会找到所有与string参数值相匹配的<a>标签:

    >>> soup.find_all("a", string="埃尔西")
    [<a class="sister" href="http://example.com/elsie" id="link1">埃尔西</a>]
    

    limit 参数

    find_all()方法返回匹配过滤器的所有标签和文本,如果文档树很大,搜索就会变得很慢,如果不想要全部的结果,可以使用limit参数进行限制返回结果的数量,当搜索到的结果数量达到了limit的限制时,就停止搜索并返回结果。

    ​ 文档树中有3个标签符合搜索结果,但是结果只返回2个,因为设置了limit参数:

    >>> soup.find_all("a", limit=2)
    [<a class="sister" href="http://example.com/elsie" id="link1">埃尔西</a>, <a class="sister" href="http://example.com/lacie" id="link2">莱斯</a>]
    

    recursive 参数

    ​ 如果调用mytag.find_all()方法,BS将会获取mytag的所有子孙节点,但是如果只是想搜索mytag的直接子节点,可以使用recursive=False参数,对比一下:

    >>> soup.html.find_all("title")
    [<title>睡鼠的故事</title>]
    >>> 
    >>> soup.html.find_all("title", recursive=False)
    []
    

    像调用find_all()一样调用一个标签

    ​ 由于 find_all()几乎是 BeautifulSoup 中最常用的搜索方法,所以我们为它定义了一种简写的形式:如果你将 BeautifulSoup对象或 Tag 对象当作一个方法来使用,那么这个方法的执行结果与调用这个对象的 find_all()方法是相同的。

    示例

    以下的代码是等价的:

    soup.find_all("a")
    soup("a")
    

    以下的代码也是等价的:

    soup.title.find_all(text=True)
    soup.title(text=True)
    

    find() 方法

    find_all(name, attrs, recursive, string, \**kwargs)

    find_all()方法返回结果是一个列表,而find()方法是直接返回结果。find_all()方法没有找到目标返回的是空列表,find()方法没有找到就返回None。

    CSS选择器

    BeautifulSoup中有一个select()方法,该方法使用SoupSieve对解析的文档运行CSS选择器并返回所有匹配的元素。

    ​ 可以使用CSS选择器的语法找到Tag:

    >>> soup.select("title")
    [<title>睡鼠的故事</title>]
     
    >>> soup.select("p:nth-of-type(3)")
    [<p class="story">...</p>]
    

    ​ 通过tag标签逐层查找:

    >>> soup.select("body a")
    [<a class="sister" href="http://example.com/elsie" id="link1">埃尔西</a>, <a class="sister" href="http://example.com/lacie" id="link2">莱斯</a>, <a class="sister" href="http://example.com/tillie" id="link3">蒂尔莉</a>]
    >>> soup.select("html head title")
    [<title>睡鼠的故事</title>]
    

    ​ 找到某个tag标签下的直接字标签:

    >>> soup.select("head > title")
    [<title>睡鼠的故事</title>]
     
    >>> soup.select("p > a")
    [<a class="sister" href="http://example.com/elsie" id="link1">埃尔西</a>, <a class="sister" href="http://example.com/lacie" id="link2">莱斯</a>, <a class="sister" href="http://example.com/tillie" id="link3">蒂尔莉</a>]
    >>> soup.select("p > a:nth-of-type(2)")
    [<a class="sister" href="http://example.com/lacie" id="link2">莱斯</a>]
    >>> soup.select("p > #link1")
    [<a class="sister" href="http://example.com/elsie" id="link1">埃尔西</a>]
    >>> soup.select("body > a")
    []
    

    ​ 找到兄弟节点:

    >>> soup.select("#link1 ~ .sister")
    [<a class="sister" href="http://example.com/lacie" id="link2">莱斯</a>, <a class="sister" href="http://example.com/tillie" id="link3">蒂尔莉</a>]
    >>> soup.select("#link1 + .sister")
    [<a class="sister" href="http://example.com/lacie" id="link2">莱斯</a>]
    

    ​ 通过CSS的类名查找:

    >>> soup.select(".sister")
    [<a class="sister" href="http://example.com/elsie" id="link1">埃尔西</a>, <a class="sister" href="http://example.com/lacie" id="link2">莱斯</a>, <a class="sister" href="http://example.com/tillie" id="link3">蒂尔莉</a>]
    >>> soup.select("[class~=sister]")
    [<a class="sister" href="http://example.com/elsie" id="link1">埃尔西</a>, <a class="sister" href="http://example.com/lacie" id="link2">莱斯</a>, <a class="sister" href="http://example.com/tillie" id="link3">蒂尔莉</a>]
    

    ​ 通过tag的ID查找:

    >>> soup.select("#link1")
    [<a class="sister" href="http://example.com/elsie" id="link1">埃尔西</a>]
    >>> soup.select("a#link2")
    [<a class="sister" href="http://example.com/lacie" id="link2">莱斯</a>]
    

    ​ 查找与选择器列表中的任何选择器匹配的tag:

    >>> soup.select("#link1,#link2")
    [<a class="sister" href="http://example.com/elsie" id="link1">埃尔西</a>, <a class="sister" href="http://example.com/lacie" id="link2">莱斯</a>]
    

    相关文章

      网友评论

          本文标题:BeautifulSoup文档学习3-搜索文档树

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