Beautiful Soup:修订间差异

(创建页面,内容为“Beautiful Soup是一个Python库,用于从HTMLXML文件中提取数据。 ==简介== ===时间轴=== ===安装=== 可以通过下面3中方式安…”)
 
无编辑摘要
 
(未显示同一用户的10个中间版本)
第1行: 第1行:
Beautiful Soup是一个[[Python]]库,用于从[[HTML]]或[[XML]]文件中提取数据。
Beautiful Soup是一个[[Python]]库,能够方便的从[[HTML]]或[[XML]]文件中提取数据。


==简介==
==简介==
第7行: 第7行:
可以通过下面3中方式安装Beautiful Soup 4。
可以通过下面3中方式安装Beautiful Soup 4。
====通过pip安装====
====通过pip安装====
Beautiful Soup 4 通过PyPi发布,所以可以使用pip来安装:
Beautiful Soup 4 发布在[[PyPI]]平台上,所以可以使用[[pip]]来安装:
  pip install beautifulsoup4
  pip install beautifulsoup4
pip3 install beautifulsoup4  #python3中使用pip3安装


====通过软件包管理安装====
====通过软件包管理安装====
如果你用的是新版的[[Debain]]或[[Ubuntu]],那么可以通过系统的软件包管理来安装:
如果你用的是新版的[[Debain]]或[[Ubuntu]],那么也可以通过系统的软件包管理来安装:
  apt-get install Python-bs4
  apt-get install Python-bs4


第24行: 第23行:


==基础知识==
==基础知识==
===简单示例===
===获取页面===
<nowiki>from urllib.request import urlopen
获取页面可以使用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</nowiki>
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")
|-
|}
 


===HTML解析器===
{{了解更多
Beautiful Soup支持Python标准库中的[[HTML]]解析器,还支持一些第三方的解析器。
|[https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/#id13 BeautifulSoup 4 文档:安装解析器]
*Python标准库的HTML解析器,使用方法:BeautifulSoup(markup, "html.parser")
|[https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/#id53 BeautifulSoup 4 文档:指定文档解析器]
*lxml HTML解析器,安装pip install lxml,使用方法:BeautifulSoup(markup, "lxml")
}}
*html5lib HTML解析器,安装pip install html5lib,使用方法:BeautifulSoup(markup, "html5lib")


===对象===
==对象==
Beautiful Soup将复杂[[HTML]]文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:  
Beautiful Soup将复杂[[HTML]]文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:  
*Tag
{| class="wikitable"  style="width: 100%;
*NavigableString
! 类
*BeautifulSoup
! 描述
*Comment。
! 生成对象
|-
|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>
|-
|}


====Tag====
{{了解更多
Tag对象与[[XML]]或[[HTML]]原生文档中的tag相同,Tag有很多方法和属性,最重要的两个属性为name和attributes
|[https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/#id15  BeautifulSoup 4 文档:对象的种类]
}}
===BeautifulSoup ===
BeautifulSoup 对象表示的是一个文档的全部内容。大部分时候,可以把它当作 Tag 对象,它支持 遍历文档树 和 搜索文档树 中描述的大部分的方法。因为 BeautifulSoup 对象并不是真正的HTML或XML的tag,所以它没有name和attribute属性。


每个tag都有自己的名字,通过 .name 来获取。
如下生成一个BeautifulSoup 对象 bs,其中markup表示文档内容:
<nowiki>bs = BeautifulSoup('<b class="boldest">Extremely bold</b>')
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'
#'b'
tag.name = "blockquote"  也可以改变标签名称
 
#获取属性
tag.attrs      # 获取标签的所有属性,{'class': 'boldest'}
tag['class']  # 获取某个属性的值,['boldest']


#如果改变了tag的name,那将影响所有通过当前Beautiful Soup对象生成的HTML文档
#添加,删除,修改操作方法和字典一样。
tag.name = "blockquote"
tag['class'] = 'verybold'  #修改tag的class属性值为verybold
tag
tag['id'] = 1              #tag添加一个id="1"的属性
# <blockquote class="boldest">Extremely bold</blockquote></nowiki>
del tag['id']              #删除tag的id属性


一个tag可能有很多个属性,可以通过.attrs来获取,返回的类型是Python字典,也可以通过某个属性名获取属性值。
</syntaxhighlight>
<nowiki>#上面tag对象
tag.attrs
# {'class': 'boldest'}
tag['class']
# ['boldest']


#添加,删除,修改操作方法和字典一样。
tag['class'] = 'verybold'
tag['id'] = 1
tag
# <blockquote class="verybold" id="1">Extremely bold</blockquote>
#删除tag的class和id属性
del tag['class']
del tag['id']
tag
# <blockquote>Extremely bold</blockquote>


#可以包含多个值的属性,在Beautiful Soup中多值属性的返回类型是list,最常见的多值属性为class如:
bs2 = BeautifulSoup('<p class="body strikeout"></p>')
bs2.p['class']
# ["body", "strikeout"]
#如果转换的文档是XML格式,那么tag中不包含多值属性
xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml')
xml_soup.p['class']
# u'body strikeout'</nowiki>


====NavigableString ====
===NavigableString ===
字符串常被包含在标签tag内。Beautiful Soup用 NavigableString 类来包装tag中的字符串。使用.string一个 NavigableString 字符串与Python中的Unicode字符串相同,并且还支持包含在遍历文档树和搜索文档树中的一些特性。
字符串常被包含在标签tag内。Beautiful Soup用 NavigableString 类来包装tag中的字符串。使用.string一个 NavigableString 字符串与Python中的Unicode字符串相同,并且还支持包含在遍历文档树和搜索文档树中的一些特性。通过Python的 str() 方法可以直接将 NavigableString 对象转换成Unicode字符串:


<nowiki>from urllib.request import urlopen
<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'></nowiki>


====BeautifulSoup ====
title = str(tag.string)    #'百度一下,你就知道'
BeautifulSoup 对象表示的是一个文档的全部内容。大部分时候,可以把它当作 Tag 对象,它支持 遍历文档树 和 搜索文档树 中描述的大部分的方法。因为 BeautifulSoup 对象并不是真正的HTML或XML的tag,所以它没有name和attribute属性。
type(title)  # 字符串
</syntaxhighlight>


 
===Comment ===
====Comment ====
Comment是文档的注释及特殊字符串,Comment 对象是一个特殊类型的 NavigableString 对象。
Comment是文档的注释及特殊字符串,Comment 对象是一个特殊类型的 NavigableString 对象。
<nowiki>markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
<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>
# u'Hey, buddy. Want to buy a used parser'
</nowiki>


==遍历文档树==
==遍历文档树==
===子节点===
===子节点===
一个Tag可能包含多个字符串或其它的Tag,这些都是这个Tag的子节点。Beautiful Soup提供了许多操作和遍历子节点的属性。操作文档树最简单的方法就是告诉它你想获取的tag的name。如下:
一个Tag可能包含多个字符串或其它的Tag,这些都是这个Tag的子节点。Beautiful Soup提供了许多操作和遍历子节点的属性。操作文档树最简单的方法就是告诉它你想获取的tag的name。
  <nowiki>from urllib.request import urlopen
 
from bs4 import BeautifulSoup
下表中bs为一个BeautifulSoup对象,tag为一个Tag对象:
html = urlopen('https://www.baidu.com')
{| class="wikitable"  style="width: 100%;
bs = BeautifulSoup(html.read(), 'html.parser')
! 属性
! 描述
! 示例
|-
| .标签名称
| 获取对象第一个该名称标签。
| <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')


#获取 <head> 标签
bs.find_all(has_class_but_no_id)
bs.head
</syntaxhighlight>
#获取 <body> 标签
===CSS选择器===
bs.body
Tag 或 BeautifulSoup 对象的 select() 方法用于通过[[CSS]]选择器查找tag。Beautiful Soup支持大部分的[http://www.w3.org/TR/CSS2/selector.html CSS选择器]。用法为CSS选择器作为字符串值传入select() 方法。


#获取 <body> 标签中第一个<b>标签
对于熟悉CSS选择器语法的人来说这是个非常方便的方法.Beautiful Soup也支持CSS选择器API, 如果你仅仅需要CSS选择器的功能,那么直接使用 lxml 也可以, 而且速度更快,支持更多的CSS选择器语法,但Beautiful Soup整合了CSS选择器的语法和自身方便使用API。
bs.body.b


#通过点取属性的方式只能获得当前名字的第一个tag:
示例如下:
bs.a
<syntaxhighlight lang="python">
#要想取得这个名字标签的全部标签,可以使用find_all()方法
bs.find_all('a')</nowiki>


tag的 .contents 属性可以将tag的子节点以列表的方式输出:
bs.select("title")
<nowiki>head_tag = bs.head
head_tag.contents
#列表中第一个子节点
head_tag.contents[0]
#子节点个数
#len(head_tag.contents)


#BeautifulSoup 对象本身一定会包含子节点,也就是说<html>标签也是 BeautifulSoup 对象的子节点
bs.select("body a")
bs.contents[0]
#'html'</nowiki>


.contents 和 .children 属性仅包含tag的直接子节点。而.descendants属性可以对所有tag的子孙节点进行递归循环。
bs.select("p > a")


如果tag只有一个 NavigableString 类型子节点,那么这个tag可以使用 .string 得到子节点。但如果tag包含了多个子节点,tag就无法确定 .string 方法应该调用哪个子节点的内容, .string 的输出结果是 None,要使用.strings或.stripped_strings来获取,使用.stripped_strings获取时会自动除去空格和空行,全部是空格的行会被忽略掉,段首和段末的空白会被删除。
bs.select("p:nth-of-type(3)")
<nowiki>bs.title.sting
#'百度一下,你就知道'
bs.body.string
#None


#有多个NavigableString 型子节点使用.strings
</syntaxhighlight>
for string in bs.body.strings:
    print(repr(string))


#使用.stripped_strings除去空格和空行
==修改文档树==
for string in bs.stripped_strings:
Beautiful Soup的强项是文档树的搜索,但同时也可以方便的修改文档树
    print(repr(string))</nowiki>
===父节点===


==搜索文档树==
==输出==
格式化输出使用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://www.crummy.com/software/BeautifulSoup/ Beautiful Soup]
*[https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/ Beautiful Soup 4 文档]
==参考文献==
*[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库,能够方便的从HTMLXML文件中提取数据。

简介

时间轴

安装

可以通过下面3中方式安装Beautiful Soup 4。

通过pip安装

Beautiful Soup 4 发布在PyPI平台上,所以可以使用pip来安装:

pip install beautifulsoup4

通过软件包管理安装

如果你用的是新版的DebainUbuntu,那么也可以通过系统的软件包管理来安装:

apt-get install Python-bs4

下载源代码安装

下载BS4的源码,然后通过setup.py来安装。

Python setup.py install

了解更多 >> Beautiful Soup 4 文档:安装Beautiful Soup


基础知识

获取页面

获取页面可以使用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会自动选择一个已安装的,优先数序:lxmlhtml5libhtml.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")


了解更多 >> BeautifulSoup 4 文档:安装解析器 BeautifulSoup 4 文档:指定文档解析器


对象

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对象与XMLHTML原生文档中的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属性


NavigableString

字符串常被包含在标签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文档都有自己的编码方式,比如ASCIIUTF-8,但是使用Beautiful Soup解析后,文档都被转换成了Unicode

资源

官网

网站