Beautiful Soup:修订间差异
无编辑摘要 |
|||
(未显示同一用户的10个中间版本) | |||
第1行: | 第1行: | ||
Beautiful Soup是一个[[Python]] | Beautiful Soup是一个[[Python]]库,能够方便的从[[HTML]]或[[XML]]文件中提取数据。 | ||
==简介== | ==简介== | ||
第7行: | 第7行: | ||
可以通过下面3中方式安装Beautiful Soup 4。 | 可以通过下面3中方式安装Beautiful Soup 4。 | ||
====通过pip安装==== | ====通过pip安装==== | ||
Beautiful Soup 4 | Beautiful Soup 4 发布在[[PyPI]]平台上,所以可以使用[[pip]]来安装: | ||
pip install beautifulsoup4 | pip install beautifulsoup4 | ||
====通过软件包管理安装==== | ====通过软件包管理安装==== | ||
如果你用的是新版的[[Debain]]或[[Ubuntu]], | 如果你用的是新版的[[Debain]]或[[Ubuntu]],那么也可以通过系统的软件包管理来安装: | ||
apt-get install Python-bs4 | apt-get install Python-bs4 | ||
第24行: | 第23行: | ||
==基础知识== | ==基础知识== | ||
=== | ===获取页面=== | ||
获取页面可以使用Python的urllib标准库下的[https://docs.python.org/zh-cn/3/library/urllib.request.html request]模块或[[requests]]库。 | |||
下面使用[[requests]]库获取页面,然后使用BeautifulSoup提取body标签。 | |||
<syntaxhighlight lang="python"> | |||
import requests | |||
from bs4 import BeautifulSoup | |||
response = requests.get('https://www.baidu.com') | |||
bs = BeautifulSoup(response.content, 'html.parser') | |||
tag = bs.body | |||
</syntaxhighlight> | |||
使用Python的request模块获取页面,然后使用BeautifulSoup提取标题字符串。示例如下: | |||
<syntaxhighlight lang="python"> | |||
from urllib.request import urlopen | |||
from bs4 import BeautifulSoup | from bs4 import BeautifulSoup | ||
html = urlopen('https://www.baidu.com') | html = urlopen('https://www.baidu.com') | ||
bs = BeautifulSoup(html.read(), 'html.parser') | bs = BeautifulSoup(html.read(), 'html.parser') | ||
bs.title</ | title = str(bs.title.string) #标题内容 | ||
</syntaxhighlight> | |||
===文档解析器=== | |||
Beautiful Soup支持Python标准库的HTML解析器 [https://docs.python.org/zh-cn/3/library/html.parser.html html.parser],还支持一些第三方的解析器。如果未通过参数设置指定的解析器,Beautiful Soup会自动选择一个已安装的,优先数序:[[lxml]],[[html5lib]],[https://docs.python.org/zh-cn/3/library/html.parser.html html.parser]。不同的解析器得到的结果可能不同,所以防止程序的不稳定,最好指定解析器。支持解析的文档格式有[[HTML]]、HTML5和[[XML]],其中只有lxml解析器支持解析XML文档。下表为当前支持的解析器: | |||
{| class="wikitable" style="width: 100%; | |||
! 解析器 | |||
! 描述 | |||
! 安装 | |||
! 用法 | |||
|- | |||
| Python标准库 html.parser | |||
| 速度中,Python的内置标准库 | |||
| 不需要安装 | |||
| BeautifulSoup(markup, "html.parser") | |||
|- | |||
| lxml 的 HTML解析器 | |||
| 速度快 | |||
| pip install lxml | |||
| BeautifulSoup(markup, "lxml") | |||
|- | |||
| lxml 的 XML 解析器 | |||
| 速度快,唯一支持XML的解析器 | |||
| pip install lxml | |||
| BeautifulSoup(markup, ["lxml-xml"]) <br \>BeautifulSoup(markup, "xml") | |||
|- | |||
| html5lib | |||
| 速度慢,最好的容错性,以浏览器的方式解析文档,生成HTML5格式的文档 | |||
| pip install html5lib | |||
| BeautifulSoup(markup, "html5lib") | |||
|- | |||
|} | |||
{{了解更多 | |||
|[https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/#id13 BeautifulSoup 4 文档:安装解析器] | |||
|[https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/#id53 BeautifulSoup 4 文档:指定文档解析器] | |||
}} | |||
==对象== | |||
Beautiful Soup将复杂[[HTML]]文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种: | Beautiful Soup将复杂[[HTML]]文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种: | ||
{| class="wikitable" style="width: 100%; | |||
! 类 | |||
! 描述 | |||
! 生成对象 | |||
|- | |||
|BeautifulSoup | |||
|BeautifulSoup 对象表示的是一个文档的全部内容。基本上可以当作Tag对象,支持遍历文档树和搜索文档树中描述的大部分的方法。 | |||
|如<code>BeautifulSoup(markup, "html.parser")</code> | |||
|- | |||
|Tag | |||
|Tag对象与XML或HTML原生文档中的tag(标签)相同。Tag有很多方法和属性,常用如<code>tag.name</code>获取Tag的标签名称,<code>tag.class</code>获取Tag的class,<code>tag.text</code>获取Tag的所有显示文本(包括子Tag的文本)。 | |||
|通过BeautifulSoup对象遍历文档树或搜索文档树生成。如bs表示一个BeautifulSoup对象,<code>bs.p</code> | |||
|- | |||
|NavigableString | |||
|tag中的字符串被封装在NavigableString类中。一个 NavigableString 字符串与Python中的Unicode字符串相同,并且还支持包含在 遍历文档树 和 搜索文档树 中的一些特性。 | |||
|通过Tag对象string属性生成。<br \>如<code>tag.string</code> | |||
|- | |||
|Comment | |||
|文档的注释部分包装在Comment类中,Comment 对象是一个特殊类型的 NavigableString 对象。 | |||
|通过Tag对象string属性生成。<br \>如<code>tag.string</code> | |||
|- | |||
|} | |||
=== | {{了解更多 | ||
|[https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/#id15 BeautifulSoup 4 文档:对象的种类] | |||
}} | |||
===BeautifulSoup === | |||
BeautifulSoup 对象表示的是一个文档的全部内容。大部分时候,可以把它当作 Tag 对象,它支持 遍历文档树 和 搜索文档树 中描述的大部分的方法。因为 BeautifulSoup 对象并不是真正的HTML或XML的tag,所以它没有name和attribute属性。 | |||
如下生成一个BeautifulSoup 对象 bs,其中markup表示文档内容: | |||
bs = BeautifulSoup(markup, "html.parser") | |||
tag = bs.b | |||
type(tag) | |||
# <class 'bs4.element.Tag'> | ===Tag=== | ||
Tag对象与[[XML]]或[[HTML]]原生文档中的tag相同,Tag有很多方法和属性。标签名称通过对象<code>.name</code>获取,如tag.name。标签的某个属性可以通过对象的<code>.属性名</code>或<code>[属性名]</code>操作获取,如tag['class']或tag.class。标签的所有属性可以通过对象的<code>.attrs</code>获取,返回字典类型。示例如下: | |||
<syntaxhighlight lang="python"> | |||
bs = BeautifulSoup('<b class="boldest">Extremely bold</b>') | |||
tag = bs.b #生成一个tag对象 | |||
type(tag) # <class 'bs4.element.Tag'> | |||
#获取该标签的名字 | #获取该标签的名字 | ||
tag.name | tag.name #'b' | ||
#' | tag.name = "blockquote" 也可以改变标签名称 | ||
#获取属性 | |||
tag.attrs # 获取标签的所有属性,{'class': 'boldest'} | |||
tag['class'] # 获取某个属性的值,['boldest'] | |||
# | #添加,删除,修改操作方法和字典一样。 | ||
tag | tag['class'] = 'verybold' #修改tag的class属性值为verybold | ||
tag | tag['id'] = 1 #tag添加一个id="1"的属性 | ||
# | del tag['id'] #删除tag的id属性 | ||
</syntaxhighlight> | |||
===NavigableString === | |||
字符串常被包含在标签tag内。Beautiful Soup用 NavigableString 类来包装tag中的字符串。使用.string一个 NavigableString 字符串与Python中的Unicode字符串相同, | 字符串常被包含在标签tag内。Beautiful Soup用 NavigableString 类来包装tag中的字符串。使用.string一个 NavigableString 字符串与Python中的Unicode字符串相同,并且还支持包含在遍历文档树和搜索文档树中的一些特性。通过Python的 str() 方法可以直接将 NavigableString 对象转换成Unicode字符串: | ||
<syntaxhighlight lang="python"> | |||
from urllib.request import urlopen | |||
from bs4 import BeautifulSoup | from bs4 import BeautifulSoup | ||
html = urlopen('https://www.baidu.com') | html = urlopen('https://www.baidu.com') | ||
第98行: | 第154行: | ||
tag = bs.title | tag = bs.title | ||
tag.string | tag.string #'百度一下,你就知道' | ||
#'百度一下,你就知道' | type(tag.string) # <class 'bs4.element.NavigableString'> | ||
type(tag.string) | |||
# <class 'bs4.element.NavigableString' | |||
= | title = str(tag.string) #'百度一下,你就知道' | ||
type(title) # 字符串 | |||
</syntaxhighlight> | |||
===Comment === | |||
Comment是文档的注释及特殊字符串,Comment 对象是一个特殊类型的 NavigableString 对象。 | Comment是文档的注释及特殊字符串,Comment 对象是一个特殊类型的 NavigableString 对象。 | ||
<syntaxhighlight lang="python"> | |||
markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>" | |||
soup = BeautifulSoup(markup) | soup = BeautifulSoup(markup) | ||
comment1 = soup.b.string | comment1 = soup.b.string | ||
type(comment1) | type(comment1) # <class 'bs4.element.Comment'> | ||
# <class 'bs4.element.Comment'> | comment1 # 'Hey, buddy. Want to buy a used parser' | ||
comment1 | </syntaxhighlight> | ||
# | |||
</ | |||
==遍历文档树== | ==遍历文档树== | ||
===子节点=== | ===子节点=== | ||
一个Tag可能包含多个字符串或其它的Tag,这些都是这个Tag的子节点。Beautiful | 一个Tag可能包含多个字符串或其它的Tag,这些都是这个Tag的子节点。Beautiful Soup提供了许多操作和遍历子节点的属性。操作文档树最简单的方法就是告诉它你想获取的tag的name。 | ||
< | |||
下表中bs为一个BeautifulSoup对象,tag为一个Tag对象: | |||
{| class="wikitable" style="width: 100%; | |||
bs = | ! 属性 | ||
! 描述 | |||
! 示例 | |||
|- | |||
| .标签名称 | |||
| 获取对象第一个该名称标签。 | |||
| <code>bs.p</code>获取bs的第一个名称为p的标签。<br \><code>bs.p.b</code> | |||
|- | |||
| .contents | |||
| 以列表形式输出对象的子节点。只包括子代节点。 | |||
| <code>bs.contents</code> | |||
|- | |||
| .children | |||
| 返回一个所有子节点list_iterator迭代器。只包括子代节点。 | |||
| <code>bs.children</code> | |||
|- | |||
| .descendants | |||
| 返回一个递归的子孙节点生成器。 | |||
| <code>bs.descendants</code> | |||
|- | |||
| .string | |||
| 返回节点NavigableString对象,当该节点有多个NavigableString对象,返回空。 | |||
| <code>tag.string</code> | |||
|- | |||
| .strings | |||
| 返回节点所有NavigableString对象生成器。 | |||
| <code>tag.strings</code> | |||
|- | |||
| .stripped_strings | |||
| 与.strings一样,但会去掉字符串中多余的空格或空行 | |||
| <code>tag.stripped_strings</code> | |||
|} | |||
===父节点=== | |||
每个Tag或NavigableString都有父节点,包含在该节点中。如下: | |||
{| class="wikitable" style="width: 100%; | |||
! 属性 | |||
! 描述 | |||
! 示例 | |||
|- | |||
|.parent | |||
|获取某个元素的父节点 | |||
|<code>tag.parent</code> | |||
|- | |||
|.parents | |||
| | |||
| | |||
|- | |||
|} | |||
===兄弟节点=== | |||
{| class="wikitable" style="width: 100%; | |||
! 属性 | |||
! 描述 | |||
! 示例 | |||
|- | |||
|.next_sibling | |||
| | |||
|<code>tag.next_sibling</code> | |||
|- | |||
|.previous_sibling | |||
| | |||
| | |||
|- | |||
|.next_siblings | |||
| | |||
|<code>tag.next_sibling</code> | |||
|- | |||
|.previous_siblings | |||
| | |||
| | |||
|- | |||
|} | |||
===回退和前进=== | |||
{| class="wikitable" style="width: 100%; | |||
! 属性 | |||
! 描述 | |||
! 示例 | |||
|- | |||
|.next_element | |||
| 属性指向解析过程中下一个被解析的对象(字符串或tag),结果可能与 .next_sibling 相同,但通常是不一样的. | |||
|<code>tag.next_element</code> | |||
|- | |||
|.previous_element | |||
| | |||
|<code>tag.previous_element</code> | |||
|- | |||
|.next_elements 和 | |||
| | |||
|<code>tag.next_elements </code> | |||
|- | |||
|.previous_elements | |||
| | |||
|<code>tag.previous_elements</code> | |||
|- | |||
|} | |||
==搜索文档树== | |||
===搜索方法=== | |||
Beautiful Soup定义了很多搜索方法,find_all()几乎是Beautiful Soup中最常用的搜索方法。 | |||
{| class="wikitable" style="width: 100%; | |||
! 方法 | |||
! 描述 | |||
! 示例 | |||
|- | |||
|find_all() | |||
|返回文档中符合条件的所有节点对象 | |||
| | |||
|- | |||
|find() | |||
| | |||
|soup.find('title') | |||
|- | |||
|find_parents() | |||
| | |||
| | |||
|- | |||
|find_parent() | |||
| | |||
| | |||
|- | |||
|find_next_siblings() | |||
| | |||
| | |||
|- | |||
|find_next_sibling() | |||
| | |||
| | |||
|- | |||
|find_previous_siblings() | |||
| | |||
| | |||
|- | |||
|find_previous_sibling() | |||
| | |||
| | |||
|- | |||
|find_all_next() | |||
| | |||
| | |||
|- | |||
|find_next() | |||
| | |||
| | |||
|- | |||
|find_all_previous() | |||
| | |||
| | |||
|- | |||
|find_previous() | |||
| | |||
| | |||
|- | |||
|select() | |||
|使用CSS选择器的语法找到tag,在 Tag 或 BeautifulSoup 对象的select() 方法中传入字符串参数即可。如果仅需要CSS选择器的功能,那么可以直接使用[[lxml]]。 | |||
|<code>bs.select("p > #toc")</code> | |||
|} | |||
===参数=== | |||
12个find开头的搜索方法,其参数和用法类似,格式都为: | |||
function( name , attrs , recursive , string , **kwargs ) | |||
这些方法的参数如下: | |||
{| class="wikitable" style="width: 100%; | |||
! 参数 | |||
! 描述 | |||
! 示例 | |||
|- | |||
|name | |||
|按tag的名称搜素tag,字符串对象会被自动忽略掉。 name参数的值可以是任一类型的过滤器(字符串、正则表达式、列表、函数或布尔值)。 | |||
|<code>bs.find_all("title")</code>查找所有名为title的tag | |||
|- | |||
|**kwargs | |||
|可变关键字参数,按属性来搜索tag,参数值可以是任一类型的过滤器。 <br /><br />常见如:<br /><code>id</code>按id来搜索tag <br /><code>class_</code> 按CSS类名(class)来搜索tag <br /><code>href</code>按href来搜索tag <br /><br />当指定名字的参数不是方法内置的参数名时,会把该参数当作指定名字tag的属性来搜索。 一些没有内置的属性名,可以使用attrs参数传入。 | |||
|<code>bs.find(id="p1")</code>查看标签id='p1'。 <br /><code>bs.find(class_="content")</code>查看标签class属性包含content。 | |||
|- | |||
|attrs | |||
|标签的属性值都可以使用attrs表示,可以传入字典。css属性需要完全匹配也可以使用attrs传入。 | |||
|<code>bs.find(attrs={'name':'commodity'})</code> 查找标签属性name="commodity"的标签。<br /> <code>bs.find_all(attrs={"data-foo": "value"})</code> | |||
|- | |||
|string | |||
|按文档中的字符串内容搜索,参数值可以是任一类型的过滤器。 | |||
| | |||
|- | |||
|limit | |||
|限制返回结果的数量,效果与SQL中的limit关键字类似,在**kwargs接收。有时文档树很大搜索会很慢,当不需要全部结果可以使用limit参数限制。 | |||
|<code>bs.find_all("a", limit=2)</code> | |||
|- | |||
|recursive | |||
|限制只搜索直接子节点,而不是全部的子孙节点。 | |||
|<code>tag.find_all("a", recursive=False)</code> | |||
|- | |||
|} | |||
{{了解更多 | |||
|[https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/#find-all Beautiful Soup 4文档:find_all()] | |||
}} | |||
===过滤器=== | |||
过滤器是筛选条件,用于搜索函数参数值,包括节点名称、节点属性、string中或他们的混合中。过滤器类型包括:字符串、[[正则表达式]]、列表、函数或布尔值。 | |||
{| class="wikitable" style="width: 100%; | |||
! 过滤器 | |||
! 描述 | |||
! 示例 | |||
|- | |||
|字符串 | |||
|最简单的过滤器是字符串,在搜索方法中传入一个字符串参数值,会匹配与字符串完全相同的值。 | |||
|<code>bs.find("title")</code>查找名称为“title”的tag <br \><code>bs.find_all(class_ = 'section')</code>查找class属性为“section”的tag <br \><code>bs.find(id = 'toc')</code>查找id属性为“toc”的tag | |||
|- | |||
|正则表达式 | |||
|如果传入正则表达式作为参数值,Beautiful Soup会通过Python中正则表达式[https://docs.python.org/zh-cn/3/library/re.htm re]模块的[https://docs.python.org/zh-cn/3/library/re.html#re.search search()]函数来匹配内容。 | |||
|<code>bs.find_all(re.compile("^b")</code>查找所有tag名称以"b"字母开头的tag。<br \><code>soup.find_all(class_ = "data", id = re.compile("t"))</code>查找所有tag的class属性为"data",id属性含有"t"的tag。 | |||
|- | |||
|列表 | |||
|如果传入列表参数值,Beautiful Soup会将与列表中任一元素匹配的内容返回。 | |||
|<code>bs.find_all(["a", "div"])</code>查找所有tag名称为"a"或"div"的tag。<br \><code>bs.find_all("div", class_ = ["section", "data"])</code>查找所有tag的名称为"div",且class属性为"section"或"data"的tag。 | |||
|- | |||
|布尔值 | |||
|可以传入布尔值True或False作为参数值。 True 可以匹配任何值,但是不会返回字符串对象的节点。 | |||
|<code>bs.find_all(True)</code>查找所有tag。<br \><code>bs.find_all(class_ = True)</code>查找所有含有class属性的tag。 | |||
|- | |||
|函数 | |||
|如果没有合适过滤器,那么还可以定义一个函数,函数只接受一个元素作为参数,如果这个函数返回 True 表示当前元素匹配并且被找到,如果不是则反回 False。 | |||
|见下文 | |||
|- | |||
|} | |||
一个简单使用函数作为过滤器如下,该函数检测当前元素,如果包含 class 属性却不包含 id 属性,那么将返回 True: | |||
<syntaxhighlight lang="python"> | |||
def has_class_but_no_id(tag): | |||
return tag.has_attr('class') and not tag.has_attr('id') | |||
bs.find_all(has_class_but_no_id) | |||
bs. | </syntaxhighlight> | ||
===CSS选择器=== | |||
Tag 或 BeautifulSoup 对象的 select() 方法用于通过[[CSS]]选择器查找tag。Beautiful Soup支持大部分的[http://www.w3.org/TR/CSS2/selector.html CSS选择器]。用法为CSS选择器作为字符串值传入select() 方法。 | |||
对于熟悉CSS选择器语法的人来说这是个非常方便的方法.Beautiful Soup也支持CSS选择器API, 如果你仅仅需要CSS选择器的功能,那么直接使用 lxml 也可以, 而且速度更快,支持更多的CSS选择器语法,但Beautiful Soup整合了CSS选择器的语法和自身方便使用API。 | |||
示例如下: | |||
<syntaxhighlight lang="python"> | |||
bs.select("title") | |||
bs.select("body a") | |||
bs. | |||
. | bs.select("p > a") | ||
bs.select("p:nth-of-type(3)") | |||
</syntaxhighlight> | |||
==修改文档树== | |||
Beautiful Soup的强项是文档树的搜索,但同时也可以方便的修改文档树 | |||
== | |||
== | ==输出== | ||
格式化输出使用prettify() 方法,如<code>bs.prettify()</code>。该方法将Beautiful Soup的文档树格式化后以Unicode编码输出,每个XML/HTML标签都独占一行。 如果不重视格式,也可以对象使用Python的str()方法,如<code>str(bs.title)</code>。 | |||
如果只想得到tag中包含的文本内容,那么可以调用 get_text() 方法,这个方法获取到tag中包含的所有文版内容包括子孙tag中的内容,并将结果作为Unicode字符串返回。如<code>bs.get_text()</code>。 | |||
==编码== | |||
任何HTML或XML文档都有自己的编码方式,比如[[ASCII]] 或 [[UTF-8]],但是使用Beautiful Soup解析后,文档都被转换成了[[Unicode]]。 | |||
==资源== | ==资源== | ||
===官网=== | |||
*Beautiful Soup:https://www.crummy.com/software/BeautifulSoup/ | |||
*Beautiful Soup 4 中文文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/ | |||
===网站=== | ===网站=== | ||
*[https://en.wikipedia.org/wiki/Beautiful_Soup_(HTML_parser) 维基百科:Beautiful Soup] | *[https://en.wikipedia.org/wiki/Beautiful_Soup_(HTML_parser) 维基百科:Beautiful Soup] | ||
[[分类: | [[分类:数据分析]] |
2022年10月9日 (日) 08:21的最新版本
Beautiful Soup是一个Python库,能够方便的从HTML或XML文件中提取数据。
简介
时间轴
安装
可以通过下面3中方式安装Beautiful Soup 4。
通过pip安装
Beautiful Soup 4 发布在PyPI平台上,所以可以使用pip来安装:
pip install beautifulsoup4
通过软件包管理安装
如果你用的是新版的Debain或Ubuntu,那么也可以通过系统的软件包管理来安装:
apt-get install Python-bs4
下载源代码安装
下载BS4的源码,然后通过setup.py来安装。
Python setup.py install
基础知识
获取页面
获取页面可以使用Python的urllib标准库下的request模块或requests库。
下面使用requests库获取页面,然后使用BeautifulSoup提取body标签。
import requests
from bs4 import BeautifulSoup
response = requests.get('https://www.baidu.com')
bs = BeautifulSoup(response.content, 'html.parser')
tag = bs.body
使用Python的request模块获取页面,然后使用BeautifulSoup提取标题字符串。示例如下:
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen('https://www.baidu.com')
bs = BeautifulSoup(html.read(), 'html.parser')
title = str(bs.title.string) #标题内容
文档解析器
Beautiful Soup支持Python标准库的HTML解析器 html.parser,还支持一些第三方的解析器。如果未通过参数设置指定的解析器,Beautiful Soup会自动选择一个已安装的,优先数序:lxml,html5lib,html.parser。不同的解析器得到的结果可能不同,所以防止程序的不稳定,最好指定解析器。支持解析的文档格式有HTML、HTML5和XML,其中只有lxml解析器支持解析XML文档。下表为当前支持的解析器:
解析器 | 描述 | 安装 | 用法 |
---|---|---|---|
Python标准库 html.parser | 速度中,Python的内置标准库 | 不需要安装 | BeautifulSoup(markup, "html.parser") |
lxml 的 HTML解析器 | 速度快 | pip install lxml | BeautifulSoup(markup, "lxml") |
lxml 的 XML 解析器 | 速度快,唯一支持XML的解析器 | pip install lxml | BeautifulSoup(markup, ["lxml-xml"]) BeautifulSoup(markup, "xml") |
html5lib | 速度慢,最好的容错性,以浏览器的方式解析文档,生成HTML5格式的文档 | pip install html5lib | BeautifulSoup(markup, "html5lib") |
对象
Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:
类 | 描述 | 生成对象 |
---|---|---|
BeautifulSoup | BeautifulSoup 对象表示的是一个文档的全部内容。基本上可以当作Tag对象,支持遍历文档树和搜索文档树中描述的大部分的方法。 | 如BeautifulSoup(markup, "html.parser")
|
Tag | Tag对象与XML或HTML原生文档中的tag(标签)相同。Tag有很多方法和属性,常用如tag.name 获取Tag的标签名称,tag.class 获取Tag的class,tag.text 获取Tag的所有显示文本(包括子Tag的文本)。
|
通过BeautifulSoup对象遍历文档树或搜索文档树生成。如bs表示一个BeautifulSoup对象,bs.p
|
NavigableString | tag中的字符串被封装在NavigableString类中。一个 NavigableString 字符串与Python中的Unicode字符串相同,并且还支持包含在 遍历文档树 和 搜索文档树 中的一些特性。 | 通过Tag对象string属性生成。 如 tag.string
|
Comment | 文档的注释部分包装在Comment类中,Comment 对象是一个特殊类型的 NavigableString 对象。 | 通过Tag对象string属性生成。 如 tag.string
|
了解更多 >> BeautifulSoup 4 文档:对象的种类
BeautifulSoup
BeautifulSoup 对象表示的是一个文档的全部内容。大部分时候,可以把它当作 Tag 对象,它支持 遍历文档树 和 搜索文档树 中描述的大部分的方法。因为 BeautifulSoup 对象并不是真正的HTML或XML的tag,所以它没有name和attribute属性。
如下生成一个BeautifulSoup 对象 bs,其中markup表示文档内容:
bs = BeautifulSoup(markup, "html.parser")
Tag
Tag对象与XML或HTML原生文档中的tag相同,Tag有很多方法和属性。标签名称通过对象.name
获取,如tag.name。标签的某个属性可以通过对象的.属性名
或[属性名]
操作获取,如tag['class']或tag.class。标签的所有属性可以通过对象的.attrs
获取,返回字典类型。示例如下:
bs = BeautifulSoup('<b class="boldest">Extremely bold</b>')
tag = bs.b #生成一个tag对象
type(tag) # <class 'bs4.element.Tag'>
#获取该标签的名字
tag.name #'b'
tag.name = "blockquote" 也可以改变标签名称
#获取属性
tag.attrs # 获取标签的所有属性,{'class': 'boldest'}
tag['class'] # 获取某个属性的值,['boldest']
#添加,删除,修改操作方法和字典一样。
tag['class'] = 'verybold' #修改tag的class属性值为verybold
tag['id'] = 1 #tag添加一个id="1"的属性
del tag['id'] #删除tag的id属性
字符串常被包含在标签tag内。Beautiful Soup用 NavigableString 类来包装tag中的字符串。使用.string一个 NavigableString 字符串与Python中的Unicode字符串相同,并且还支持包含在遍历文档树和搜索文档树中的一些特性。通过Python的 str() 方法可以直接将 NavigableString 对象转换成Unicode字符串:
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen('https://www.baidu.com')
bs = BeautifulSoup(html.read(), 'html.parser')
tag = bs.title
tag.string #'百度一下,你就知道'
type(tag.string) # <class 'bs4.element.NavigableString'>
title = str(tag.string) #'百度一下,你就知道'
type(title) # 字符串
Comment
Comment是文档的注释及特殊字符串,Comment 对象是一个特殊类型的 NavigableString 对象。
markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
soup = BeautifulSoup(markup)
comment1 = soup.b.string
type(comment1) # <class 'bs4.element.Comment'>
comment1 # 'Hey, buddy. Want to buy a used parser'
遍历文档树
子节点
一个Tag可能包含多个字符串或其它的Tag,这些都是这个Tag的子节点。Beautiful Soup提供了许多操作和遍历子节点的属性。操作文档树最简单的方法就是告诉它你想获取的tag的name。
下表中bs为一个BeautifulSoup对象,tag为一个Tag对象:
属性 | 描述 | 示例 |
---|---|---|
.标签名称 | 获取对象第一个该名称标签。 | bs.p 获取bs的第一个名称为p的标签。bs.p.b
|
.contents | 以列表形式输出对象的子节点。只包括子代节点。 | bs.contents
|
.children | 返回一个所有子节点list_iterator迭代器。只包括子代节点。 | bs.children
|
.descendants | 返回一个递归的子孙节点生成器。 | bs.descendants
|
.string | 返回节点NavigableString对象,当该节点有多个NavigableString对象,返回空。 | tag.string
|
.strings | 返回节点所有NavigableString对象生成器。 | tag.strings
|
.stripped_strings | 与.strings一样,但会去掉字符串中多余的空格或空行 | tag.stripped_strings
|
父节点
每个Tag或NavigableString都有父节点,包含在该节点中。如下:
属性 | 描述 | 示例 |
---|---|---|
.parent | 获取某个元素的父节点 | tag.parent
|
.parents |
兄弟节点
属性 | 描述 | 示例 |
---|---|---|
.next_sibling | tag.next_sibling
| |
.previous_sibling | ||
.next_siblings | tag.next_sibling
| |
.previous_siblings |
回退和前进
属性 | 描述 | 示例 |
---|---|---|
.next_element | 属性指向解析过程中下一个被解析的对象(字符串或tag),结果可能与 .next_sibling 相同,但通常是不一样的. | tag.next_element
|
.previous_element | tag.previous_element
| |
.next_elements 和 | tag.next_elements
| |
.previous_elements | tag.previous_elements
|
搜索文档树
搜索方法
Beautiful Soup定义了很多搜索方法,find_all()几乎是Beautiful Soup中最常用的搜索方法。
方法 | 描述 | 示例 |
---|---|---|
find_all() | 返回文档中符合条件的所有节点对象 | |
find() | soup.find('title') | |
find_parents() | ||
find_parent() | ||
find_next_siblings() | ||
find_next_sibling() | ||
find_previous_siblings() | ||
find_previous_sibling() | ||
find_all_next() | ||
find_next() | ||
find_all_previous() | ||
find_previous() | ||
select() | 使用CSS选择器的语法找到tag,在 Tag 或 BeautifulSoup 对象的select() 方法中传入字符串参数即可。如果仅需要CSS选择器的功能,那么可以直接使用lxml。 | bs.select("p > #toc")
|
参数
12个find开头的搜索方法,其参数和用法类似,格式都为:
function( name , attrs , recursive , string , **kwargs )
这些方法的参数如下:
参数 | 描述 | 示例 |
---|---|---|
name | 按tag的名称搜素tag,字符串对象会被自动忽略掉。 name参数的值可以是任一类型的过滤器(字符串、正则表达式、列表、函数或布尔值)。 | bs.find_all("title") 查找所有名为title的tag
|
**kwargs | 可变关键字参数,按属性来搜索tag,参数值可以是任一类型的过滤器。 常见如: id 按id来搜索tag class_ 按CSS类名(class)来搜索tag href 按href来搜索tag 当指定名字的参数不是方法内置的参数名时,会把该参数当作指定名字tag的属性来搜索。 一些没有内置的属性名,可以使用attrs参数传入。 |
bs.find(id="p1") 查看标签id='p1'。 bs.find(class_="content") 查看标签class属性包含content。
|
attrs | 标签的属性值都可以使用attrs表示,可以传入字典。css属性需要完全匹配也可以使用attrs传入。 | bs.find(attrs={'name':'commodity'}) 查找标签属性name="commodity"的标签。bs.find_all(attrs={"data-foo": "value"})
|
string | 按文档中的字符串内容搜索,参数值可以是任一类型的过滤器。 | |
limit | 限制返回结果的数量,效果与SQL中的limit关键字类似,在**kwargs接收。有时文档树很大搜索会很慢,当不需要全部结果可以使用limit参数限制。 | bs.find_all("a", limit=2)
|
recursive | 限制只搜索直接子节点,而不是全部的子孙节点。 | tag.find_all("a", recursive=False)
|
了解更多 >> Beautiful Soup 4文档:find_all()
过滤器
过滤器是筛选条件,用于搜索函数参数值,包括节点名称、节点属性、string中或他们的混合中。过滤器类型包括:字符串、正则表达式、列表、函数或布尔值。
过滤器 | 描述 | 示例 |
---|---|---|
字符串 | 最简单的过滤器是字符串,在搜索方法中传入一个字符串参数值,会匹配与字符串完全相同的值。 | bs.find("title") 查找名称为“title”的tag bs.find_all(class_ = 'section') 查找class属性为“section”的tag bs.find(id = 'toc') 查找id属性为“toc”的tag
|
正则表达式 | 如果传入正则表达式作为参数值,Beautiful Soup会通过Python中正则表达式re模块的search()函数来匹配内容。 | bs.find_all(re.compile("^b") 查找所有tag名称以"b"字母开头的tag。soup.find_all(class_ = "data", id = re.compile("t")) 查找所有tag的class属性为"data",id属性含有"t"的tag。
|
列表 | 如果传入列表参数值,Beautiful Soup会将与列表中任一元素匹配的内容返回。 | bs.find_all(["a", "div"]) 查找所有tag名称为"a"或"div"的tag。bs.find_all("div", class_ = ["section", "data"]) 查找所有tag的名称为"div",且class属性为"section"或"data"的tag。
|
布尔值 | 可以传入布尔值True或False作为参数值。 True 可以匹配任何值,但是不会返回字符串对象的节点。 | bs.find_all(True) 查找所有tag。bs.find_all(class_ = True) 查找所有含有class属性的tag。
|
函数 | 如果没有合适过滤器,那么还可以定义一个函数,函数只接受一个元素作为参数,如果这个函数返回 True 表示当前元素匹配并且被找到,如果不是则反回 False。 | 见下文 |
一个简单使用函数作为过滤器如下,该函数检测当前元素,如果包含 class 属性却不包含 id 属性,那么将返回 True:
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id')
bs.find_all(has_class_but_no_id)
CSS选择器
Tag 或 BeautifulSoup 对象的 select() 方法用于通过CSS选择器查找tag。Beautiful Soup支持大部分的CSS选择器。用法为CSS选择器作为字符串值传入select() 方法。
对于熟悉CSS选择器语法的人来说这是个非常方便的方法.Beautiful Soup也支持CSS选择器API, 如果你仅仅需要CSS选择器的功能,那么直接使用 lxml 也可以, 而且速度更快,支持更多的CSS选择器语法,但Beautiful Soup整合了CSS选择器的语法和自身方便使用API。
示例如下:
bs.select("title")
bs.select("body a")
bs.select("p > a")
bs.select("p:nth-of-type(3)")
修改文档树
Beautiful Soup的强项是文档树的搜索,但同时也可以方便的修改文档树
输出
格式化输出使用prettify() 方法,如bs.prettify()
。该方法将Beautiful Soup的文档树格式化后以Unicode编码输出,每个XML/HTML标签都独占一行。 如果不重视格式,也可以对象使用Python的str()方法,如str(bs.title)
。
如果只想得到tag中包含的文本内容,那么可以调用 get_text() 方法,这个方法获取到tag中包含的所有文版内容包括子孙tag中的内容,并将结果作为Unicode字符串返回。如bs.get_text()
。
编码
任何HTML或XML文档都有自己的编码方式,比如ASCII 或 UTF-8,但是使用Beautiful Soup解析后,文档都被转换成了Unicode。
资源
官网
- Beautiful Soup:https://www.crummy.com/software/BeautifulSoup/
- Beautiful Soup 4 中文文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/