BeautifulSoup
简介
BeautifulSoup 是一个可以把 HTML 或 XML 文档“变成结构化树”,方便你用Python 来查找、遍历、提取内容的工具。
解析器
| 解析器 | 使用方法 | 优势 | 劣势 |
|---|---|---|---|
| Python标准库 | BeautifulSoup(markup, ‘html.parser’) | python内置的标准库,执行速度适中 | Python3.2.2之前的版本容错能力差 |
| lxml HTML解析器 | BeautifulSoup(markup, ’lxml') | 速度快、文档容错能力强 | 需要安装C语言库 |
| lxml XML解析器 | BeautifulSoup(markup ‘xml’) | 速度快,唯一支持XML的解析器 | 需要安装C语言库 |
| html5lib | BeautifulSoup(markup, ‘html5lib’) | 最好的容错性、以浏览器的方式解析文档、生成HTML5格式的文档 | 速度慢,不依赖外部拓展 |
具体使用代码展示如下:
|
|
基本用法
当传入不标准的HTML字符串,BeautifulSoup可以自动更正格式。
-
soup.prettify(): 用于将 HTML 或 XML 文档格式化输出为带缩进的字符串,即会把原始网页内容重新排版,输出一个带有层级缩进的漂亮 HTML 字符串,例:
1 2 3 4 5 6 7from bs4 import BeautifulSoup html = '<html><head><title>Test</title></head><body><h1>Hi</h1><p>Hello</p></body></html>' soup = BeautifulSoup(html, 'html.parser') pretty_html = soup.prettify() print(pretty_html)输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15<html> <head> <title> Test </title> </head> <body> <h1> Hi </h1> <p> Hello </p> </body> </html> -
.title:获取title标签
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17html_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> """" # 创建beautifulsoup对象 解析器为lxml soup = BeautifulSoup(html_doc, 'lxml') print(soup.title) #output-><title>The Dormouse's story</title> -
.name:返回的是当前节点的“标签名称”
1 2 3 4 5soup = BeautifulSoup(html_doc, 'lxml') print(soup.title.name) print(soup.name) #output->title #[document] -
.string/.text:获取标签中的文字内容
1 2 3 4 5soup = BeautifulSoup(html_doc, 'lxml') print(soup.title.string) print(soup.title.text) #output->The Dormouse's story #The Dormouse's story -
.p:访问HTML中第一个
标签
1 2 3soup = BeautifulSoup(html_doc, 'lxml') print(soup.p) #output-><p class="title"><b>The Dormouse's story</b></p> -
.find_all():查找文档中所有符合条件的标签元素,返回一个列表
用法 示例 说明 查找所有某种标签 soup.find_all(‘p’) 找出所有 <p>根据 class 属性 soup.find_all(‘p’, class_=‘story’) class 要用 class_表示查找多个标签 soup.find_all([‘p’, ‘a’]) 所有 <p>和<a>标签查找包含特定字符串的标签 soup.find_all(string=‘Hello’) 内容匹配为 ‘Hello’ 的标签 使用属性字典 soup.find_all(‘a’, {‘id’: ’link1’}) 属性筛选 限制返回数量 soup.find_all(‘p’, limit=2) 最多返回 2 个 <p>标签1 2 3 4''' 基本语法: soup.find_all(name=None, attrs={}, recursive=True, string=None, limit=None, **kwargs) ''' -
.find():获取第一次匹配条件的元素
1 2 3soup = BeautifulSoup(html_doc, 'lxml') print(soup.find(id="link1")) #output-><a class="sister" href="https://example.com/elsie" id="link1">Elsie</a> -
.parent:获取父级标签
1 2 3 4 5soup = BeautifulSoup(html_doc, 'lxml') print(soup.title) print(soup.title.parnt) #output-><title>The Dormouse's story</title> #<head><title>The Dormouse's story</title></head> -
.p[‘class’]:获取某个
<p>标签的class属性的值1 2 3soup = BeautifulSoup(html_doc, 'lxml') print(soup.p["class"]) #output->['title'] -
.get_text():获取文档中所有文字内容
|
|
-
.get():用于安全地获取某个属性的值
1 2 3 4 5 6 7 8 9''' tag.get('属性名') 相当于 tag['属性名'],但如果属性不存在,不会报错,而是返回 None ''' a_tags = soup.find_all('a') for a_tag in a_tags: print(a_tag.get("href")) #output->https://example.com/elsie #https://example.com/lacie #https://example.com/tillie
BeautifulSoup的对象种类
主要有四种主要类型:Tag,NavigableString,BeautifulSoup,Comment。
-
Tag:该对象与HTML或XML原生文档中的标签相同,该对象可以包含其他标签,文本内容和属性。
1 2 3 4soup = BeautifulSoup(html_doc, 'lxml') tag = soup.title print(type(tag)) #output-><class 'bs4.element.Tag'> -
NavigableString:标签中的文本内容,是一个不可变字符串,可以由Tag对象的.string获取
1 2 3 4soup = BeautifulSoup(html_doc, 'lxml') tag = soup.title print(type(tag.string)) #output-> <class 'bs4.element.NavigableString'> -
BeautifulSoup:整个文档的根对象,即整个文档的根内容,可以被视为一个特殊的Tag对象,但没有名称和属性,其提供对整个文档的遍历,搜索和修改
1 2 3soup = BeautifulSoup(html_doc, 'lxml') print(type(soup)) #output-> <class 'bs4.BeautifulSoup'> -
Comment:对象是一个特殊类型的NavigableString对象,表示HTML和XML中的注释部分
1 2 3 4# <b><!--This is a comment--></b> soup = BeautifulSoup(html_doc, 'lxml') print(type(soup.b.string)) #output-> <class 'bs4.element.NavigableString'>
BeautifulSoup遍历文档树
BeautifulSoup提供很多方法来遍历解析后的文档树
-
导航父节点:.parent和.parents。其中.parent可以获取当前节点的上一级父节点,.parents可以遍历获取当前节点的所有父辈节点
1 2 3 4soup = BeautifulSoup(html_doc, 'lxml') title_tag = soup.title print(title_tag.parent) #<head><title>The Dormouse's story</title></head>1 2 3 4 5 6 7 8 9 10soup = BeautifulSoup(html_doc, 'lxml') body_tag = soup.body for parent in body_tag.parents: print(parent) #<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 class="sister" href="https://example.com/elsie" id="link1">Elsie</a>, #.... -
导航子节点:.contents可以获取当前节点的所有子节点;.children可以遍历当前节点的所有子节点,返回一个list。字符串没有这两个属性。这两个仅包含tag直接子结点,字符串”The Dormouse’s story”是
<head>标签的子孙结点1 2 3 4soup = BeautifulSoup(html_doc, 'lxml') head_contents = soup.head.contents print(head_contents) #output-> [<title>The Dormouse's story</title>]1 2 3 4 5 6 7 8 9 10soup = BeautifulSoup(html_doc, 'lxml') body_children = soup.body.children for child in body_children: print(child) #output-><p class="title"><b>The Dormouse's story</b></p> #<a class="sister" href="https://example.com/elsie" id="link1">Elsie</a>, #<a class="sister" href="https://example.com/tillie" id="link3">Tillie</a>; #and they lived at the bottom of a well.</p> #..... -
.descendants:可以遍历当前节点的所有后代节点(层遍历)
1 2 3soup = BeautifulSoup(html_doc, 'lxml') for descendant in soup.descendants: print(descendant) -
节点内容:.string,.strings,.stripped_strings。.string如果如果tag只有一个
NavigableString类型子节点,那么这个tag可以使用.string得到其子节点。但若tag中包含了多个子节点,tag就无法确定string方法应该调用哪一个字节的内容,则会输出None1 2 3 4 5soup = BeautifulSoup(html_doc, 'lxml') print(soup.head.string) #The Dormouse's story print(soup.title.string) #The Dormouse's story1 2 3soup = BeautifulSoup(html_doc, 'lxml') print(soup.body.string) #None.strings可以遍历获取标签中的所有文本内容,.stripped_strings可以去除多余的空白字符
1 2 3 4 5 6 7soup = BeautifulSoup(html_doc, 'lxml') for string in soup.strings: print(string) #The Dormouse's story ...... #The Dormouse's story
BeautifulSoup搜索文档树
-
find_all():搜索当前tag的所有tag子节点
1 2 3 4 5 6 7 8 9 10 11soup = 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>] #[<p class="title"><b>The Dormouse's story</b></p>] #[<a class="sister" href="https://example.com/elsie" id="link1">Elsie</a>, <a class="sister" href="https://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="https://example.com/tillie" id="link3">Tillie</a>] #[<a class="sister" href="https://example.com/lacie" id="link2">Lacie</a>] -
find_parent():只返回最接近的父标签
1 2 3 4soup = BeautifulSoup(html_doc, 'lxml') a_string = soup.find(string='Lacie') print(a_string.find_parent()) # 查找父节点 #<a class="sister" href="https://example.com/lacie" id="link2">Lacie</a> -
find_parents():返回所有符合条件的祖先标签,按从近到远的顺序排列
1 2 3 4 5 6 7soup = BeautifulSoup(html_doc, 'lxml') a_string = soup.find(string='Lacie') print(a_string.find_parents()) # 查找父节点 #[<a class="sister" href="https://example.com/lacie" id="link2">Lacie</a>, <p class="story">Once upon a time there were three little sisters; and their names were #<a class="sister" href="https://example.com/elsie" id="link1">Elsie</a>, #<a class="sister" href="https://example.com/lacie" id="link2">Lacie</a> and #and they lived at the bottom of a well.</p>, <body>....]
BeautifulSoup的CSS选择器
我们在写CSS时,标签名不加任何修饰,类名前加点,id名前加#,BeautifulSoup中也可以使用类似的方法来筛选元素。BeautifulSoup中的select()方法允许使用CSS选择器来查找HTML文档元素,其返回一个包含所有匹配元素的列表类似于find_all()方法。
-
通过标签名查找:
1 2 3soup = BeautifulSoup(html_doc, 'lxml') print(soup.select('b')) #[<b>The Dormouse's story</b>, <b><!--This is a comment--></b>] -
通过类名查找:
1 2 3soup = BeautifulSoup(html_doc, 'lxml') print(soup.select('.title')) #[<p class="title"><b>The Dormouse's story</b></p>] -
id名查找:
1 2 3soup = BeautifulSoup(html_doc, 'lxml') print(soup.select('#link1')) #[<a class="sister" href="https://example.com/elsie" id="link1">Elsie</a>] -
组合查找:组合查找即与写class时一致,标签名与类名id名进行组合的原理一样
1 2 3soup = BeautifulSoup(html_doc, 'lxml') print(soup.select('p #link1')) #[<a class="sister" href="https://example.com/elsie" id="link1">Elsie</a>] -
属性查找:选择具有特定属性或属性值的标签
-
简单属性选择器:
1 2 3soup = BeautifulSoup(html_doc, 'lxml') print(soup.select("a[href='https://example.com/elsie']")) # 选择a标签中href属性为https://example.com/elsie的标签 #[<a class="sister" href="https://example.com/elsie" id="link1">Elsie</a>] -
属性值选择器
1 2 3 4 5 6 7 8 9 10 11 12 13''' 精确匹配:[attribute="value"] 部分匹配 包含特定值:[attribute~="value"] 选择属性值包含特定单词的标签。 以特定值开头:[attribute^="value"] 选择属性值以特定字符串开头的标签 以特定值结尾:[attribute$="value"] 选择属性值以特定字符串结尾的标签。 包含特定子字符串:[attribute*="value"] 选择属性值包含特定子字符串的标签 ''' soup = BeautifulSoup(html_doc, 'lxml') print(soup.select('a[href^="https://example.com"]')) # 选择href以https://example.com开头的a标签 #[<a class="sister" href="https://example.com/elsie" id="link1">Elsie</a>, <a class="sister" href="https://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="https://example.com/tillie" id="link3">Tillie</a>]