翼度科技»论坛 编程开发 python 查看内容

BeautifulSoup(bs4)细致讲解

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
BeautifulSoup(bs4)

BeautifulSoup是python的一个库,最主要的功能是从网页爬取数据,官方是这样解释的:BeautifulSoup提供一些简单,python式函数来处理导航,搜索,修改分析树等功能,其是一个工具库,通过解析文档为用户提供需要抓取的数据,因为简单,所有不需要多少代码就可以写出一个完整的程序
bs4安装

直接使用pip install命令安装
  1. pip install beautifulsoup4
复制代码
lxml解析器

lxml是一个高性能的Python库,用于处理XML与HTML文档,与bs4相比之下lxml具有更强大的功能与更高的性能,特别是处理大型文档时尤为明显.lxml可以与bs4结合使用,也可以单独使用
lxml安装

同样使用pip install 安装
  1. pip install lxml
复制代码
其用于在接下来会结合bs4进行讲解
BeautifulSoup浏览浏览器结构化方法


  • .title:获取title标签
    1. html_doc="""....
    2. """"
    3. # 创建beautifulsoup对象 解析器为lxml
    4. soup = BeautifulSoup(html_doc, 'lxml')
    5. print(soup.title)
    6. #output-><title>The Dormouse's story</title>
    复制代码
  • .name获取文件或标签类型名称
    1. soup = BeautifulSoup(html_doc, 'lxml')
    2. print(soup.title.name)
    3. print(soup.name)
    4. #output->title
    5. #[document]
    复制代码
  • .string/.text:获取标签中的文字内容
    1. soup = BeautifulSoup(html_doc, 'lxml')
    2. print(soup.title.string)
    3. print(soup.title.text)
    4. #output->The Dormouse's story
    5. #The Dormouse's story
    复制代码
  • .p:获取标签
    1. soup = BeautifulSoup(html_doc, 'lxml')
    2. print(soup.p)
    3. #output-><p ><b>The Dormouse's story</b></p>
    复制代码
  • .find_all(name,attrs={}):获取所有标签,参数:标签名,如’a’a标签,’p’p标签等等,attrs={}:属性值筛选器字典如attrs={'class': 'story'}
    1. # 创建beautifulsoup对象 解析器为lxml
    2. soup = BeautifulSoup(html_doc, 'lxml')
    3. print(soup.find_all('p'))
    4. print(soup.find_all('p', attrs={'class': 'title'}))
    复制代码
  • .find(name,attrs={}):获取第一次匹配条件的元素
    1. soup = BeautifulSoup(html_doc, 'lxml')
    2. print(soup.find(id="link1"))
    3. #output-><a  target="_blank" href="https://example.com/elsie" id="link1">Elsie</a>
    复制代码
  • .parent:获取父级标签
    1. soup = BeautifulSoup(html_doc, 'lxml')
    2. print(soup.title.parent)
    3. #output-><head><title>The Dormouse's story</title></head>
    复制代码
  • .p['class'] :获取class的值
    1. soup = BeautifulSoup(html_doc, 'lxml')
    2. print(soup.p["class"])
    3. #output->['title']
    复制代码
  • .get_text():获取文档中所有文字内容
    1. soup = BeautifulSoup(html_doc, 'lxml')
    2. print(soup.get_text())
    3. The Dormouse's story
    4. The Dormouse's story
    5. Once upon a time there were three little sisters; and their names were
    6. Elsie,
    7. Lacie and
    8. Tillie;
    9. and they lived at the bottom of a well.
    10. ...
    复制代码
  • 从文档中找到所有标签的链接
    1. a_tags = soup.find_all('a')
    2. for a_tag in a_tags:
    3.     print(a_tag.get("href"))
    4. #output->https://example.com/elsie
    5. #https://example.com/lacie
    6. #https://example.com/tillie
    复制代码
BeautifulSoup的对象种类

当你使用BeautifulSoup 解析一个HTML或XML文档时,BeautifulSoup会整个文档转换为一个树形结构,其中每个结点(标签,文本,注释)都被表示为一个python对象
BeautifulSoup的树形结构

在HTML文档中,根结点通常是标签,其余的标签和文本内容则是其子结点
若有以下一个HTML文档:
  1. <html>
  2.     <head>
  3.         <title>The Dormouse's story</title>
  4.     </head>
  5.     <body>
  6.         <h1>The Dormouse's story</h1>
  7.         <p>Once upon a time...</p>
  8.     </body>
  9. </html>
复制代码

  • 经过BeautifulSoup的解析后,是根结点,与相邻的与是其子结点,同理可得是子结点,
    是子结点
对象类型

BeautifulSoup有四种主要类型,Tag,NavigableString,BeautifulSoup,Comment
Tag

Tag对象与HTML或XML原生文档中的标签相同,每个Tag对象都可以包含其他标签,文本内容和属性
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. tag = soup.title
  3. print(type(tag))
  4. #output-><class 'bs4.element.Tag'>
复制代码
NavigableString

NavigableString对象表示标签内的文本内容,是一个不可变字符串,可以提供Tag对象的.string获取
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. tag = soup.title
  3. print(type(tag.string))
  4. #output-> <class 'bs4.element.NavigableString'>
复制代码
BeautifulSoup

BeautifulSoup对象表示整个文档的内容.其可以被视为一个特殊的Tag对象,但没有名称与属性.其提供了对整个文档的遍历,搜索和修改的功能
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. print(type(soup))
  3. #output-> <class 'bs4.BeautifulSoup'>
复制代码
Comment

Comment对象是一个特殊类型的NavigableString对象,表示HTML和XML中的注释部分
  1. # <b></b>
  2. soup = BeautifulSoup(html_doc, 'lxml')
  3. print(type(soup.b.string))
  4. #output-> <class 'bs4.element.NavigableString'>
复制代码
BeautifulSoup遍历文档树

BeautifulSoup提供了许多方法来遍历解析后的文档树
导航父节点


  • .parent与.parents:.parent可以获取当前节点的上一级父节点,.parents可以遍历获取当前节点的所有父辈节点
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. title_tag = soup.title
  3. print(title_tag.parent)
  4. #<head><title>The Dormouse's story</title></head>
复制代码
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. body_tag = soup.body
  3. for parent in body_tag.parents:
  4.     print(parent)
  5. #<html><head><title>The Dormouse's story</title></head>
  6. #<body>
  7. #<p ><b>The Dormouse's story</b></p>
  8. #<p >Once upon a time there were three little sisters; and their names were
  9. #<a  target="_blank" href="https://example.com/elsie" id="link1">Elsie</a>,
  10. #....
复制代码
导航子结点


  • .contents:可以获取当前结点的所有子结点
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. head_contents = soup.head.contents
  3. print(head_contents)
  4. #output-> [<title>The Dormouse's story</title>]
复制代码

  • .children:可以遍历当前结点的所有子结点,返回一个list
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. body_children = soup.body.children
  3. for child in body_children:
  4.     print(child)
  5. #output-><p ><b>The Dormouse's story</b></p>
  6. #<a  target="_blank" href="https://example.com/elsie" id="link1">Elsie</a>,
  7. #<a  target="_blank" href="https://example.com/tillie" id="link3">Tillie</a>;
  8. #and they lived at the bottom of a well.</p>
  9. #.....
复制代码

  • 字符串没有.children与.contents属性
导航所有后代节点

.contents与.children属性仅包含tag直接子结点,例如标签只有一个直接子结点
  1. #[<title>The Dormouse's story</title>]
复制代码
但标签也包含一个子结点:字符串”The Dormouse's story”,字符串”The Dormouse's story”是标签的子孙结点

  • .descendants属性可以遍历当前结点的所有后代结点(层遍历)
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. for descendant in soup.descendants:
  3.     print(descendant)
复制代码
节点内容


  • .string

    • 如果tag只有一个NavigableString类型子节点,那么这个tag可以使用.string得到其子节点.
      1. soup = BeautifulSoup(html_doc, 'lxml')
      2. print(soup.head.string)
      3. #The Dormouse's story
      4. print(soup.title.string)
      5. #The Dormouse's story
      复制代码
    • 但若tag中包含了多个子节点,tag就无法确定string方法应该调用哪一个字节的内容,则会输出None
      1. soup = BeautifulSoup(html_doc, 'lxml')
      2. print(soup.body.string)
      3. #None
      复制代码

  • .strings和.stripped_strings

    • .strings可以遍历获取标签中的所有文本内容,.stripped_strings可以除去多余的空白字符
    1. soup = BeautifulSoup(html_doc, 'lxml')
    2. for string in soup.strings:
    3.     print(string)
    4. #The Dormouse's story
    5. ......
    6. #The Dormouse's story
    复制代码
    1. soup = BeautifulSoup(html_doc, 'lxml')
    2. for string in soup.stripped_strings:
    3.     print(string)
    4. #The Dormouse's story
    5. #The Dormouse's story
    6. #Once upon a time there were three little sisters; and their names were
    7. #Elsie
    8. #,
    9. ...
    复制代码
BeautifulSoup搜索文档树

BeautifulSoup提供了多种方法来搜索解析后的文档树
find_all(name , attrs , recursive , string , **kwargs)


  • find_all()方法搜索当前tag的所有tag子节点
  1. soup = BeautifulSoup(html_doc, 'lxml')print(soup.find_all("title"))  # 查找所有的title标签print(soup.find_all("p", "title"))  # 查找p标签中class为title的标签print(soup.find_all("a"))  # 查找所有的a标签print(soup.find_all(id="link2"))  # 查找id为link2的标签#[<title>The Dormouse's story</title>]#[[b]The Dormouse's story[/b]
  2. ]#[[url=https://example.com/elsie]Elsie[/url], [url=https://example.com/lacie]Lacie[/url], [url=https://example.com/tillie]Tillie[/url]]#[[url=https://example.com/lacie]Lacie[/url]]
复制代码
接下来我们来详细解析一下每个参数的含义
name参数

name参数可以查找所有名字为name的tag,字符串对象名字会自动被忽略


  • eg
    1. soup.find_all("title")
    2. # [<title>The Dormouse's story</title>]
    复制代码
  • name参数可以为任意类型的过滤器,如字符串,正则表达式,列表,方法等等
  • 传字符串
    传入字符串是最简单的过滤器,在搜索方法中传入一个字符串参数,BeautifulSoup会查找与字符串匹配的内容


    • 下面的例子用于查找文档中所有的<b>标签
    1. soup.find_all('b')
    2. # [<b>The Dormouse's story</b>]
    复制代码
  • 传入正则表达式
    若传入正则表达式作为参数,BeautifulSoup会通过正则表达式match()来匹配内容


    • 查找b开头的标签,这表示和<b>标签都应该被找到
    1. soup = BeautifulSoup(html_doc, 'lxml')
    2. for tag in soup.find_all(re.compile("^b")):
    3.     print(tag.name)
    4. # body
    5. # b
    复制代码
  • 传入列表
    如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回


    • 找到文档中所有标签和<b>标签
    1. soup = BeautifulSoup(html_doc, 'lxml')
    2. for tag in soup.find_all(['a', 'b']):
    3.     print(tag.name)
    4. #b
    5. #a
    6. #a
    7. #a
    8. #b
    复制代码
**kwargs参数

在BeautifulSoup中,**kwargs(即关键字参数)可用于通过标签的属性来查找特定的标签.这些关键字参数可以直接传递给find,find_all方法,使得搜索更加强大.标签的属性名作为关键字参数,值可以是字符串、正则表达式或列表
使用字典


  • 可以使用key=’word’传入参数
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. print(soup.find_all(id='link1'))
  3. #[<a  target="_blank" href="https://example.com/elsie" id="link1">Elsie</a>]
复制代码
使用正则表达式


  • 使用Python的re模块中的正则表达式来匹配属性值,使搜索更灵活
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. print(soup.find_all('a', href=re.compile("elsie")))  # 查找href属性中包含elsie的a标签
  3. print(soup.find_all(string=re.compile("^The")))  # 查找文本中The开头的标签
  4. #[<a  target="_blank" href="https://example.com/elsie" id="link1">Elsie</a>]
  5. #["The Dormouse's story", "The Dormouse's story"]
复制代码
使用列表


  • 可以传递一个列表作为关键字参数的值.BeautifulSoup会匹配列表中的任意一个值
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. print(soup.find('a', id=['link1', 'link2']))  # 查找id为link1或者link2的a标签
  3. print(soup.find_all(class_=['sister', 'story']))  # 查找class为sister或者story的标签
  4. #<a  target="_blank" href="https://example.com/elsie" id="link1">Elsie</a>
  5. #[<p >Once upon a time there were three little sisters; and their names were
  6. #...
复制代码
特殊属性名称

HTML的属性名称与Python的保留字冲突,为了防止冲突,BeautifulSoup提供了一些特殊的替代名称


  • class_:用于匹配class属性
  • data-*:用于匹配自定义的data-*属性
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. print(soup.find_all('p', class_="title"))  # 查找所有class为title的p标签
  3. print(soup.find_all('p', attrs={'data-p', 'story'}))  # 查找所有class为story的p标签
  4. #[<p ><b>The Dormouse's story</b></p>]
  5. #[<p >Once upon a time there were three little sisters; and their names were
  6. #<a  target="_blank" href="https://example.com/elsie" id="link1">Elsie</a>,
  7. #<a  target="_blank" href="https://example.com/lacie" id="link2">Lacie</a> and
复制代码
text/string参数

text/string参数允许操作者根据标签的文本内容进行搜索,与name参数类似,text参数也支持多种类型的值,包括正则表达式,字符串列表和True,早期bs4支持text,近期bs4将text都改为string
使用字符串匹配

你可以直接传递一个字符串作为 string参数的值,BeautifulSoup 会查找所有包含该字符串的标签
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. print(soup.find_all(string='Elsie'))
  3. #['Elsie']
复制代码
使用正则表达式匹配
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. print(soup.find_all(string=re.compile('sister'), limit=2))  # 查找前两个包含sister的字符串
  3. print(soup.find_all(string=re.compile('Dormouse')))  # 查找包含Dormouse的字符串
  4. #['Once upon a time there were three little sisters; and their names were\n']
  5. #["The Dormouse's story", "The Dormouse's story"]
复制代码
使用列表匹配
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. print(soup.find_all(string=['Elsie', 'Lacie', 'Tillie']))
  3. #['Elsie', 'Lacie', 'Tillie']
复制代码
limit参数

BeautifulSoup中的limit参数用于限制find_all方法结果的返回数量,当只需要查询前几个标签时,使用limit参数可以提高搜索搜索效率,效果与SQL中的limit关键字类似,当搜索到的结果数量达到 limit 的限制时,就停止搜索返回结果
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. print(soup.find_all('a', limit=2))  # 查找所有a标签,限制输出2个
  3. #[<a  target="_blank" href="https://example.com/elsie" id="link1">Elsie</a>, <a  target="_blank" href="https://example.com/lacie" id="link2">Lacie</a>]
复制代码
find_parents() 和 find_parent()

BeautifulSoup 提供了 find_parents() 和 find_parent() 方法,用于在解析后的文档树中向上查找父标签.两个方法的主要区别在于返回的结果数量


  • find_parent(name=None, attrs={}, **kwargs):只返回最接近的父标签(即第一个匹配的父标签)
  • find_parents(name=None, attrs={}, limit=None, **kwargs):返回所有符合条件的祖先标签,按从近到远的顺序排列
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. a_string = soup.find(string='Lacie')
  3. print(a_string.find_parent())  # 查找父节点
  4. print('-----------------')
  5. print(a_string.find_parents())  # 查找所有父节点
  6. #<a  target="_blank" href="https://example.com/lacie" id="link2">Lacie</a>
  7. #-----------------
  8. #[<a  target="_blank" href="https://example.com/lacie" id="link2">Lacie</a>, <p >Once upon a time there were three little sisters; and their names were
  9. #<a  target="_blank" href="https://example.com/elsie" id="link1">Elsie</a>,
  10. #<a  target="_blank" href="https://example.com/lacie" id="link2">Lacie</a> and
  11. #and they lived at the bottom of a well.</p>, <body>....]
复制代码
BeautifulSoup的CSS选择器

我们在写CSS时,标签名不加任何修饰,类名前加点,id名前加#,BeautifulSoup中也可以使用类似的方法来筛选元素,
select(selector, namespaces=None, limit=None, **kwargs)

BeautifulSoup中的select()方法允许使用CSS选择器来查找HTML文档元素,其返回一个包含所有匹配元素的列表类似与find_all()方法


  • selector:一个字符串,表示将要选择的CSS选择器,可以是简单标签选择器,类选择器,id选择器
通过标签名查找
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. print(soup.select('b'))
  3. #[<b>The Dormouse's story</b>, <b></b>]
复制代码
通过类名查找
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. print(soup.select('.title'))
  3. #[<p ><b>The Dormouse's story</b></p>]
复制代码
id名查找
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. print(soup.select('#link1'))
  3. #[<a  target="_blank" href="https://example.com/elsie" id="link1">Elsie</a>]
复制代码
组合查找


  • 组合查找即与写class时一致,标签名与类名id名进行组合的原理一样
eg:查找p标签中id为link1的内容
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. print(soup.select('p #link1'))
  3. #[<a  target="_blank" href="https://example.com/elsie" id="link1">Elsie</a>]
复制代码

  • 查找类选择器时也可以使用id选择器的标签
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. print(soup.select('.story#text'))
复制代码

  • 查找有多个class选择器和一个id选择器的标签
  1. soup = BeautifulSoup(html_doc, 'lxml')
  2. print(soup.select(".story .sister#link1"))
  3. #[<a  target="_blank" href="https://example.com/elsie" id="link1">Elsie</a>]
复制代码
属性查找

选择具有特定属性或属性值的标签


  • 简单属性选择器

    • 选择具有特定属性的标签
    1. soup = BeautifulSoup(html_doc, 'lxml')
    2. print(soup.select("a[href='https://example.com/elsie']"))  # 选择a标签中href属性为https://example.com/elsie的标签
    3. #[<a  target="_blank" href="https://example.com/elsie" id="link1">Elsie</a>]
    复制代码
  • 属性值选择器
    选择具有特定属性值的标签


    • 精确匹配:[attribute="value"]
    • 部分匹配

      • 包含特定值:[attribute~="value"] 选择属性值包含特定单词的标签。
      • 以特定值开头:[attribute^="value"] 选择属性值以特定字符串开头的标签
      • 以特定值结尾:[attribute$="value"] 选择属性值以特定字符串结尾的标签。
      • 包含特定子字符串:[attribute*="value"] 选择属性值包含特定子字符串的标签

    1. soup = BeautifulSoup(html_doc, 'lxml')
    2. print(soup.select('a[href^="https://example.com"]'))  # 选择href以https://example.com开头的a标签
    3. #[<a  target="_blank" href="https://example.com/elsie" id="link1">Elsie</a>, <a  target="_blank" href="https://example.com/lacie" id="link2">Lacie</a>, <a  target="_blank" href="https://example.com/tillie" id="link3">Tillie</a>]
    复制代码

来源:https://www.cnblogs.com/ihave2carryon/p/18578873
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具