Merge ~phoenixsite/beautifulsoup:master into beautifulsoup:master

Proposed by Carlos Romero
Status: Merged
Merged at revision: 59f273d402dc5c5ce48f78d043b701ab0b1f7764
Proposed branch: ~phoenixsite/beautifulsoup:master
Merge into: beautifulsoup:master
Diff against target: 3872 lines (+1586/-723)
2 files modified
doc.zh/source/conf.py (+1/-1)
doc.zh/source/index.rst (+1585/-722)
Reviewer Review Type Date Requested Status
Leonard Richardson Approve
Review via email: mp+458648@code.launchpad.net

Commit message

Updated the Chinese translation to version 4.12.0 from DeronW (https://groups.google.com/g/beautifulsoup/c/2U4r9sxFw7w).

Description of the change

I included the changes from DeronW's Github repo to my BS4 Launchpad repo to easily merge the changes to the master branch.

To post a comment you must log in.
Revision history for this message
Carlos Romero (phoenixsite) wrote :

Sorry, I didn't included the link to the Spanish translation.

Revision history for this message
Leonard Richardson (leonardr) :
review: Approve
Revision history for this message
Leonard Richardson (leonardr) wrote :

Thank you for taking care of this. I've restored the link to the Spanish translation.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/doc.zh/source/conf.py b/doc.zh/source/conf.py
index 102c3cf..1014dad 100644
--- a/doc.zh/source/conf.py
+++ b/doc.zh/source/conf.py
@@ -50,7 +50,7 @@ copyright = u'2012, Leonard Richardson'
50# The short X.Y version.50# The short X.Y version.
51version = '4'51version = '4'
52# The full version, including alpha/beta/rc tags.52# The full version, including alpha/beta/rc tags.
53release = '4.2.0'53release = '4.12.0'
5454
55# The language for content autogenerated by Sphinx. Refer to documentation55# The language for content autogenerated by Sphinx. Refer to documentation
56# for a list of supported languages.56# for a list of supported languages.
diff --git a/doc.zh/source/index.rst b/doc.zh/source/index.rst
index 05b9cfc..4e099cd 100644
--- a/doc.zh/source/index.rst
+++ b/doc.zh/source/index.rst
@@ -1,38 +1,47 @@
1.. BeautifulSoup文档 documentation master file, created by
2 Deron Wang on Fri Nov 29 13:49:30 2013.
3 You can adapt this file completely to your liking, but it should at least
4 contain the root `toctree` directive.
51
6Beautiful Soup 4.4.0 文档2Beautiful Soup 4.12.0 文档
7==========================3==========================
84
9`Beautiful Soup <http://www.crummy.com/software/BeautifulSoup/>`_ 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.5.. py:module:: bs4
106
11这篇文档介绍了BeautifulSoup4中所有主要特性,并且有小例子.让我来向你展示它适合做什么,如何工作,怎样使用,如何达到你想要的效果,和处理异常情况.7`Beautiful Soup <http://www.crummy.com/software/BeautifulSoup/>`_ 是一个
8可以从 HTML 或 XML 文件中提取数据的 Python 库。它能用你喜欢的解析器和习惯的方式实现
9文档树的导航、查找、和修改。它会帮你节省数小时甚至数天的工作时间。
1210
13文档中出现的例子在Python2.7和Python3.2中的执行结果相同11这篇文档介绍了 Beautiful Soup 4 中所有主要特性,并附带例子。文档会展示这个库的适合场景,
12工作原理,怎样使用,如何达到预期效果,以及如何处理异常情况。
1413
15你可能在寻找 `Beautiful Soup3 <http://www.crummy.com/software/BeautifulSoup/bs3/documentation.html>`_ 的文档,Beautiful Soup 3 目前已经停止开发,我们推荐在现在的项目中使用Beautiful Soup 4, `移植到BS4 <http://www.baidu.com>`_14文档覆盖了 Beautful Soup 4.12.0 版本,文档中的例子使用 Python 3.8 版本编写。
1615
17这篇帮助文档已经被翻译成了其它语言:16你可能在寻找 `Beautiful Soup3 <http://www.crummy.com/software/BeautifulSoup/bs3/documentation.html>`_
17的文档,Beautiful Soup 3 目前已经停止开发,并且自 2020年12月31日以后就停止维护了。
18如果想要了解 Beautiful Soup 3 和 Beautiful Soup 4 的不同,参考 `迁移到 BS4`_。
1819
19* `这篇文档当然还有中文版. <https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/>`_20这篇文档已经被翻译成多种语言:
21
22* `这篇文档当然还有中文版 <https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/>`_ ,
23 (`Github 地址 <https://github.com/DeronW/beautifulsoup>`_).
20* このページは日本語で利用できます(`外部リンク <http://kondou.com/BS4/>`_)24* このページは日本語で利用できます(`外部リンク <http://kondou.com/BS4/>`_)
21* `이 문서는 한국어 번역도 가능합니다. <https://www.crummy.com/software/BeautifulSoup/bs4/doc.ko/>`_25* `이 문서는 한국어 번역도 가능합니다. <https://www.crummy.com/software/BeautifulSoup/bs4/doc.ko/>`_
22* `Este documento também está disponível em Português do Brasil. <https://www.crummy.com/software/BeautifulSoup/bs4/doc.ptbr/>`_26* `Este documento também está disponível em Português do Brasil.
23* `Este documento también está disponible en una traducción al español. <https://www.crummy.com/software/BeautifulSoup/bs4/doc.es/>`_27 <https://www.crummy.com/software/BeautifulSoup/bs4/doc.ptbr>`_
24* `Эта документация доступна на русском языке. <https://www.crummy.com/software/BeautifulSoup/bs4/doc.ru/>`_28* `Эта документация доступна на русском языке.
25 29 <https://www.crummy.com/software/BeautifulSoup/bs4/doc.ru/>`_
2630
27寻求帮助31寻求帮助
28--------32--------
2933
30如果你有关于BeautifulSoup的问题,可以发送邮件到 `讨论组 <https://groups.google.com/forum/?fromgroups#!forum/beautifulsoup>`_ .如果你的问题包含了一段需要转换的HTML代码,那么确保你提的问题描述中附带这段HTML文档的 `代码诊断`_ [1]_34如果有关于 Beautiful Soup 4 的疑问,或遇到了问题,可以发送邮件到 `讨论组
35<https://groups.google.com/forum/?fromgroups#!forum/beautifulsoup>`_。
36
37如果问题中包含要解析的 HTML 代码,那么请在你的问题描述中附带这段HTML文档的 `代码诊断`_ [1]_。
38
39如果报告文档中的错误,请指出具体文档的语言版本。
3140
32快速开始41快速开始
33========42========
3443
35下面的一段HTML代码将作为例子被多次用到.这是 *爱丽丝梦游仙境的* 的一段内容(以后内容中简称为 *爱丽丝* 的文档):44下面的一段HTML代码将作为例子被多次用到。这是 `爱丽丝梦游仙境` 的一段内容(以后简称 *爱丽丝* 的文档):
3645
37::46::
3847
@@ -50,7 +59,8 @@ Beautiful Soup 4.4.0 文档
50 <p class="story">...</p>59 <p class="story">...</p>
51 """60 """
5261
53使用BeautifulSoup解析这段代码,能够得到一个 ``BeautifulSoup`` 的对象,并能按照标准的缩进格式的结构输出:62上面的 *爱丽丝* 文档经过 Beautiful Soup 的解析后,会得到一个 :py:class:`BeautifulSoup` 的对象,
63一个嵌套结构的对象:
5464
55::65::
5666
@@ -80,7 +90,7 @@ Beautiful Soup 4.4.0 文档
80 # Lacie90 # Lacie
81 # </a>91 # </a>
82 # and92 # and
83 # <a class="sister" href="http://example.com/tillie" id="link3">93 # <a class="sister" href="http://example.com/tillie" id="link2">
84 # Tillie94 # Tillie
85 # </a>95 # </a>
86 # ; and they lived at the bottom of a well.96 # ; and they lived at the bottom of a well.
@@ -91,7 +101,7 @@ Beautiful Soup 4.4.0 文档
91 # </body>101 # </body>
92 # </html>102 # </html>
93103
94几个简单的浏览结构化数据的方法:104这是几个简单的浏览结构化数据的方法:
95105
96::106::
97107
@@ -124,7 +134,7 @@ Beautiful Soup 4.4.0 文档
124 soup.find(id="link3")134 soup.find(id="link3")
125 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>135 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
126136
127从文档中找到所有<a>标签的链接:137常见任务之一,就是从文档中找到所有 <a> 标签的链接:
128138
129::139::
130140
@@ -134,7 +144,7 @@ Beautiful Soup 4.4.0 文档
134 # http://example.com/lacie144 # http://example.com/lacie
135 # http://example.com/tillie145 # http://example.com/tillie
136146
137从文档中获取所有文字内容:147另一种常见任务,是从文档中获取所有文字内容:
138148
139::149::
140150
@@ -151,152 +161,142 @@ Beautiful Soup 4.4.0 文档
151 #161 #
152 # ...162 # ...
153163
154这是你想要的吗?别着急,还有更好用的164这是你想要的吗?是的话,继续看下去。
155165
156安装 Beautiful Soup166安装 Beautiful Soup
157======================167======================
158168
159如果你用的是新版的Debain或ubuntu,那么可以通过系统的软件包管理来安装:169如果你用的是新版的 Debain 或 Ubuntu,那么可以通过系统的软件包管理来安装:
160
161``$ apt-get install Python-bs4``
162
163Beautiful Soup 4 通过PyPi发布,所以如果你无法使用系统包管理安装,那么也可以通过 ``easy_install`` 或 ``pip`` 来安装.包的名字是 ``beautifulsoup4`` ,这个包兼容Python2和Python3.
164
165``$ easy_install beautifulsoup4``
166170
167``$ pip install beautifulsoup4``171:kbd:`$ apt-get install python3-bs4`
168
169(在PyPi中还有一个名字是 ``BeautifulSoup`` 的包,但那可能不是你想要的,那是 `Beautiful Soup3 <http://www.crummy.com/software/BeautifulSoup/bs3/documentation.html>`_ 的发布版本,因为很多项目还在使用BS3, 所以 ``BeautifulSoup`` 包依然有效.但是如果你在编写新项目,那么你应该安装的 ``beautifulsoup4`` )
170
171如果你没有安装 ``easy_install`` 或 ``pip`` ,那你也可以 `下载BS4的源码 <http://www.crummy.com/software/BeautifulSoup/download/4.x/>`_ ,然后通过setup.py来安装.
172
173``$ Python setup.py install``
174
175如果上述安装方法都行不通,Beautiful Soup的发布协议允许你将BS4的代码打包在你的项目中,这样无须安装即可使用.
176
177作者在Python2.7和Python3.2的版本下开发Beautiful Soup, 理论上Beautiful Soup应该在所有当前的Python版本中正常工作
178
179安装完成后的问题
180-----------------
181172
182Beautiful Soup发布时打包成Python2版本的代码,在Python3环境下安装时,会自动转换成Python3的代码,如果没有一个安装的过程,那么代码就不会被转换.173Beautiful Soup 4 通过 PyPi 发布,所以如果无法使用系统包管理安装,那么
174也可以通过 ``easy_install`` 或 ``pip`` 来安装。包的名字是 ``beautifulsoup4``。
175确保使用的是与 Python 版本对应的 ``pip`` 或 ``easy_install`` 版本
176(他们的名字也可能是 ``pip3`` 和 ``easy_install`` )。
183177
184如果代码抛出了 ``ImportError`` 的异常: "No module named HTMLParser", 这是因为你在Python3版本中执行Python2版本的代码.178:kbd:`$ easy_install beautifulsoup4`
185179
180:kbd:`$ pip install beautifulsoup4`
186181
187如果代码抛出了 ``ImportError`` 的异常: "No module named html.parser", 这是因为你在Python2版本中执行Python3版本的代码.182(在 PyPi 中还有一个名字是 ``BeautifulSoup`` 的包,但那可能不是你想要的,那是
183`Beautiful Soup3`_ 版本。因为很多项目还在使用BS3, 所以 ``BeautifulSoup``
184包依然有效。但是新项目中,应该安装 ``beautifulsoup4``。)
188185
189如果遇到上述2种情况,最好的解决方法是重新安装BeautifulSoup4.186如果没有安装 ``easy_install`` 或 ``pip`` ,那也可以 `下载 BS4 的源码
187<http://www.crummy.com/software/BeautifulSoup/download/4.x/>`_ ,
188然后通过 ``setup.py`` 来安装。
190189
191如果在ROOT_TAG_NAME = u'[document]'代码处遇到 ``SyntaxError`` "Invalid syntax"错误,需要将把BS4的Python代码版本从Python2转换到Python3. 可以重新安装BS4:190:kbd:`$ Python setup.py install`
192191
193``$ Python3 setup.py install``192如果上述安装方法都行不通,根据 Beautiful Soup 的协议,可以将项目的代码打包在
193你的项目中,这样无须安装即可使用。
194194
195或在bs4的目录中执行Python代码版本转换脚本195Beautiful Soup 用 Python 3.10 版本开发,但也可以在当前的其它版本中运行。
196
197``$ 2to3-3.2 -w bs4``
198196
199安装解析器197安装解析器
200------------198--------------
201199
202Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 `lxml <http://lxml.de/>`_ .根据操作系统不同,可以选择下列方法来安装lxml:200Beautiful Soup 支持 Python 标准库中的 HTML 解析器,还支持一些第三方的解析器,
201其中一个是 `lxml parser <http://lxml.de/>`_ 。根据安装方法的不同,
202可以选择下列方法来安装 lxml:
203203
204``$ apt-get install Python-lxml``204:kbd:`$ apt-get install Python-lxml`
205205
206``$ easy_install lxml``206:kbd:`$ easy_install lxml`
207207
208``$ pip install lxml``208:kbd:`$ pip install lxml`
209209
210另一个可供选择的解析器是纯Python实现的 `html5lib <http://code.google.com/p/html5lib/>`_ , html5lib的解析方式与浏览器相同,可以选择下列方法来安装html5lib:210另一个可供选择的解析器是纯 Python 实现的 `html5lib <http://code.google.com/p/html5lib/>`_ ,
211html5lib 的解析方式与浏览器相同,根据安装方法的不同,可以选择下列方法来安装html5lib:
211212
212``$ apt-get install Python-html5lib``213:kbd:`$ apt-get install python-html5lib`
213214
214``$ easy_install html5lib``215:kbd:`$ easy_install html5lib`
215216
216``$ pip install html5lib``217:kbd:`$ pip install html5lib`
217218
218下表列出了主要的解析器,以及它们的优缺点:219下表描述了几种解析器的优缺点:
219220
220+-----------------------+---------------------------+---------------------------+---------------------------+221+-------------------+-------------------------------------------+---------------------------+------------------------------------------+
221| 解析器 | 使用方法 | 优势 | 劣势 |222| 解析器 | 使用方法 | 优势 | 劣势 |
222+=======================+===========================+===========================+===========================+223+===================+===========================================+===========================+==========================================+
223| Python标准库 | ``BeautifulSoup(markup, | - Python的内置标准库 | - Python 2.7.3 or 3.2.2)前|224|| Python 标准库 || ``BeautifulSoup(markup, "html.parser")`` || - Python的内置标准库 || - 速度没有 lxml 快,容错没有 html5lib强 |
224| | "html.parser")`` | - 执行速度适中 | 的版本中文档容错能力差 |225|| || || - 执行速度较快 || |
225| | | - 文档容错能力强 | |226|| || || - 容错能力强 || |
226| | | | |227+-------------------+-------------------------------------------+---------------------------+------------------------------------------+
227+-----------------------+---------------------------+---------------------------+---------------------------+228|| lxml HTML 解析器 || ``BeautifulSoup(markup, "lxml")`` || - 速度快 || - 额外的 C 依赖 |
228| lxml HTML 解析器 | ``BeautifulSoup(markup, | - 速度快 | - 需要安装C语言库 |229|| || || - 容错能力强 || |
229| | "lxml")`` | - 文档容错能力强 | |230|| || || || |
230| | | | |231+-------------------+-------------------------------------------+---------------------------+------------------------------------------+
231+-----------------------+---------------------------+---------------------------+---------------------------+232|| lxml XML 解析器 || ``BeautifulSoup(markup, ["lxml-xml"])`` || - 速度快 || - 额外的 C 依赖 |
232| lxml XML 解析器 | ``BeautifulSoup(markup, | - 速度快 | - 需要安装C语言库 |233|| || ``BeautifulSoup(markup, "xml")`` || - 唯一支持 XML 的解析器 || |
233| | ["lxml-xml"])`` | - 唯一支持XML的解析器 | |234+-------------------+-------------------------------------------+---------------------------+------------------------------------------+
234| | | | |235|| html5lib || ``BeautifulSoup(markup, "html5lib")`` || - 最好的容错性 || - 速度慢 |
235| | ``BeautifulSoup(markup, | | |236|| || || - 以浏览器的方式解析文档 || - 额外的 Python 依赖 |
236| | "xml")`` | | |237|| || || - 生成 HTML5 格式的文档 || |
237+-----------------------+---------------------------+---------------------------+---------------------------+238+-------------------+-------------------------------------------+---------------------------+------------------------------------------+
238| html5lib | ``BeautifulSoup(markup, | - 最好的容错性 | - 速度慢 |
239| | "html5lib")`` | - 以浏览器的方式解析文档 | - 不依赖外部扩展 |
240| | | - 生成HTML5格式的文档 | |
241+-----------------------+---------------------------+---------------------------+---------------------------+
242239
243推荐使用lxml作为解析器,因为效率更高. 在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib, 因为那些Python版本的标准库中内置的HTML解析方法不够稳定.240如果可以,推荐使用 lxml 来获得更高的速度。
244241
245提示: 如果一段HTML或XML文档格式不正确的话,那么在不同的解析器中返回的结果可能是不一样的,查看 `解析器之间的区别`_ 了解更多细节242注意,如果一段文档格式不标准,那么在不同解析器生成的 Beautiful Soup 数可能不一样。
243查看 `解析器之间的区别`_ 了解更多细节。
246244
247如何使用245如何使用
248========246========
249247
250将一段文档传入BeautifulSoup 的构造方法,就能得到一个文档的对象, 可以传入一段字符串或一个文件句柄.248解析文档是,将文档传入 :py:class:`BeautifulSoup` 的构造方法。也可以传入一段字符串
249或一个文件句柄:
251250
252::251::
253252
254 from bs4 import BeautifulSoup253 from bs4 import BeautifulSoup
255254
256 soup = BeautifulSoup(open("index.html"))255 with open("index.html") as fp:
256 soup = BeautifulSoup(fp, 'html.parser')
257257
258 soup = BeautifulSoup("<html>data</html>")258 soup = BeautifulSoup("<html>a web page</html>", 'html.parser')
259259
260首先,文档被转换成Unicode,并且HTML的实例都被转换成Unicode编码260首先,文档被转换成 Unicode,并且 HTML 中的实体也都被转换成 Unicode 编码
261261
262::262::
263263
264 BeautifulSoup("Sacr&eacute; bleu!")264 print(BeautifulSoup("<html><head></head><body>Sacr&eacute; bleu!</body></html>", "html.parser"))
265 <html><head></head><body>Sacré bleu!</body></html>265 # <html><head></head><body>Sacré bleu!</body></html>
266266
267然后,Beautiful Soup选择最合适的解析器来解析这段文档,如果手动指定解析器那么Beautiful Soup会选择指定的解析器来解析文档.(参考 `解析成XML`_ ).267然后,Beautiful Soup 选择最合适的解析器来解析这段文档。如果指定了解析器那么 Beautiful Soup
268会选择指定的解析器来解析文档。(参考 `解析成XML`_ )。
268269
269对象的种类270对象的种类
270==========271==========
271272
272Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:273Beautiful Soup 将复杂的 HTML 文档转换成一个复杂的由 Python 对象构成的树形结构,但处理对象
273``Tag`` , ``NavigableString`` , ``BeautifulSoup`` , ``Comment`` .274的过程只包含 4 种类型的对象: :py:class:`Tag`, :py:class:`NavigableString`,
275:py:class:`BeautifulSoup`, 和 :py:class:`Comment`。
274276
275Tag277:py:class:`Tag`
276-----278``Tag`` 对象与 XML 或 HTML 原生文档中的 tag 相同:
277
278``Tag`` 对象与XML或HTML原生文档中的tag相同:
279279
280::280::
281281
282 soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')282 soup = BeautifulSoup('<b class="boldest">Extremely bold</b>', 'html.parser')
283 tag = soup.b283 tag = soup.b
284 type(tag)284 type(tag)
285 # <class 'bs4.element.Tag'>285 # <class 'bs4.element.Tag'>
286286
287Tag有很多方法和属性,在 `遍历文档树`_ 和 `搜索文档树`_ 中有详细解释.现在介绍一下tag中最重要的属性: name和attributes287Tag有很多属性和方法,在 `遍历文档树`_ 和 `搜索文档树`_ 中有详细解释。
288现在介绍一下 tag 中最重要的属性: name 和 attributes。
288289
289Name290.. py:attribute:: name
290.....
291291
292每个tag都有自己的名字,通过 ``.name`` 来获取:292每个 tag 都有一个名字:
293293
294::294::
295295
296 tag.name296 tag.name
297 # u'b'297 # u'b'
298298
299如果改变了tag的name,那将影响所有通过当前Beautiful Soup对象生成的HTML文档:299如果改变了 tag 的 name,那将影响所有通过当前 Beautiful Soup 对象生成的HTML文档:
300300
301::301::
302302
@@ -304,107 +304,161 @@ Name
304 tag304 tag
305 # <blockquote class="boldest">Extremely bold</blockquote>305 # <blockquote class="boldest">Extremely bold</blockquote>
306306
307Attributes307.. py:attribute:: attrs
308............
309308
310一个tag可能有很多个属性. tag ``<b class="boldest">`` 有一个 "class" 的属性,值为 "boldest" . tag的属性的操作方法与字典相同:309一个 HTML 或 XML 的 tag 可能有很多属性。tag ``<b id="boldest">`` 有
310一个 "id" 的属性,值为 "boldest"。你可以想处理一个字段一样来处理 tag 的属性:
311311
312::312::
313313
314 tag['class']314 tag = BeautifulSoup('<b id="boldest">bold</b>', 'html.parser').b
315 # u'boldest'315 tag['id']
316 # 'boldest'
316317
317也可以直接"点"取属性, 比如: ``.attrs`` :318也可以直接"点"取属性,比如: ``.attrs`` :
318319
319::320::
320321
321 tag.attrs322 tag.attrs
322 # {u'class': u'boldest'}323 # {u'class': u'boldest'}
323324
324tag的属性可以被添加,删除或修改. 再说一次, tag的属性操作方法与字典一样325tag 的属性可以被添加、删除或修改。再说一次,tag的属性操作方法与字典一样
325326
326::327::
327328
328 tag['class'] = 'verybold'329 tag['id'] = 'verybold'
329 tag['id'] = 1330 tag['another-attribute'] = 1
330 tag331 tag
331 # <blockquote class="verybold" id="1">Extremely bold</blockquote>332 # <b another-attribute="1" id="verybold"></b>
332333
333 del tag['class']334 del tag['id']
334 del tag['id']335 del tag['another-attribute']
335 tag336 tag
336 # <blockquote>Extremely bold</blockquote>337 # <b>bold</b>
337338
338 tag['class']339 tag['id']
339 # KeyError: 'class'340 # KeyError: 'id'
340 print(tag.get('class'))341 tag.get('id')
341 # None342 # None
343
344.. _multivalue:
342345
343多值属性346多值属性
344``````````347----------
345348
346HTML 4定义了一系列可以包含多个值的属性.在HTML5中移除了一些,却增加更多.最常见的多值的属性是 class (一个tag可以有多个CSS的class). 还有一些属性 ``rel`` , ``rev`` , ``accept-charset`` , ``headers`` , ``accesskey`` . 在Beautiful Soup中多值属性的返回类型是list:349HTML 4 定义了一系列可以包含多个值的属性。在 HTML5 中移除了一些,却增加更多。
350最常见的多值的属性是 ``class`` (一个 tag 可以有多个 CSS class)。还有一些
351属性 ``rel``、 ``rev``、 ``accept-charset``、 ``headers``、 ``accesskey``。
352默认情况,Beautiful Soup 中将多值属性解析为一个列表:
347353
348::354::
349355
350 css_soup = BeautifulSoup('<p class="body strikeout"></p>')356 css_soup = BeautifulSoup('<p class="body"></p>', 'html.parser')
351 css_soup.p['class']357 css_soup.p['class']
352 # ["body", "strikeout"]358 # ['body']
359
360 css_soup = BeautifulSoup('<p class="body strikeout"></p>', 'html.parser')
361 css_soup.p['class']
362 # ['body', 'strikeout']
363
364 If an attribute `looks` like it has more than one value, but it's not
365 a multi-valued attribute as defined by any version of the HTML
366 standard, Beautiful Soup will leave the attribute alone::
353367
354 css_soup = BeautifulSoup('<p class="body"></p>')368 id_soup = BeautifulSoup('<p id="my id"></p>', 'html.parser')
355 css_soup.p['class']369 id_soup.p['id']
356 # ["body"]370 # 'my id'
357371
358如果某个属性看起来好像有多个值,但在任何版本的HTML定义中都没有被定义为多值属性,那么Beautiful Soup会将这个属性作为字符串返回372如果某个属性看起来好像有多个值,但在任何版本的 HTML 定义中都没有将其定义为多值属性,
373那么 Beautiful Soup 会将这个属性作为单值返回
359374
360::375::
361376
362 id_soup = BeautifulSoup('<p id="my id"></p>')377 id_soup = BeautifulSoup('<p id="my id"></p>', 'html.parser')
363 id_soup.p['id']378 id_soup.p['id']
364 # 'my id'379 # 'my id'
365380
366将tag转换成字符串时,多值属性会合并为一个值381将 tag 转换成字符串时,多值属性会合并为一个值
367382
368::383::
369384
370 rel_soup = BeautifulSoup('<p>Back to the <a rel="index">homepage</a></p>')385 rel_soup = BeautifulSoup('<p>Back to the <a rel="index first">homepage</a></p>', 'html.parser')
371 rel_soup.a['rel']386 rel_soup.a['rel']
372 # ['index']387 # ['index', 'first']
373 rel_soup.a['rel'] = ['index', 'contents']388 rel_soup.a['rel'] = ['index', 'contents']
374 print(rel_soup.p)389 print(rel_soup.p)
375 # <p>Back to the <a rel="index contents">homepage</a></p>390 # <p>Back to the <a rel="index contents">homepage</a></p>
376391
377如果转换的文档是XML格式,那么tag中不包含多值属性392若想强制将所有属性当做多值进行解析,可以在 :py:class:`BeautifulSoup` 构造方法中设置
393``multi_valued_attributes=None`` 参数:
394
395::
396
397 no_list_soup = BeautifulSoup('<p class="body strikeout"></p>', 'html.parser', multi_valued_attributes=None)
398 no_list_soup.p['class']
399 # 'body strikeout'
400
401或者使用 ``get_attribute_list`` 方法来获取多值列表,不管是不是一个多值属性:
402
403::
404
405 id_soup.p.get_attribute_list('id')
406 # ["my id"]
407
408如果以 XML 方式解析文档,则没有多值属性:
378409
379::410::
380411
381 xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml')412 xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml')
382 xml_soup.p['class']413 xml_soup.p['class']
383 # u'body strikeout'414 # 'body strikeout'
415
416但是,可以通过配置 ``multi_valued_attributes`` 参数来修改:
417
418::
419
420 class_is_multi= { '*' : 'class'}
421 xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml', multi_valued_attributes=class_is_multi)
422 xml_soup.p['class']
423 # ['body', 'strikeout']
424
425可能实际当中并不需要修改默认配置,默认采用的是 HTML 标准:
426
427::
384428
385可以遍历的字符串429 from bs4.builder import builder_registry
430 builder_registry.lookup('html').DEFAULT_CDATA_LIST_ATTRIBUTES
431
432.. py:class:: NavigableString
433
434可遍历的字符串
386----------------435----------------
387436
388字符串常被包含在tag内.Beautiful Soup用 ``NavigableString`` 类来包装tag中的字符串:437字符串对应 tag 中的一段文本。Beautiful Soup 用 :py:class:`NavigableString`
438类来包装 tag 中的字符串:
389439
390::440::
391441
442 soup = BeautifulSoup('<b class="boldest">Extremely bold</b>', 'html.parser')
443 tag = soup.b
392 tag.string444 tag.string
393 # u'Extremely bold'445 # 'Extremely bold'
394 type(tag.string)446 type(tag.string)
395 # <class 'bs4.element.NavigableString'>447 # <class 'bs4.element.NavigableString'>
396448
397一个 ``NavigableString`` 字符串与Python中的Unicode字符串相同,并且还支持包含在 `遍历文档树`_ 和 `搜索文档树`_ 中的一些特性. 通过 ``unicode()`` 方法可以直接将 ``NavigableString`` 对象转换成Unicode字符串:449一个 :py:class:`NavigableString` 对象与 Python 中的Unicode 字符串相同,
450并且还支持包含在 `遍历文档树`_ 和 `搜索文档树`_ 中的一些特性。通过 ``str`` 方法可以直接将
451:py:class:`NavigableString` 对象转换成 Unicode 字符串:
398452
399::453::
400454
401 unicode_string = unicode(tag.string)455 unicode_string = str(tag.string)
402 unicode_string456 unicode_string
403 # u'Extremely bold'457 # 'Extremely bold'
404 type(unicode_string)458 type(unicode_string)
405 # <type 'unicode'>459 # <type 'str'>
406460
407tag中包含的字符串不能编辑,但是可以被替换成其它的字符串,用 `replace_with()`_ 方法:461tag 中包含的字符串不能直接编辑,但是可以被替换成其它的字符串,用 :ref:`replace_with()` 方法:
408462
409::463::
410464
@@ -412,16 +466,24 @@ tag中包含的字符串不能编辑,但是可以被替换成其它的字符串,
412 tag466 tag
413 # <blockquote>No longer bold</blockquote>467 # <blockquote>No longer bold</blockquote>
414468
415``NavigableString`` 对象支持 `遍历文档树`_ 和 `搜索文档树`_ 中定义的大部分属性, 并非全部.尤其是,一个字符串不能包含其它内容(tag能够包含字符串或是其它tag),字符串不支持 ``.contents`` 或 ``.string`` 属性或 ``find()`` 方法.469:py:class:`NavigableString` 对象支持 `遍历文档树`_ 和 `搜索文档树`_ 中定义的大部分属性,
470并非全部。尤其是,一个字符串不能包含其它内容(tag 能够包含字符串或是其它 tag),字符串不支持
471``.contents`` 或 ``.string`` 属性或 ``find()`` 方法。
416472
417如果想在Beautiful Soup之外使用 ``NavigableString`` 对象,需要调用 ``unicode()`` 方法,将该对象转换成普通的Unicode字符串,否则就算Beautiful Soup已方法已经执行结束,该对象的输出也会带有对象的引用地址.这样会浪费内存.473如果想在 Beautiful Soup 之外使用 :py:class:`NavigableString` 对象,需要调用 ``unicode()``
474方法,将该对象转换成普通的Unicode字符串,否则就算 Beautiful Soup 方法已经执行结束,该对象的输出
475也会带有对象的引用地址。这样会浪费内存。
418476
419BeautifulSoup477.. py:class:: BeautifulSoup
420----------------478
479-------------------------------
421480
422``BeautifulSoup`` 对象表示的是一个文档的全部内容.大部分时候,可以把它当作 ``Tag`` 对象,它支持 `遍历文档树`_ 和 `搜索文档树`_ 中描述的大部分的方法.481``BeautifulSoup`` 对象表示的是一个文档的全部内容。大部分时候,可以把它当作 ``Tag`` 对象,
482它支持 `遍历文档树`_ 和 `搜索文档树`_ 中描述的大部分的方法。
423483
424因为 ``BeautifulSoup`` 对象并不是真正的HTML或XML的tag,所以它没有name和attribute属性.但有时查看它的 ``.name`` 属性是很方便的,所以 ``BeautifulSoup`` 对象包含了一个值为 "[document]" 的特殊属性 ``.name``484因为 ``BeautifulSoup`` 对象并不是真正的HTML或XML的tag,所以它没有name和attribute属性。
485但有时查看它的 ``.name`` 属性是很方便的,所以 ``BeautifulSoup`` 对象包含了一个
486值为 "[document]" 的特殊属性 ``.name``
425487
426::488::
427489
@@ -431,24 +493,25 @@ BeautifulSoup
431注释及特殊字符串493注释及特殊字符串
432-----------------494-----------------
433495
434``Tag`` , ``NavigableString`` , ``BeautifulSoup`` 几乎覆盖了html和xml中的所有内容,但是还有一些特殊对象.容易让人担心的内容是文档的注释部分:496:py:class:`Tag`, :py:class:`NavigableString`, :py:class:`BeautifulSoup`
497几乎覆盖了html和xml中的所有内容,但是还有一些特殊对象。容易让人担心的内容是文档的注释部分:
435498
436::499::
437500
438 markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"501 markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
439 soup = BeautifulSoup(markup)502 soup = BeautifulSoup(markup, 'html.parser')
440 comment = soup.b.string503 comment = soup.b.string
441 type(comment)504 type(comment)
442 # <class 'bs4.element.Comment'>505 # <class 'bs4.element.Comment'>
443506
444``Comment`` 对象是一个特殊类型的 ``NavigableString`` 对象:507:py:class:`Comment` 对象是一个特殊类型的 :py:class:`NavigableString` 对象:
445508
446::509::
447510
448 comment511 comment
449 # u'Hey, buddy. Want to buy a used parser'512 # u'Hey, buddy. Want to buy a used parser'
450513
451但是当它出现在HTML文档中时, ``Comment`` 对象会使用特殊的格式输出:514但是当它出现在 HTML 文档中时,:py:class:`Comment` 对象会使用特殊的格式输出:
452515
453::516::
454517
@@ -457,23 +520,61 @@ BeautifulSoup
457 # <!--Hey, buddy. Want to buy a used parser?-->520 # <!--Hey, buddy. Want to buy a used parser?-->
458 # </b>521 # </b>
459522
460Beautiful Soup中定义的其它类型都可能会出现在XML的文档中: ``CData`` , ``ProcessingInstruction`` , ``Declaration`` , ``Doctype`` .与 ``Comment`` 对象类似,这些类都是 ``NavigableString`` 的子类,只是添加了一些额外的方法的字符串独享.下面是用CDATA来替代注释的例子:
461523
462::524针对 HTML 文档
525^^^^^^^^^^^^^^^^^^
463526
464 from bs4 import CData527Beautiful Soup 定义了一些 :py:class:`NavigableString` 子类来处理特定的 HTML 标签。
465 cdata = CData("A CDATA block")528通过忽略页面中表示程序指令的字符串,可以更容易挑出页面的 body 内容。
466 comment.replace_with(cdata)529(这些类是在 Beautiful Soup 4.9.0 版本中添加的,html5lib 解析器不会使用它们)
467530
468 print(soup.b.prettify())531.. py:class:: Stylesheet
469 # <b>532
470 # <![CDATA[A CDATA block]]>533有一种 :py:class:`NavigableString` 子类表示嵌入的 CSS 脚本;
471 # </b>534内容是 ``<style>`` 标签内部的所有字符串。
535
536.. py:class:: Script
537
538有一种 :py:class:`NavigableString` 子类表示嵌入的 JavaScript 脚本;
539内容是 ``<script>`` 标签内部的所有字符串。
540
541.. py:class:: Template
542
543有一种 :py:class:`NavigableString` 子类表示嵌入的 HTML 模板,
544内容是 ``<template>`` 标签内部的所有字符串。
545
546针对 XML 文档
547^^^^^^^^^^^^^^^^^
548
549Beautiful Soup 定义了一些 :py:class:`NavigableString` 子类来处理 XML 文档中的特定
550字符串。比如 :py:class:`Comment`,这些 :py:class:`NavigableString` 的子类生成字符
551串时会添加额外内容。
552
553.. py:class:: Declaration
554
555有一种 :py:class:`NavigableString` 子类表示 XML 文档开头的
556`declaration <https://www.w3.org/TR/REC-xml/#sec-prolog-dtd>`_ 。
557
558.. py:class:: Doctype
559
560有一种 :py:class:`NavigableString` 子类表示可能出现在 XML 文档开头的
561`document type
562declaration <https://www.w3.org/TR/REC-xml/#dt-doctype>`_ 。
563
564.. py:class:: CData
565
566有一种 :py:class:`NavigableString` 子类表示
567`CData section <https://www.w3.org/TR/REC-xml/#sec-cdata-sect>`_。
568
569.. py:class:: ProcessingInstruction
570
571有一种 :py:class:`NavigableString` 子类表示 `XML 处理指令
572<https://www.w3.org/TR/REC-xml/#sec-pi>`_。
472573
473遍历文档树574遍历文档树
474==========575==========
475576
476还拿"爱丽丝梦游仙境"的文档来做例子:577还是用"爱丽丝"的文档来做例子:
477578
478::579::
479580
@@ -499,14 +600,15 @@ Beautiful Soup中定义的其它类型都可能会出现在XML的文档中: ``CD
499子节点600子节点
500-------601-------
501602
502一个Tag可能包含多个字符串或其它的Tag,这些都是这个Tag的子节点.Beautiful Soup提供了许多操作和遍历子节点的属性.603tag 可能包含多个字符串或其它的 tag,这些都是这个 Tag 的子节点。Beautiful Soup 提供了许多查找
604和操作子节点的方法。
503605
504注意: Beautiful Soup中字符串节点不支持这些属性,因为字符串没有子节点606注意: Beautiful Soup中字符串节点不支持这些属性,因为字符串没有子节点。
505607
506tag的名字608Tag 的名字
507..........609^^^^^^^^^^^^
508610
509操作文档树最简单的方法就是告诉它你想获取的tag的name.如果想获取 <head> 标签,只要用 ``soup.head`` :611操作文档树最简单的方法就是告诉它你想获取的 tag 的 name。如果想获取 <head> 标签,只要用 ``soup.head``:
510612
511::613::
512614
@@ -516,7 +618,8 @@ tag的名字
516 soup.title618 soup.title
517 # <title>The Dormouse's story</title>619 # <title>The Dormouse's story</title>
518620
519这是个获取tag的小窍门,可以在文档树的tag中多次调用这个方法.下面的代码可以获取<body>标签中的第一个<b>标签:621这是个获取tag的小窍门,可以在文档树的tag中多次调用这个方法。下面的代码可以获取 <body> 标签中的
622第一个 <b> 标签:
520623
521::624::
522625
@@ -530,7 +633,8 @@ tag的名字
530 soup.a633 soup.a
531 # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>634 # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
532635
533如果想要得到所有的<a>标签,或是通过名字得到比一个tag更多的内容的时候,就需要用到 `Searching the tree` 中描述的方法,比如: find_all()636如果想要得到所有的 <a> 标签,或是比通过名字获取内容更复杂的方法时,就需要用到 `搜索文档树`_
637中描述的方法,比如: `find_all()`
534638
535::639::
536640
@@ -539,10 +643,10 @@ tag的名字
539 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,643 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
540 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]644 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
541645
542.contents 和 .children646``.contents`` 和 ``.children``
543........................647^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
544648
545tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:649Tag 的 ``.contents`` 属性可以将 tag 的全部子节点以列表的方式输出:
546650
547::651::
548652
@@ -559,7 +663,8 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
559 title_tag.contents663 title_tag.contents
560 # [u'The Dormouse's story']664 # [u'The Dormouse's story']
561665
562``BeautifulSoup`` 对象本身一定会包含子节点,也就是说<html>标签也是 ``BeautifulSoup`` 对象的子节点:666:py:class:`BeautifulSoup` 对象一定会包含子节点。下面例子中 <html> 标签就是 ``BeautifulSoup``
667对象的子节点:
563668
564::669::
565670
@@ -568,7 +673,7 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
568 soup.contents[0].name673 soup.contents[0].name
569 # u'html'674 # u'html'
570675
571字符串没有 ``.contents`` 属性,因为字符串没有子节点:676字符串没有 ``.contents`` 属性,因为字符串没有子节点:
572677
573::678::
574679
@@ -576,7 +681,7 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
576 text.contents681 text.contents
577 # AttributeError: 'NavigableString' object has no attribute 'contents'682 # AttributeError: 'NavigableString' object has no attribute 'contents'
578683
579通过tag的 ``.children`` 生成器,可以对tag的子节点进行循环:684通过 tag 的 ``.children`` 生成器,可以对 tag 的子节点进行循环:
580685
581::686::
582687
@@ -584,17 +689,23 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
584 print(child)689 print(child)
585 # The Dormouse's story690 # The Dormouse's story
586691
587.descendants692如果想要修改 tag 的子节点,使用 `修改文档树`_ 中描述的方法。不要直接修改 ``contents`` 列表:
588..............693那样会导致细微且难以定位的问题。
694
695``.descendants``
696^^^^^^^^^^^^^^^^
589697
590``.contents`` 和 ``.children`` 属性仅包含tag的直接子节点.例如,<head>标签只有一个直接子节点<title>698``.contents`` 和 ``.children`` 属性仅包含 tag 的直接子节点。例如,<head> 标签只有一个直接
699子节点 <title>
591700
592::701::
593702
594 head_tag.contents703 head_tag.contents
595 # [<title>The Dormouse's story</title>]704 # [<title>The Dormouse's story</title>]
596705
597但是<title>标签也包含一个子节点:字符串 “The Dormouse’s story”,这种情况下字符串 “The Dormouse’s story”也属于<head>标签的子孙节点. ``.descendants`` 属性可以对所有tag的子孙节点进行递归循环 [5]_ :706但是 <title> 标签也包含一个子节点:字符串 “The Dormouse’s story”。这种情况下字符串
707“The Dormouse’s story” 也属于 <head> 标签的子节点。 ``.descendants`` 属性可以对
708所有 tag 的子孙节点进行递归循环 [5]_ ,包括子节点,子节点的子节点:
598709
599::710::
600711
@@ -603,7 +714,8 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
603 # <title>The Dormouse's story</title>714 # <title>The Dormouse's story</title>
604 # The Dormouse's story715 # The Dormouse's story
605716
606上面的例子中, <head>标签只有一个子节点,但是有2个子孙节点:<head>节点和<head>的子节点, ``BeautifulSoup`` 有一个直接子节点(<html>节点),却有很多子孙节点:717上面的例子中,<head> 标签只有一个子节点,但是有 2 个子孙节点: <head> 标签和 <head> 的子节点。
718:py:class:`BeautifulSoup` 对象只有一个直接子节点(<html> 节点),却有很多子孙节点:
607719
608::720::
609721
@@ -612,17 +724,22 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
612 len(list(soup.descendants))724 len(list(soup.descendants))
613 # 25725 # 25
614726
615.string
616........
617727
618如果tag只有一个 ``NavigableString`` 类型子节点,那么这个tag可以使用 ``.string`` 得到子节点:728.. _.string:
729
730``.string``
731^^^^^^^^^^^
732
733如果 tag 只有一个 ``NavigableString`` 类型子节点,那么这个tag可以使用 ``.string``
734得到子节点:
619735
620::736::
621737
622 title_tag.string738 title_tag.string
623 # u'The Dormouse's story'739 # u'The Dormouse's story'
624740
625如果一个tag仅有一个子节点,那么这个tag也可以使用 ``.string`` 方法,输出结果与当前唯一子节点的 ``.string`` 结果相同:741如果一个tag仅有一个子节点,那么这个tag也可以使用 ``.string`` 方法,输出结果与当前唯一
742子节点的 ``.string`` 结果相同:
626743
627::744::
628745
@@ -632,17 +749,20 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
632 head_tag.string749 head_tag.string
633 # u'The Dormouse's story'750 # u'The Dormouse's story'
634751
635如果tag包含了多个子节点,tag就无法确定 ``.string`` 方法应该调用哪个子节点的内容, ``.string`` 的输出结果是 ``None`` :752如果tag包含了多个子节点,tag就无法确定 ``.string`` 方法应该调用哪个子节点的内容,
753``.string`` 的输出结果是 ``None`` :
636754
637::755::
638756
639 print(soup.html.string)757 print(soup.html.string)
640 # None758 # None
641759
760.. _string-generators:
761
642.strings 和 stripped_strings762.strings 和 stripped_strings
643.............................763^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
644764
645如果tag中包含多个字符串 [2]_ ,可以使用 ``.strings`` 来循环获取:765如果 tag 中包含多个字符串 [2]_ ,可以使用 ``.strings`` 来循环获取:
646766
647::767::
648768
@@ -663,7 +783,7 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
663 # u'...'783 # u'...'
664 # u'\n'784 # u'\n'
665785
666输出的字符串中可能包含了很多空格或空行,使用 ``.stripped_strings`` 可以去除多余空白内容:786输出的字符串中可能包含了很多空格或空行,使用 ``.stripped_strings`` 可以去除多余空白内容:
667787
668::788::
669789
@@ -680,17 +800,20 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
680 # u';\nand they lived at the bottom of a well.'800 # u';\nand they lived at the bottom of a well.'
681 # u'...'801 # u'...'
682802
683全部是空格的行会被忽略掉,段首和段末的空白会被删除803全部是空格的行会被忽略掉,段首和段末的空白会被删除
684804
685父节点805父节点
686-------806-------
687807
688继续分析文档树,每个tag或字符串都有父节点:被包含在某个tag中808继续分析文档树,每个 tag 或字符串都有父节点: 包含当前内容的 tag
809
810.. _.parent:
689811
690.parent812.parent
691........813^^^^^^^^^^^^^
692814
693通过 ``.parent`` 属性来获取某个元素的父节点.在例子“爱丽丝”的文档中,<head>标签是<title>标签的父节点:815通过 ``.parent`` 属性来获取某个元素的父节点。在例子“爱丽丝”的文档中,<head> 标签是
816<title> 标签的父节点:
694817
695::818::
696819
@@ -700,14 +823,14 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
700 title_tag.parent823 title_tag.parent
701 # <head><title>The Dormouse's story</title></head>824 # <head><title>The Dormouse's story</title></head>
702825
703文档title的字符串也有父节点:<title>标签826文档的 title 字符串也有父节点: <title> 标签
704827
705::828::
706829
707 title_tag.string.parent830 title_tag.string.parent
708 # <title>The Dormouse's story</title>831 # <title>The Dormouse's story</title>
709832
710文档的顶层节点比如<html>的父节点是 ``BeautifulSoup`` 对象:833文档的顶层节点比如 <html> 的父节点是 ``BeautifulSoup`` 对象:
711834
712::835::
713836
@@ -722,10 +845,13 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
722 print(soup.parent)845 print(soup.parent)
723 # None846 # None
724847
848.. _.parents:
849
725.parents850.parents
726..........851^^^^^^^^^^^^
727852
728通过元素的 ``.parents`` 属性可以递归得到元素的所有父辈节点,下面的例子使用了 ``.parents`` 方法遍历了<a>标签到根节点的所有节点.853通过元素的 ``.parents`` 属性可以递归得到元素的所有父辈节点,下面的例子使用了 ``.parents``
854方法遍历了 <a> 标签到根节点的所有节点。
729855
730::856::
731857
@@ -750,10 +876,8 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
750876
751::877::
752878
753 sibling_soup = BeautifulSoup("<a><b>text1</b><c>text2</c></b></a>")879 sibling_soup = BeautifulSoup("<a><b>text1</b><c>text2</c></a>", 'html.parser')
754 print(sibling_soup.prettify())880 print(sibling_soup.prettify())
755 # <html>
756 # <body>
757 # <a>881 # <a>
758 # <b>882 # <b>
759 # text1883 # text1
@@ -762,15 +886,14 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
762 # text2886 # text2
763 # </c>887 # </c>
764 # </a>888 # </a>
765 # </body>
766 # </html>
767889
768因为<b>标签和<c>标签是同一层:他们是同一个元素的子节点,所以<b>和<c>可以被称为兄弟节点.一段文档以标准格式输出时,兄弟节点有相同的缩进级别.在代码中也可以使用这种关系.890因为 <b> 标签和 <c> 标签是同一层: 他们是同一个元素的子节点,所以 <b> 和 <c> 可以被称为兄弟节点。
891一段文档以标准格式输出时,兄弟节点有相同的缩进级别。在代码中也可以使用这种关系。
769892
770.next_sibling 和 .previous_sibling893.next_sibling 和 .previous_sibling
771....................................894^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
772895
773在文档树中,使用 ``.next_sibling`` 和 ``.previous_sibling`` 属性来查询兄弟节点:896在文档树中,使用 ``.next_sibling`` 和 ``.previous_sibling`` 属性来查询兄弟节点:
774897
775::898::
776899
@@ -780,7 +903,9 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
780 sibling_soup.c.previous_sibling903 sibling_soup.c.previous_sibling
781 # <b>text1</b>904 # <b>text1</b>
782905
783<b>标签有 ``.next_sibling`` 属性,但是没有 ``.previous_sibling`` 属性,因为<b>标签在同级节点中是第一个.同理,<c>标签有 ``.previous_sibling`` 属性,却没有 ``.next_sibling`` 属性:906<b> 标签有 ``.next_sibling`` 属性,但是没有 ``.previous_sibling`` 属性,
907因为 <b> 标签在同级节点中是第一个。同理,<c>标签有 ``.previous_sibling`` 属性,
908却没有 ``.next_sibling`` 属性:
784909
785::910::
786911
@@ -789,7 +914,7 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
789 print(sibling_soup.c.next_sibling)914 print(sibling_soup.c.next_sibling)
790 # None915 # None
791916
792例子中的字符串“text1”和“text2”不是兄弟节点,因为它们的父节点不同:917例子中的字符串 "text1" 和 "text2" 不是兄弟节点,因为它们的父节点不同:
793918
794::919::
795920
@@ -799,7 +924,8 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
799 print(sibling_soup.b.string.next_sibling)924 print(sibling_soup.b.string.next_sibling)
800 # None925 # None
801926
802实际文档中的tag的 ``.next_sibling`` 和 ``.previous_sibling`` 属性通常是字符串或空白. 看看“爱丽丝”文档:927实际文档中的 tag 的 ``.next_sibling`` 和 ``.previous_sibling`` 属性通常是字符串或空白。
928看看“爱丽丝”文档:
803929
804::930::
805931
@@ -807,7 +933,8 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
807 <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a>933 <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a>
808 <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>934 <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>
809935
810如果以为第一个<a>标签的 ``.next_sibling`` 结果是第二个<a>标签,那就错了,真实结果是第一个<a>标签和第二个<a>标签之间的顿号和换行符:936如果以为第一个 <a> 标签的 ``.next_sibling`` 结果是第二个 <a> 标签,那就错了,
937真实结果是第一个 <a> 标签和第二个<a> 标签之间的顿号和换行符:
811938
812::939::
813940
@@ -825,8 +952,10 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
825 link.next_sibling.next_sibling952 link.next_sibling.next_sibling
826 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>953 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
827954
955.. _sibling-generators:
956
828.next_siblings 和 .previous_siblings957.next_siblings 和 .previous_siblings
829......................................958^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
830959
831通过 ``.next_siblings`` 和 ``.previous_siblings`` 属性可以对当前节点的兄弟节点迭代输出:960通过 ``.next_siblings`` 和 ``.previous_siblings`` 属性可以对当前节点的兄弟节点迭代输出:
832961
@@ -834,21 +963,19 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
834963
835 for sibling in soup.a.next_siblings:964 for sibling in soup.a.next_siblings:
836 print(repr(sibling))965 print(repr(sibling))
837 # u',\n'966 # ',\n'
838 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>967 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
839 # u' and\n'968 # ' and\n'
840 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>969 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
841 # u'; and they lived at the bottom of a well.'970 # '; and they lived at the bottom of a well.'
842 # None
843971
844 for sibling in soup.find(id="link3").previous_siblings:972 for sibling in soup.find(id="link3").previous_siblings:
845 print(repr(sibling))973 print(repr(sibling))
846 # ' and\n'974 # ' and\n'
847 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>975 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
848 # u',\n'976 # ',\n'
849 # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>977 # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
850 # u'Once upon a time there were three little sisters; and their names were\n'978 # 'Once upon a time there were three little sisters; and their names were\n'
851 # None
852979
853回退和前进980回退和前进
854----------981----------
@@ -860,14 +987,20 @@ tag的 ``.contents`` 属性可以将tag的子节点以列表的方式输出:
860 <html><head><title>The Dormouse's story</title></head>987 <html><head><title>The Dormouse's story</title></head>
861 <p class="title"><b>The Dormouse's story</b></p>988 <p class="title"><b>The Dormouse's story</b></p>
862989
863HTML解析器把这段字符串转换成一连串的事件: "打开<html>标签","打开一个<head>标签","打开一个<title>标签","添加一段字符串","关闭<title>标签","打开<p>标签",等等.Beautiful Soup提供了重现解析器初始化过程的方法.990HTML解析器把这段字符串转换成一连串的事件: "打开<html>标签","打开一个<head>标签",
991"打开一个<title>标签","添加一段字符串","关闭<title>标签","打开<p>标签",等等。
992Beautiful Soup提供了重现解析器初始化过程的方法。
993
994.. _element-generators:
864995
865.next_element 和 .previous_element996.next_element 和 .previous_element
866...................................997^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
867998
868``.next_element`` 属性指向解析过程中下一个被解析的对象(字符串或tag),结果可能与 ``.next_sibling`` 相同,但通常是不一样的.999``.next_element`` 属性指向解析过程中下一个被解析的对象(字符串或tag),
1000结果可能与 ``.next_sibling`` 相同,但通常是不一样的。
8691001
870这是“爱丽丝”文档中最后一个<a>标签,它的 ``.next_sibling`` 结果是一个字符串,因为当前的解析过程 [2]_ 因为当前的解析过程因为遇到了<a>标签而中断了:1002这是“爱丽丝”文档中最后一个 <a> 标签,它的 ``.next_sibling`` 结果是一个字符串,
1003因为当前的解析过程 [2]_ 因为当前的解析过程因为遇到了<a>标签而中断了:
8711004
872::1005::
8731006
@@ -878,16 +1011,20 @@ HTML解析器把这段字符串转换成一连串的事件: "打开<html>标签"
878 last_a_tag.next_sibling1011 last_a_tag.next_sibling
879 # '; and they lived at the bottom of a well.'1012 # '; and they lived at the bottom of a well.'
8801013
881但这个<a>标签的 ``.next_element`` 属性结果是在<a>标签被解析之后的解析内容,不是<a>标签后的句子部分,应该是字符串"Tillie":1014但这个 <a> 标签的 ``.next_element`` 属性结果是在 <a> 标签被解析之后的解析内容,
1015不是 <a> 标签后的句子部分,而是字符串 "Tillie":
8821016
883::1017::
8841018
885 last_a_tag.next_element1019 last_a_tag.next_element
886 # u'Tillie'1020 # u'Tillie'
8871021
888这是因为在原始文档中,字符串“Tillie” 在分号前出现,解析器先进入<a>标签,然后是字符串“Tillie”,然后关闭</a>标签,然后是分号和剩余部分.分号与<a>标签在同一层级,但是字符串“Tillie”会被先解析.1022这是因为在原始文档中,字符串 “Tillie” 在分号前出现,解析器先进入 <a> 标签,
1023然后是字符串 “Tillie”,然后关闭 </a> 标签,然后是分号和剩余部分。
1024分号与 <a> 标签在同一层级,但是字符串 “Tillie” 会先被解析。
8891025
890``.previous_element`` 属性刚好与 ``.next_element`` 相反,它指向当前被解析的对象的前一个解析对象:1026``.previous_element`` 属性刚好与 ``.next_element`` 相反,
1027它指向当前被解析的对象的前一个解析对象:
8911028
892::1029::
8931030
@@ -897,9 +1034,10 @@ HTML解析器把这段字符串转换成一连串的事件: "打开<html>标签"
897 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>1034 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
8981035
899.next_elements 和 .previous_elements1036.next_elements 和 .previous_elements
900.....................................1037^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9011038
902通过 ``.next_elements`` 和 ``.previous_elements`` 的迭代器就可以向前或向后访问文档的解析内容,就好像文档正在被解析一样:1039通过 ``.next_elements`` 和 ``.previous_elements`` 的迭代器就可以向前或向后
1040访问文档的解析内容,就好像文档正在被解析一样:
9031041
904::1042::
9051043
@@ -914,9 +1052,10 @@ HTML解析器把这段字符串转换成一连串的事件: "打开<html>标签"
914 # None1052 # None
9151053
916搜索文档树1054搜索文档树
917==========1055============
9181056
919Beautiful Soup定义了很多搜索方法,这里着重介绍2个: ``find()`` 和 ``find_all()`` .其它方法的参数和用法类似,请读者举一反三.1057Beautiful Soup 定义了很多相似的文档搜索方法,这里着重介绍2个: ``find()`` 和 ``find_all()``,
1058其它方法的参数和用法类似,所以一笔带过。
9201059
921再以“爱丽丝”文档作为例子:1060再以“爱丽丝”文档作为例子:
9221061
@@ -939,29 +1078,38 @@ Beautiful Soup定义了很多搜索方法,这里着重介绍2个: ``find()`` 和
939 from bs4 import BeautifulSoup1078 from bs4 import BeautifulSoup
940 soup = BeautifulSoup(html_doc, 'html.parser')1079 soup = BeautifulSoup(html_doc, 'html.parser')
9411080
942使用 ``find_all()`` 类似的方法可以查找到想要查找的文档内容1081使用 ``find_all()`` 这种过滤方法,就可以检索想要查找的文档内容。
1082
1083过滤器类型
1084-------------
9431085
944过滤器1086介绍 ``find_all()`` 或类似方法前,先介绍一下这些方法可以使用哪些过滤器的类型 [3]_,
945------1087这些过滤器在搜索的 API 中反复出现。过滤器可以作用在 tag 的 name 上,节点的属性上,
1088字符串上或与他们混合使用。
9461089
947介绍 ``find_all()`` 方法前,先介绍一下过滤器的类型 [3]_ ,这些过滤器贯穿整个搜索的API.过滤器可以被用在tag的name中,节点的属性中,字符串中或他们的混合中.1090.. _字符串:
9481091
949字符串1092字符串
950............1093^^^^^^^^
9511094
952最简单的过滤器是字符串.在搜索方法中传入一个字符串参数,Beautiful Soup会查找与字符串完整匹配的内容,下面的例子用于查找文档中所有的<b>标签:1095最简单的过滤器是字符串。在搜索方法中传入一个字符串参数,Beautiful Soup
1096会查找与字符串完整匹配的内容,下面的例子用于查找文档中所有的 <b> 标签:
9531097
954::1098::
9551099
956 soup.find_all('b')1100 soup.find_all('b')
957 # [<b>The Dormouse's story</b>]1101 # [<b>The Dormouse's story</b>]
9581102
959如果传入字节码参数,Beautiful Soup会当作UTF-8编码,可以传入一段Unicode 编码来避免Beautiful Soup解析编码出错1103如果传入字节码参数,Beautiful Soup会当作UTF-8编码,可以传入一段Unicode 编码来避免
1104Beautiful Soup 解析编码出错。
1105
1106.. _正则表达式:
9601107
961正则表达式1108正则表达式
962..........1109^^^^^^^^^^^
9631110
964如果传入正则表达式作为参数,Beautiful Soup会通过正则表达式的 ``search()`` 来匹配内容.下面例子中找出所有以b开头的标签,这表示<body>和<b>标签都应该被找到:1111如果传入正则表达式作为参数,Beautiful Soup 会通过正则表达式的 ``match()`` 来匹配内容。
1112下面例子中找出所有以 b 开头的标签,这种情况下 <body> 和 <b> 标签都会被找到:
9651113
966::1114::
9671115
@@ -971,7 +1119,7 @@ Beautiful Soup定义了很多搜索方法,这里着重介绍2个: ``find()`` 和
971 # body1119 # body
972 # b1120 # b
9731121
974下面代码找出所有名字中包含"t"的标签:1122下面代码找出所有名字中包含 "t" 的标签:
9751123
976::1124::
9771125
@@ -980,10 +1128,13 @@ Beautiful Soup定义了很多搜索方法,这里着重介绍2个: ``find()`` 和
980 # html1128 # html
981 # title1129 # title
9821130
1131.. _列表:
1132
983列表1133列表
984....1134^^^^^^
9851135
986如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回.下面代码找到文档中所有<a>标签和<b>标签:1136如果传入列表参数,Beautiful Soup会 将与列表中任一元素匹配的内容返回。
1137下面代码找到文档中所有 <a> 标签和 <b> 标签:
9871138
988::1139::
9891140
@@ -993,10 +1144,12 @@ Beautiful Soup定义了很多搜索方法,这里着重介绍2个: ``find()`` 和
993 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,1144 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
994 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]1145 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
9951146
1147.. _True:
1148
996True1149True
997.....1150^^^^^^
9981151
999``True`` 可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点1152``True`` 可以匹配任何值,下面代码查找到所有的 tag,但是不会返回字符串节点
10001153
1001::1154::
10021155
@@ -1014,19 +1167,23 @@ True
1014 # a1167 # a
1015 # p1168 # p
10161169
1017方法1170.. _函数:
1018....
10191171
1020如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数 [4]_ ,如果这个方法返回 ``True`` 表示当前元素匹配并且被找到,如果不是则反回 ``False``1172函数
1173^^^^^^
10211174
1022下面方法校验了当前元素,如果包含 ``class`` 属性却不包含 ``id`` 属性,那么将返回 ``True``:1175如果没有合适过滤器,那么还可以定义一个函数方法,参数是一个元素 [4]_ ,
1176如果这个方法返回 ``True`` 表示当前元素匹配并且被找到,如果不是则反回 ``False``。
1177
1178下面方法实现的匹配功能是,如果包含 ``class`` 属性却不包含 ``id`` 属性,
1179那么将返回 ``True``:
10231180
1024::1181::
10251182
1026 def has_class_but_no_id(tag):1183 def has_class_but_no_id(tag):
1027 return tag.has_attr('class') and not tag.has_attr('id')1184 return tag.has_attr('class') and not tag.has_attr('id')
10281185
1029将这个方法作为参数传入 ``find_all()`` 方法,将得到所有<p>标签:1186将这个方法作为参数传入 ``find_all()`` 方法,将得到所有 <p> 标签:
10301187
1031::1188::
10321189
@@ -1035,21 +1192,20 @@ True
1035 # <p class="story">Once upon a time there were...</p>,1192 # <p class="story">Once upon a time there were...</p>,
1036 # <p class="story">...</p>]1193 # <p class="story">...</p>]
10371194
1038返回结果中只有<p>标签没有<a>标签,因为<a>标签还定义了"id",没有返回<html>和<head>,因为<html>和<head>中没有定义"class"属性.1195返回结果中只有 <p> 标签,没有 <a> 标签,因为 <a> 标签还定义了"id",
10391196没有返回 <html> 和 <head>,因为 <html> 和 <head> 中没有定义 "class" 属性。
1040通过一个方法来过滤一类标签属性的时候, 这个方法的参数是要被过滤的属性的值, 而不是这个标签.
1041下面的例子是找出 ``href`` 属性不符合指定正则的 ``a`` 标签.
1042
1043::
10441197
1198如果通过方法来筛选特殊属性,比如 ``href``,传入方法的参数应该是对应属性的值,
1199而不是整个元素。下面的例子是找出那些 ``a`` 标签中的 ``href`` 属性不匹配指定正则::
10451200
1046 def not_lacie(href):1201 def not_lacie(href):
1047 return href and not re.compile("lacie").search(href)1202 return href and not re.compile("lacie").search(href)
1203
1048 soup.find_all(href=not_lacie)1204 soup.find_all(href=not_lacie)
1049 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,1205 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
1050 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]1206 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
10511207
1052标签过滤方法可以使用复杂方法. 下面的例子可以过滤出前后都有文字的标签.1208标签过滤方法可以使用复杂方法。下面的例子可以过滤出前后都有文字的标签。
10531209
1054::1210::
10551211
@@ -1071,9 +1227,11 @@ True
1071find_all()1227find_all()
1072-----------1228-----------
10731229
1074find_all( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )1230find_all(`name`_ , `attrs`_ , `recursive <recursive>`_ , `string <string>`_ ,
1231`**kwargs <kwargs>`_ )
10751232
1076``find_all()`` 方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件.这里有几个例子:1233``find_all()`` 方法搜索当前 tag 的所有子节点,并判断是否符合过滤器的条件。
1234`过滤器类型`_ 中已经举过几个例子,这里再展示几个新例子:
10771235
1078::1236::
10791237
@@ -1095,12 +1253,17 @@ find_all( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )
1095 soup.find(string=re.compile("sisters"))1253 soup.find(string=re.compile("sisters"))
1096 # u'Once upon a time there were three little sisters; and their names were\n'1254 # u'Once upon a time there were three little sisters; and their names were\n'
10971255
1098有几个方法很相似,还有几个方法是新的,参数中的 ``string`` 和 ``id`` 是什么含义? 为什么 ``find_all("p", "title")`` 返回的是CSS Class为"title"的<p>标签? 我们来仔细看一下 ``find_all()`` 的参数1256有几个方法很相似,还有几个方法是新的,参数中的 ``string`` 和 ``id`` 是什么含义?
1257为什么 ``find_all("p", "title")`` 返回的是CSS Class为"title"的<p>标签?
1258我们来仔细看一下 ``find_all()`` 的参数
1259
1260.. _name:
10991261
1100name 参数1262name 参数
1101..........1263^^^^^^^^^^^
11021264
1103``name`` 参数可以查找所有名字为 ``name`` 的tag,字符串对象会被自动忽略掉.1265传一个值给 ``name`` 参数,就可以查找所有名字为 ``name`` 的 tag。所有文本都会被忽略掉,
1266因为它们不匹配标签名字。
11041267
1105简单的用法如下:1268简单的用法如下:
11061269
@@ -1109,19 +1272,24 @@ name 参数
1109 soup.find_all("title")1272 soup.find_all("title")
1110 # [<title>The Dormouse's story</title>]1273 # [<title>The Dormouse's story</title>]
11111274
1112重申: 搜索 ``name`` 参数的值可以使任一类型的 `过滤器`_ ,字符窜,正则表达式,列表,方法或是 ``True`` .1275回忆 `过滤器类型`_ 中描述的内容,搜索 ``name`` 的参数值可以是:
1276字符串、正则表达式、列表、方法或是 ``True`` 。
1277
1278.. _kwargs:
11131279
1114keyword 参数1280keyword 参数
1115..............1281^^^^^^^^^^^^^^^
11161282
1117如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索,如果包含一个名字为 ``id`` 的参数,Beautiful Soup会搜索每个tag的"id"属性.1283如果动态参数中出现未能识别的参数名,搜索时会把该参数当作 tag 属性来搜索,
1284比如搜索参数中包含一个名字为 ``id`` 的参数,Beautiful Soup 会搜索每个
1285tag 上的 ``id`` 属性
11181286
1119::1287::
11201288
1121 soup.find_all(id='link2')1289 soup.find_all(id='link2')
1122 # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]1290 # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
11231291
1124如果传入 ``href`` 参数,Beautiful Soup会搜索每个tag的"href"属性:1292如果传入 ``href`` 参数,Beautiful Soup会搜索每个 tag 的 ``href`` 属性
11251293
1126::1294::
11271295
@@ -1130,7 +1298,7 @@ keyword 参数
11301298
1131搜索指定名字的属性时可以使用的参数值包括 `字符串`_ , `正则表达式`_ , `列表`_, `True`_ .1299搜索指定名字的属性时可以使用的参数值包括 `字符串`_ , `正则表达式`_ , `列表`_, `True`_ .
11321300
1133下面的例子在文档树中查找所有包含 ``id`` 属性的tag,无论 ``id`` 的值是什么:1301下面的例子在文档树中查找所有包含 ``id`` 属性的 tag,无论 ``id`` 的值是什么:
11341302
1135::1303::
11361304
@@ -1139,14 +1307,14 @@ keyword 参数
1139 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,1307 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
1140 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]1308 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
11411309
1142使用多个指定名字的参数可以同时过滤tag的多个属性:1310使用多个指定名字的参数可以同时过滤多个 tag 属性:
11431311
1144::1312::
11451313
1146 soup.find_all(href=re.compile("elsie"), id='link1')1314 soup.find_all(href=re.compile("elsie"), id='link1')
1147 # [<a class="sister" href="http://example.com/elsie" id="link1">three</a>]1315 # [<a class="sister" href="http://example.com/elsie" id="link1">three</a>]
11481316
1149有些tag属性在搜索不能使用,比如HTML5中的 data-* 属性:1317有些 tag 属性在搜索不能使用,比如HTML5中的 data-* 属性:
11501318
1151::1319::
11521320
@@ -1154,17 +1322,33 @@ keyword 参数
1154 data_soup.find_all(data-foo="value")1322 data_soup.find_all(data-foo="value")
1155 # SyntaxError: keyword can't be an expression1323 # SyntaxError: keyword can't be an expression
11561324
1157但是可以通过 ``find_all()`` 方法的 ``attrs`` 参数定义一个字典参数来搜索包含特殊属性的tag:1325这种情况下可以通过 ``find_all()`` 方法的 ``attrs`` 参数定义一个字典参数
1326来搜索包含特殊属性的 tag:
11581327
1159::1328::
11601329
1161 data_soup.find_all(attrs={"data-foo": "value"})1330 data_soup.find_all(attrs={"data-foo": "value"})
1162 # [<div data-foo="value">foo!</div>]1331 # [<div data-foo="value">foo!</div>]
11631332
1333不要使用 "name" 作为关键字参数搜索 HTML 元素,因为 Beautiful Soup 用 ``name``
1334来识别 tag 本身的名字。换一种方法,你可以这样搜索属性中的 "name" 值
1335
1336::
1337
1338 name_soup = BeautifulSoup('<input name="email"/>', 'html.parser')
1339 name_soup.find_all(name="email")
1340 # []
1341 name_soup.find_all(attrs={"name": "email"})
1342 # [<input name="email"/>]
1343
1344.. _attrs:
1345
1164按CSS搜索1346按CSS搜索
1165..........1347^^^^^^^^^^^
11661348
1167按照CSS类名搜索tag的功能非常实用,但标识CSS类名的关键字 ``class`` 在Python中是保留字,使用 ``class`` 做参数会导致语法错误.从Beautiful Soup的4.1.1版本开始,可以通过 ``class_`` 参数搜索有指定CSS类名的tag:1349按照 CSS 类名搜索的功能非常实用,但标识 CSS 类名的关键字 ``class`` 在Python中是保留字,
1350使用 ``class`` 做参数会导致语法错误。从 Beautiful Soup 4.1.2 版本开始,可以通过 ``class_``
1351参数搜索有指定CSS类名的 tag:
11681352
1169::1353::
11701354
@@ -1173,7 +1357,8 @@ keyword 参数
1173 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,1357 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
1174 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]1358 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
11751359
1176``class_`` 参数同样接受不同类型的 ``过滤器`` ,字符串,正则表达式,方法或 ``True`` :1360作为关键字形式的参数 ``class_`` 同样接受不同类型的 ``过滤器``,字符串、正则表达式、
1361方法或 ``True`` :
11771362
1178::1363::
11791364
@@ -1188,7 +1373,7 @@ keyword 参数
1188 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,1373 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
1189 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]1374 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
11901375
1191tag的 ``class`` 属性是 `多值属性`_ .按照CSS类名搜索tag时,可以分别搜索tag中的每个CSS类名:1376tag 的 ``class`` 属性是 `多值属性`_ 。按照 CSS 类名搜索时,表示匹配到 tag 中任意 CSS 类名:
11921377
1193::1378::
11941379
@@ -1199,14 +1384,29 @@ tag的 ``class`` 属性是 `多值属性`_ .按照CSS类名搜索tag时,可以
1199 css_soup.find_all("p", class_="body")1384 css_soup.find_all("p", class_="body")
1200 # [<p class="body strikeout"></p>]1385 # [<p class="body strikeout"></p>]
12011386
1202搜索 ``class`` 属性时也可以通过CSS值完全匹配:1387搜索 ``class`` 属性时也可以通过 CSS 值进行完全匹配:
12031388
1204::1389::
12051390
1206 css_soup.find_all("p", class_="body strikeout")1391 css_soup.find_all("p", class_="body strikeout")
1207 # [<p class="body strikeout"></p>]1392 # [<p class="body strikeout"></p>]
12081393
1209完全匹配 ``class`` 的值时,如果CSS类名的顺序与实际不符,将搜索不到结果:1394完全匹配 ``class`` 的值时,如果CSS类名的顺序与实际不符,将搜索不到结果:
1395
1396::
1397
1398 css_soup.find_all("p", class_="strikeout body")
1399 # []
1400
1401如果想要通过多个 CSS 类型来搜索 tag,应该使用 CSS 选择器
1402
1403::
1404
1405 css_soup.select("p.strikeout.body")
1406 # [<p class="body strikeout"></p>]
1407
1408在旧版本的 Beautiful Soup 中,可能不支持 ``class_``,这时可以使用 ``attrs`` 实现相同效果。
1409创建一个字典,包含要搜索的 class 类名(或者正则表达式等形式)
12101410
1211::1411::
12121412
@@ -1215,10 +1415,13 @@ tag的 ``class`` 属性是 `多值属性`_ .按照CSS类名搜索tag时,可以
1215 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,1415 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
1216 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]1416 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
12171417
1218``string`` 参数1418.. _string2:
1219...............1419
1420string 参数
1421^^^^^^^^^^^^^^^^^^^^^^^
12201422
1221通过 ``string`` 参数可以搜搜文档中的字符串内容.与 ``name`` 参数的可选值一样, ``string`` 参数接受 `字符串`_ , `正则表达式`_ , `列表`_, `True`_ . 看例子:1423通过 ``string`` 参数可以搜索文档中的字符串内容。与 ``name`` 参数接受的值一样,
1424``string`` 参数接受 `字符串`_ , `正则表达式`_ , `列表`_, `函数`_, `True`_ 。看例子:
12221425
1223::1426::
12241427
@@ -1238,19 +1441,32 @@ tag的 ``class`` 属性是 `多值属性`_ .按照CSS类名搜索tag时,可以
1238 soup.find_all(string=is_the_only_string_within_a_tag)1441 soup.find_all(string=is_the_only_string_within_a_tag)
1239 # [u"The Dormouse's story", u"The Dormouse's story", u'Elsie', u'Lacie', u'Tillie', u'...']1442 # [u"The Dormouse's story", u"The Dormouse's story", u'Elsie', u'Lacie', u'Tillie', u'...']
12401443
1241虽然 ``string`` 参数用于搜索字符串,还可以与其它参数混合使用来过滤tag.Beautiful Soup会找到 ``.string`` 方法与 ``string`` 参数值相符的tag.下面代码用来搜索内容里面包含“Elsie”的<a>标签:1444虽然 ``string`` 参数用于搜索字符串,同时也以与其它参数混合使用来搜索 tag。
1445Beautiful Soup 会过滤那些 ``string`` 值与 ``.string`` 参数相符的 tag。
1446下面代码用来搜索内容里面包含 “Elsie” 的 <a> 标签:
12421447
1243::1448::
12441449
1245 soup.find_all("a", string="Elsie")1450 soup.find_all("a", string="Elsie")
1246 # [<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>]1451 # [<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>]
12471452
1453``string`` 参数是在 4.4.0 中新增的。早期版本中该参数名为 ``text``。
1454
1455::
1456
1457 soup.find_all("a", text="Elsie")
1458 # [<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>]
1459
1248``limit`` 参数1460``limit`` 参数
1249...............1461^^^^^^^^^^^^^^^^
12501462
1251``find_all()`` 方法返回全部的搜索结构,如果文档树很大那么搜索会很慢.如果我们不需要全部结果,可以使用 ``limit`` 参数限制返回结果的数量.效果与SQL中的limit关键字类似,当搜索到的结果数量达到 ``limit`` 的限制时,就停止搜索返回结果.1463``find_all()`` 方法会返回全部的搜索结构,如果文档树很大那么搜索会很慢。
1464如果我们不需要全部结果,可以使用 ``limit`` 参数限制返回结果的数量。
1465效果与SQL中的limit关键字类似,当搜索到的结果数量达到 ``limit`` 的限制时,
1466就停止搜索返回结果。
12521467
1253文档树中有3个tag符合搜索条件,但结果只返回了2个,因为我们限制了返回数量:1468“爱丽丝”文档例子中有 3 个 tag 符合搜索条件,但下面例子中的结果只返回了 2 个,
1469因为我们限制了返回数量:
12541470
1255::1471::
12561472
@@ -1258,24 +1474,13 @@ tag的 ``class`` 属性是 `多值属性`_ .按照CSS类名搜索tag时,可以
1258 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,1474 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
1259 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]1475 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
12601476
1261``recursive`` 参数1477.. _recursive2:
1262...................
1263
1264调用tag的 ``find_all()`` 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 ``recursive=False`` .
1265
1266一段简单的文档:
12671478
1268::1479``recursive`` 参数
12691480^^^^^^^^^^^^^^^^^^^^^^^
1270 <html>
1271 <head>
1272 <title>
1273 The Dormouse's story
1274 </title>
1275 </head>
1276 ...
12771481
1278是否使用 ``recursive`` 参数的搜索结果:1482如果调用 ``mytag.find_all()`` 方法,Beautiful Soup 会检索 ``mytag`` 的所有子孙节点,
1483如果只想搜索直接子节点,可以使用参数 ``recursive=False``。查看下面例子
12791484
1280::1485::
12811486
@@ -1285,30 +1490,32 @@ tag的 ``class`` 属性是 `多值属性`_ .按照CSS类名搜索tag时,可以
1285 soup.html.find_all("title", recursive=False)1490 soup.html.find_all("title", recursive=False)
1286 # []1491 # []
12871492
1288这是文档片段1493下面一段简单的文档:
12891494
1290::1495::
12911496
1292 <html>1497 <html>
1293 <head>1498 <head>
1294 <title>1499 <title>
1295 The Dormouse's story1500 The Dormouse's story
1296 </title>1501 </title>
1297 </head>1502 </head>
1298 ...1503 ...
12991504
1300<title>标签在 <html> 标签下, 但并不是直接子节点, <head> 标签才是直接子节点.1505<title> 标签在 <html> 标签之下,但并不是直接子节点,<head> 标签才是直接子节点。
1301在允许查询所有后代节点时 Beautiful Soup 能够查找到 <title> 标签.1506在允许查询所有后代节点时 Beautiful Soup 能够查找到 <title> 标签。
1302但是使用了 ``recursive=False`` 参数之后,只能查找直接子节点,这样就查不到 <title> 标签了.1507但是使用了 ``recursive=False`` 参数之后,只能查找直接子节点,这样就查不到 <title> 标签了。
13031508
1304Beautiful Soup 提供了多种DOM树搜索方法. 这些方法都使用了类似的参数定义.1509Beautiful Soup 提供了多种 DOM 树搜索方法。这些方法都使用了类似的参数定义。
1305比如这些方法: ``find_all()``: ``name``, ``attrs``, ``text``, ``limit``.1510比如这些方法: ``find_all()``: ``name``, ``attrs``, ``text``, ``limit``.
1306但是只有 ``find_all()`` 和 ``find()`` 支持 ``recursive`` 参数.1511但是只有 ``find_all()`` 和 ``find()`` 支持 ``recursive`` 参数。
13071512
1308像调用 ``find_all()`` 一样调用tag1513像调用 ``find_all()`` 一样调用tag
1309----------------------------------1514----------------------------------
13101515
1311``find_all()`` 几乎是Beautiful Soup中最常用的搜索方法,所以我们定义了它的简写方法. ``BeautifulSoup`` 对象和 ``tag`` 对象可以被当作一个方法来使用,这个方法的执行结果与调用这个对象的 ``find_all()`` 方法相同,下面两行代码是等价的:1516``find_all()`` 几乎是 Beautiful Soup 中最常用的搜索方法,所以我们定义了它的简写方法。
1517``BeautifulSoup`` 对象和 ``Tag`` 对象可以被当作一个方法来使用,这个方法的执行结果与
1518调用这个对象的 ``find_all()`` 方法相同,下面两行代码是等价的:
13121519
1313::1520::
13141521
@@ -1325,9 +1532,13 @@ Beautiful Soup 提供了多种DOM树搜索方法. 这些方法都使用了类似
1325find()1532find()
1326-------1533-------
13271534
1328find( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )1535find(`name`_ , `attrs`_ , `recursive <recursive>`_ , `string <string>`_ ,
1536`**kwargs <kwargs>`_ )
13291537
1330``find_all()`` 方法将返回文档中符合条件的所有tag,尽管有时候我们只想得到一个结果.比如文档中只有一个<body>标签,那么使用 ``find_all()`` 方法来查找<body>标签就不太合适, 使用 ``find_all`` 方法并设置 ``limit=1`` 参数不如直接使用 ``find()`` 方法.下面两行代码是等价的:1538``find_all()`` 方法将返回文档中符合条件的所有 tag,尽管有时候我们只想得到一个结果。
1539比如文档中只有一个 <body> 标签,那么使用 ``find_all()`` 方法来查找 <body> 标签就
1540不太合适,使用 ``find_all`` 方法并设置 ``limit=1`` 参数不如直接使用 ``find()`` 方法。
1541下面两行代码是等价的:
13311542
1332::1543::
13331544
@@ -1337,16 +1548,18 @@ find( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )
1337 soup.find('title')1548 soup.find('title')
1338 # <title>The Dormouse's story</title>1549 # <title>The Dormouse's story</title>
13391550
1340唯一的区别是 ``find_all()`` 方法的返回结果是值包含一个元素的列表,而 ``find()`` 方法直接返回结果.1551唯一的区别是 ``find_all()`` 方法的返回结果是值包含一个元素的列表,而 ``find()`` 方法
1552直接返回结果。
13411553
1342``find_all()`` 方法没有找到目标是返回空列表, ``find()`` 方法找不到目标时,返回 ``None`` .1554``find_all()`` 方法没有找到目标是返回空列表, ``find()`` 方法找不到目标时,返回 ``None``。
13431555
1344::1556::
13451557
1346 print(soup.find("nosuchtag"))1558 print(soup.find("nosuchtag"))
1347 # None1559 # None
13481560
1349``soup.head.title`` 是 `tag的名字`_ 方法的简写.这个简写的原理就是多次调用当前tag的 ``find()`` 方法:1561``soup.head.title`` 是 `Tag 的名字`_ 方法的简写。这个简写就是通过多次调用 ``find()`` 方
1562法实现的:
13501563
1351::1564::
13521565
@@ -1359,13 +1572,20 @@ find( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )
1359find_parents() 和 find_parent()1572find_parents() 和 find_parent()
1360--------------------------------1573--------------------------------
13611574
1362find_parents( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )1575find_parents( `name`_ , `attrs`_ , `recursive <recursive>`_ ,
1576`string <string>`_ , `**kwargs <kwargs>`_ )
13631577
1364find_parent( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )1578find_parent( `name`_ , `attrs`_ , `recursive <recursive>`_ ,
1579`string <string>`_ , `**kwargs <kwargs>`_ )
13651580
1366我们已经用了很大篇幅来介绍 ``find_all()`` 和 ``find()`` 方法,Beautiful Soup中还有10个用于搜索的API.它们中的五个用的是与 ``find_all()`` 相同的搜索参数,另外5个与 ``find()`` 方法的搜索参数类似.区别仅是它们搜索文档的不同部分.1581我们已经用了很大篇幅来介绍 ``find_all()`` 和 ``find()`` 方法,Beautiful Soup 中
1582还有 10 个用于搜索的 API。它们中有 5 个用的是与 ``find_all()`` 相同的搜索参数,
1583另外 5 个与 ``find()`` 方法的搜索参数类似。区别仅是它们搜索文档的位置不同。
13671584
1368记住: ``find_all()`` 和 ``find()`` 只搜索当前节点的所有子节点,孙子节点等. ``find_parents()`` 和 ``find_parent()`` 用来搜索当前节点的父辈节点,搜索方法与普通tag的搜索方法相同,搜索文档\搜索文档包含的内容. 我们从一个文档中的一个叶子节点开始:1585首先来看看 ``find_parents()`` 和 ``find_parent()``。
1586记住: ``find_all()`` 和 ``find()`` 只搜索当前节点的所有子节点,孙子节点等。
1587而这 2 个方法刚好相反,它们用来搜索当前节点的父辈节点。
1588我们来试试看,从例子文档中的一个深层叶子节点开始:
13691589
1370::1590::
13711591
@@ -1383,21 +1603,29 @@ find_parent( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )
1383 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;1603 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
1384 # and they lived at the bottom of a well.</p>1604 # and they lived at the bottom of a well.</p>
13851605
1386 a_string.find_parents("p", class_="title")1606 a_string.find_parents("p", class="title")
1387 # []1607 # []
13881608
1389文档中的一个<a>标签是是当前叶子节点的直接父节点,所以可以被找到.还有一个<p>标签,是目标叶子节点的间接父辈节点,所以也可以被找到.包含class值为"title"的<p>标签不是不是目标叶子节点的父辈节点,所以通过 ``find_parents()`` 方法搜索不到.1609文档中的一个 <a> 标签是是当前叶子节点的直接父节点,所以可以被找到。
1610还有一个 <p> 标签,是目标叶子节点的间接父辈节点,所以也可以被找到。
1611包含 class 值为 "title" 的 <p> 标签不是不是目标叶子节点的父辈节点,
1612所以通过 ``find_parents()`` 方法搜索不到。
13901613
1391``find_parent()`` 和 ``find_parents()`` 方法会让人联想到 `.parent`_ 和 `.parents`_ 属性.它们之间的联系非常紧密.搜索父辈节点的方法实际上就是对 ``.parents`` 属性的迭代搜索.1614``find_parent()`` 和 ``find_parents()`` 方法会让人联想到 `.parent`_ 和 `.parents`_ 属性。
1615它们之间的联系非常紧密。搜索父辈节点的方法实际上就是对 ``.parents`` 属性的迭代搜索。
13921616
1393find_next_siblings() 和 find_next_sibling()1617find_next_siblings() 和 find_next_sibling()
1394-------------------------------------------1618-------------------------------------------
13951619
1396find_next_siblings( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )1620find_next_siblings( `name`_ , `attrs`_ , `recursive <recursive>`_ ,
1621`string <string>`_ , `**kwargs <kwargs>`_ )
13971622
1398find_next_sibling( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )1623find_next_sibling( `name`_ , `attrs`_ , `recursive <recursive>`_ ,
1624`string <string>`_ , `**kwargs <kwargs>`_ )
13991625
1400这2个方法通过 `.next_siblings`_ 属性对当tag的所有后面解析 [5]_ 的兄弟tag节点进行迭代, ``find_next_siblings()`` 方法返回所有符合条件的后面的兄弟节点, ``find_next_sibling()`` 只返回符合条件的后面的第一个tag节点.1626这 2 个方法通过 `.next_siblings <sibling-generators>`_ 属性对当 tag 的所有后面解析 [5]_
1627的兄弟tag节点进行迭代, ``find_next_siblings()`` 方法返回所有符合条件的后面的兄弟节点,
1628``find_next_sibling()`` 只返回符合条件的后面的第一个 tag 节点。
14011629
1402::1630::
14031631
@@ -1416,11 +1644,15 @@ find_next_sibling( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )
1416find_previous_siblings() 和 find_previous_sibling()1644find_previous_siblings() 和 find_previous_sibling()
1417-----------------------------------------------------1645-----------------------------------------------------
14181646
1419find_previous_siblings( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )1647find_previous_siblings( `name`_ , `attrs`_ , `recursive <recursive>`_ ,
1648`string <string>`_ , `**kwargs <kwargs>`_ )
14201649
1421find_previous_sibling( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )1650find_previous_sibling( `name`_ , `attrs`_ , `recursive <recursive>`_ ,
1651`string <string>`_ , `**kwargs <kwargs>`_ )
14221652
1423这2个方法通过 `.previous_siblings`_ 属性对当前tag的前面解析 [5]_ 的兄弟tag节点进行迭代, ``find_previous_siblings()`` 方法返回所有符合条件的前面的兄弟节点, ``find_previous_sibling()`` 方法返回第一个符合条件的前面的兄弟节点:1653这 2 个方法通过 `.previous_siblings <sibling-generators>`_ 属性对当前 tag 的前面解析 [5]_
1654的兄弟 tag 节点进行迭代, ``find_previous_siblings()`` 方法返回所有符合条件的前面的兄弟节点,
1655``find_previous_sibling()`` 方法返回第一个符合条件的前面的兄弟节点:
14241656
1425::1657::
14261658
@@ -1439,11 +1671,15 @@ find_previous_sibling( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs
1439find_all_next() 和 find_next()1671find_all_next() 和 find_next()
1440--------------------------------1672--------------------------------
14411673
1442find_all_next( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )1674find_all_next( `name`_ , `attrs`_ , `recursive <recursive>`_ ,
1675`string <string>`_ , `**kwargs <kwargs>`_ )
14431676
1444find_next( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )1677find_next( `name`_ , `attrs`_ , `recursive <recursive>`_ ,
1678`string <string>`_ , `**kwargs <kwargs>`_ )
14451679
1446这2个方法通过 `.next_elements`_ 属性对当前tag的之后的 [5]_ tag和字符串进行迭代, ``find_all_next()`` 方法返回所有符合条件的节点, ``find_next()`` 方法返回第一个符合条件的节点:1680这 2 个方法通过 `.next_elements <element-generators>`_ 属性对当前 tag 的之后的 [5]_
1681tag 和字符串进行迭代, ``find_all_next()`` 方法返回所有符合条件的节点, ``find_next()``
1682方法返回第一个符合条件的节点:
14471683
1448::1684::
14491685
@@ -1458,16 +1694,22 @@ find_next( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )
1458 first_link.find_next("p")1694 first_link.find_next("p")
1459 # <p class="story">...</p>1695 # <p class="story">...</p>
14601696
1461第一个例子中,字符串 “Elsie”也被显示出来,尽管它被包含在我们开始查找的<a>标签的里面.第二个例子中,最后一个<p>标签也被显示出来,尽管它与我们开始查找位置的<a>标签不属于同一部分.例子中,搜索的重点是要匹配过滤器的条件,并且在文档中出现的顺序而不是开始查找的元素的位置.1697第一个例子中,字符串 “Elsie”也被显示出来,尽管它被包含在我们开始查找的 <a> 标签的里面。
1698第二个例子中,最后一个<p>标签也被显示出来,尽管它与我们开始查找位置的 <a> 标签不属于同一部分。
1699例子中,搜索的重点是要匹配过滤器的条件,以及元素在文档中出现的顺序要在查找的元素的之后。
14621700
1463find_all_previous() 和 find_previous()1701find_all_previous() 和 find_previous()
1464---------------------------------------1702---------------------------------------
14651703
1466find_all_previous( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )1704find_all_previous( `name`_ , `attrs`_ , `recursive <recursive>`_ ,
1705`string <string>`_ , `**kwargs <kwargs>`_ )
14671706
1468find_previous( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )1707find_previous( `name`_ , `attrs`_ , `recursive <recursive>`_ ,
1708`string <string>`_ , `**kwargs <kwargs>`_ )
14691709
1470这2个方法通过 `.previous_elements`_ 属性对当前节点前面 [5]_ 的tag和字符串进行迭代, ``find_all_previous()`` 方法返回所有符合条件的节点, ``find_previous()`` 方法返回第一个符合条件的节点.1710这 2 个方法通过 `.previous_elements <sibling-generators>`_ 属性对当前节点前面 [5]_ 的
1711tag 和字符串进行迭代, ``find_all_previous()`` 方法返回所有符合条件的节点, ``find_previous()``
1712方法返回第一个符合条件的节点。
14711713
1472::1714::
14731715
@@ -1482,105 +1724,110 @@ find_previous( `name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ )
1482 first_link.find_previous("title")1724 first_link.find_previous("title")
1483 # <title>The Dormouse's story</title>1725 # <title>The Dormouse's story</title>
14841726
1485``find_all_previous("p")`` 返回了文档中的第一段(class="title"的那段),但还返回了第二段,<p>标签包含了我们开始查找的<a>标签.不要惊讶,这段代码的功能是查找所有出现在指定<a>标签之前的<p>标签,因为这个<p>标签包含了开始的<a>标签,所以<p>标签一定是在<a>之前出现的.1727``find_all_previous("p")`` 既返回了文档中的第一段(class="title"的那段),还返回了第二段,
1728包含了我们开始查找的 <a> 标签的那段。不用惊讶,这段代码的功能是查找所有出现在指定 <a> 标签之前
1729的 <p> 标签,因为这个 <p> 标签包含了开始的 <a> 标签,所以 <p> 标签当然是在 <a> 之前出现的。
14861730
1487CSS选择器1731CSS 选择器
1488------------1732------------
14891733
1490Beautiful Soup支持大部分的CSS选择器 `<http://www.w3.org/TR/CSS2/selector.html>`_ [6]_ ,1734BeautifulSoup 对象和 Tag 对象支持通过 ``.css`` 属性实现 CSS 选择器。具体选择功能是通过
1491在 ``Tag`` 或 ``BeautifulSoup`` 对象的 ``.select()`` 方法中传入字符串参数,1735`Soup Sieve <https://facelessuser.github.io/soupsieve/>`_ 库实现的,在 PyPI 上通
1492即可使用CSS选择器的语法找到tag:1736过关键字 ``soupsieve`` 可以找到。通过 pip 安装 Beautiful Soup 时,Soup Sieve 也会自
1737动安装,不用其它额外操作。
1738
1739Soup Sieve 文档列出了 `当前支持的 CSS 选择器 <https://facelessuser.github.io/soupsieve/selectors/>`_,
1740下面是一些基本应用
14931741
1494::1742::
14951743
1496 soup.select("title")1744 soup.css.select("title")
1497 # [<title>The Dormouse's story</title>]1745 # [<title>The Dormouse's story</title>]
14981746
1499 soup.select("p:nth-of-type(3)")1747 soup.css.select("p:nth-of-type(3)")
1500 # [<p class="story">...</p>]1748 # [<p class="story">...</p>]
15011749
1502通过tag标签逐层查找:1750查找指定层级的 tag:
15031751
1504::1752::
15051753
1506 soup.select("body a")1754 soup.css.select("body a")
1507 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,1755 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
1508 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,1756 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
1509 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]1757 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
15101758
1511 soup.select("html head title")1759 soup.css.select("html head title")
1512 # [<title>The Dormouse's story</title>]1760 # [<title>The Dormouse's story</title>]
15131761
1514找到某个tag标签下的直接子标签 [6]_ :1762找到某个 tag 标签下的直接子标签 [6]_ :
15151763
1516::1764::
15171765
1518 soup.select("head > title")1766 soup.css.select("head > title")
1519 # [<title>The Dormouse's story</title>]1767 # [<title>The Dormouse's story</title>]
15201768
1521 soup.select("p > a")1769 soup.css.select("p > a")
1522 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,1770 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
1523 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,1771 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
1524 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]1772 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
15251773
1526 soup.select("p > a:nth-of-type(2)")1774 soup.css.select("p > a:nth-of-type(2)")
1527 # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]1775 # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
15281776
1529 soup.select("p > #link1")1777 soup.css.select("p > #link1")
1530 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]1778 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
15311779
1532 soup.select("body > a")1780 soup.css.select("body > a")
1533 # []1781 # []
15341782
1535找到兄弟节点标签:1783找到兄弟节点标签:
15361784
1537::1785::
15381786
1539 soup.select("#link1 ~ .sister")1787 soup.css.select("#link1 ~ .sister")
1540 # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,1788 # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
1541 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]1789 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
15421790
1543 soup.select("#link1 + .sister")1791 soup.css.select("#link1 + .sister")
1544 # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]1792 # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
15451793
1546通过CSS的类名查找:1794通过 CSS 的类名查找:
15471795
1548::1796::
15491797
1550 soup.select(".sister")1798 soup.css.select(".sister")
1551 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,1799 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
1552 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,1800 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
1553 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]1801 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
15541802
1555 soup.select("[class~=sister]")1803 soup.css.select("[class~=sister]")
1556 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,1804 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
1557 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,1805 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
1558 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]1806 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
15591807
1560通过tag的id查找:1808通过 id 查找 tag:
15611809
1562::1810::
15631811
1564 soup.select("#link1")1812 soup.css.select("#link1")
1565 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]1813 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
15661814
1567 soup.select("a#link2")1815 soup.css.select("a#link2")
1568 # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]1816 # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
15691817
1570同时用多种CSS选择器查询元素:1818查找符合列表中任意一个选择器的 tag:
15711819
1572::1820::
15731821
1574 soup.select("#link1,#link2")1822 soup.css.select("#link1,#link2")
1575 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,1823 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
1576 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]1824 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
1577
15781825
1579通过是否存在某个属性来查找:1826通过是否存在某个属性来查找:
15801827
1581::1828::
15821829
1583 soup.select('a[href]')1830 soup.css.select('a[href]')
1584 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,1831 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
1585 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,1832 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
1586 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]1833 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
@@ -1589,62 +1836,143 @@ Beautiful Soup支持大部分的CSS选择器 `<http://www.w3.org/TR/CSS2/selecto
15891836
1590::1837::
15911838
1592 soup.select('a[href="http://example.com/elsie"]')1839 soup.css.select('a[href="http://example.com/elsie"]')
1593 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]1840 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
15941841
1595 soup.select('a[href^="http://example.com/"]')1842 soup.css.select('a[href^="http://example.com/"]')
1596 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,1843 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
1597 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,1844 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
1598 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]1845 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
15991846
1600 soup.select('a[href$="tillie"]')1847 soup.css.select('a[href$="tillie"]')
1601 # [<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]1848 # [<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
16021849
1603 soup.select('a[href*=".com/el"]')1850 soup.css.select('a[href*=".com/el"]')
1604 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]1851 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
16051852
1606通过语言设置来查找:1853还有一个 ``select_one()`` 方法,它会返回符合筛选条件的元素列表中的第一个
16071854
1608::1855::
16091856
1610 multilingual_markup = """1857 soup.css.select_one(".sister")
1611 <p lang="en">Hello</p>1858 # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
1612 <p lang="en-us">Howdy, y'all</p>
1613 <p lang="en-gb">Pip-pip, old fruit</p>
1614 <p lang="fr">Bonjour mes amis</p>
1615 """
1616 multilingual_soup = BeautifulSoup(multilingual_markup)
1617 multilingual_soup.select('p[lang|=en]')
1618 # [<p lang="en">Hello</p>,
1619 # <p lang="en-us">Howdy, y'all</p>,
1620 # <p lang="en-gb">Pip-pip, old fruit</p>]
16211859
1622返回查找到的元素的第一个1860为了方便使用,在 BeautifulSoup 或 Tag 对象上直接调用 ``select()`` 和 ``select_one()`` 方法,
1861中间省略 ``.css`` 属性
16231862
1624::1863::
16251864
1626 soup.select_one(".sister")1865 soup.select('a[href$="tillie"]')
1627 # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>1866 # [<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
16281867
1868 soup.select_one(".sister")
1869 # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
1870
1871CSS 选择器对于熟悉 CSS 语法的人来说非常方便。你可以在 Beautiful Soup 中使用相同的方法。
1872但是如果你只需要使用 CSS 选择器就够了,那么应该 ``lxml`` 作为文档解析器:因为速度快很多。
1873但是 Soup Sieve 也有优势,它允许 `组合` 使用 CSS 选择器和 Beautiful Soup 的 API。
1874
1875Soup Sieve 高级特性
1876-------------------
1877
1878Soup Sieve 提供的是比 ``select()`` 和 ``select_one()`` 更底层的方法,通过 Tag 或
1879Beautiful Soup 对象的 ``.css`` 属性,可以调用大部分的 API。下面是支持这种调用方式的方法列表,
1880查看 `Soup Sieve <https://facelessuser.github.io/soupsieve/>`_ 文档了解全部细节。
1881
1882``iselect()`` 方法与 ``select()`` 效果相同,区别是返回的结果是迭代器。
1883::
1884
1885 [tag['id'] for tag in soup.css.iselect(".sister")]
1886 # ['link1', 'link2', 'link3']
1887
1888``closest()`` 方法与 ``find_parent()`` 方法相似,返回符合 CSS 选择器的 Tag 对象的最近父级。
1889
1890::
1891
1892 elsie = soup.css.select_one(".sister")
1893 elsie.css.closest("p.story")
1894 # <p class="story">Once upon a time there were three little sisters; and their names were
1895 # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
1896 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
1897 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
1898 # and they lived at the bottom of a well.</p>
1899
1900``match()`` 方法返回布尔结果,标记指定 Tag 是否符合指定筛选器
1901
1902::
1903
1904 # elsie.css.match("#link1")
1905 True
1906
1907 # elsie.css.match("#link2")
1908 False
1909
1910``filter()`` 方法返回 tag 直接子节点中符合筛选器的节点列表
1911
1912::
1913
1914 [tag.string for tag in soup.find('p', 'story').css.filter('a')]
1915 # ['Elsie', 'Lacie', 'Tillie']
1916
1917``escape()`` 方法可以对 CSS 标识符中的特殊字符进行转义,否则是非法 CSS 标识符
16291918
1630对于熟悉CSS选择器语法的人来说这是个非常方便的方法.Beautiful Soup也支持CSS选择器API,1919::
1631如果你仅仅需要CSS选择器的功能,那么直接使用 ``lxml`` 也可以,1920
1632而且速度更快,支持更多的CSS选择器语法,但Beautiful Soup整合了CSS选择器的语法和自身方便使用API.1921 soup.css.escape("1-strange-identifier")
1922 # '\\31 -strange-identifier'
1923
1924CSS 筛选器中的命名空间
1925------------------------
1926
1927如果解析的 XML 文档中定义了命名空间,那么 CSS 筛选器中也可以使用
1928
1929::
1930
1931 from bs4 import BeautifulSoup
1932 xml = """<tag xmlns:ns1="http://namespace1/" xmlns:ns2="http://namespace2/">
1933 <ns1:child>I'm in namespace 1</ns1:child>
1934 <ns2:child>I'm in namespace 2</ns2:child>
1935 </tag> """
1936 namespace_soup = BeautifulSoup(xml, "xml")
1937
1938 namespace_soup.css.select("child")
1939 # [<ns1:child>I'm in namespace 1</ns1:child>, <ns2:child>I'm in namespace 2</ns2:child>]
1940
1941 namespace_soup.css.select("ns1|child")
1942 # [<ns1:child>I'm in namespace 1</ns1:child>]
1943
1944Beautiful Soup 尝试自动匹配解析文档中的命名空间前缀,除此之外,你还可以自定义目录的缩写
1945
1946::
1947
1948 namespaces = dict(first="http://namespace1/", second="http://namespace2/")
1949 namespace_soup.css.select("second|child", namespaces=namespaces)
1950 # [<ns1:child>I'm in namespace 2</ns1:child>]
1951
1952支持 CSS 筛选器的历史版本
1953-------------------------
1954
1955``.css`` 属性是在 Beautiful Soup 4.12.0 中添加的。在此之前,只能使用 ``.select()`` 和
1956 ``.select_one()`` 方法。
1957
1958Soup Sieve 是在 Beautiful Soup 4.7.0 开始集成的。早期版本中有 ``.select()`` 方法,但
1959仅能支持最常用的 CSS 选择器。
16331960
16341961
1635修改文档树1962修改文档树
1636===========1963===========
16371964
1638Beautiful Soup的强项是文档树的搜索,但同时也可以方便的修改文档树1965Beautiful Soup 的强项是文档树的搜索,但也支持修改文档数,或者编写新的 HTML、XML 文档。
16391966
1640修改tag的名称和属性1967修改 tag 的名称和属性
1641-------------------1968----------------------
16421969
1643在 `Attributes`_ 的章节中已经介绍过这个功能,但是再看一遍也无妨. 重命名一个tag,改变属性的值,添加或删除属性:1970在 :py:attr:`Tag.attrs` 的章节中已经介绍过这个功能,但是再看一遍也无妨。重命名一个 tag,
1971改变属性的值,添加或删除属性
16441972
1645::1973::
16461974
1647 soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')1975 soup = BeautifulSoup('<b class="boldest">Extremely bold</b>', 'html.parser')
1648 tag = soup.b1976 tag = soup.b
16491977
1650 tag.name = "blockquote"1978 tag.name = "blockquote"
@@ -1658,47 +1986,64 @@ Beautiful Soup的强项是文档树的搜索,但同时也可以方便的修改
1658 tag1986 tag
1659 # <blockquote>Extremely bold</blockquote>1987 # <blockquote>Extremely bold</blockquote>
16601988
1661修改 .string1989修改 ``.string``
1662-------------1990------------------
16631991
1664给tag的 ``.string`` 属性赋值,就相当于用当前的内容替代了原来的内容:1992如果设置 tag 的 ``.string`` 属性值,就相当于用新的内容替代了原来的内容:
16651993
1666::1994::
16671995
1668 markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'1996 markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
1669 soup = BeautifulSoup(markup)1997 soup = BeautifulSoup(markup, 'html.parser')
16701998
1671 tag = soup.a1999 tag = soup.a
1672 tag.string = "New link text."2000 tag.string = "New link text."
1673 tag2001 tag
1674 # <a href="http://example.com/">New link text.</a>2002 # <a href="http://example.com/">New link text.</a>
16752003
1676注意: 如果当前的tag包含了其它tag,那么给它的 ``.string`` 属性赋值会覆盖掉原有的所有内容包括子tag2004注意:如果 tag 原本包含了其它子节点,原有的所有内容包括子 tag 都会被覆盖掉。
16772005
1678append()2006``append()``
1679----------2007--------------
16802008
1681``Tag.append()`` 方法想tag中添加内容,就好像Python的列表的 ``.append()`` 方法:2009向 tag 中添加内容可以使用 ``Tag.append()`` 方法,就好像调用 Python 列表的 ``.append()`` 方法:
16822010
1683::2011::
16842012
1685 soup = BeautifulSoup("<a>Foo</a>")2013 soup = BeautifulSoup("<a>Foo</a>", 'html.parser')
1686 soup.a.append("Bar")2014 soup.a.append("Bar")
16872015
1688 soup2016 soup
1689 # <html><head></head><body><a>FooBar</a></body></html>2017 # <a>FooBar</a>
2018 soup.a.contents
2019 # ['Foo', 'Bar']
2020
2021``extend()``
2022--------------
2023
2024从 Beautiful Soup 4.7.0 版本开始,tag 增加了 ``.extend()`` 方法,可以把一个列表中内容,
2025按顺序全部添加到一个 tag 当中
2026
2027::
2028
2029 soup = BeautifulSoup("<a>Soup</a>", 'html.parser')
2030 soup.a.extend(["'s", " ", "on"])
2031
2032 soup
2033 # <a>Soup's on</a>
1690 soup.a.contents2034 soup.a.contents
1691 # [u'Foo', u'Bar']2035 # ['Soup', ''s', ' ', 'on']
16922036
1693NavigableString() 和 .new_tag()2037NavigableString() 和 .new_tag()
1694-----------------------------------------2038-----------------------------------------
16952039
1696如果想添加一段文本内容到文档中也没问题,可以调用Python的 ``append()`` 方法2040如果想添加一段文本内容到文档中,可以将一个 Python 字符串对象传给 ``append()`` 方法,
1697或调用 ``NavigableString`` 的构造方法:2041或调用 ``NavigableString`` 构造方法:
16982042
1699::2043::
17002044
1701 soup = BeautifulSoup("<b></b>")2045 from bs4 import NavigableString
2046 soup = BeautifulSoup("<b></b>", 'html.parser')
1702 tag = soup.b2047 tag = soup.b
1703 tag.append("Hello")2048 tag.append("Hello")
1704 new_string = NavigableString(" there")2049 new_string = NavigableString(" there")
@@ -1706,27 +2051,27 @@ NavigableString() 和 .new_tag()
1706 tag2051 tag
1707 # <b>Hello there.</b>2052 # <b>Hello there.</b>
1708 tag.contents2053 tag.contents
1709 # [u'Hello', u' there']2054 # ['Hello', ' there']
17102055
1711如果想要创建一段注释,或 ``NavigableString`` 的任何子类, 只要调用 NavigableString 的构造方法:2056如果想要创建一段注释,或其它 ``NavigableString`` 的子类,只要调用构造方法:
17122057
1713::2058::
17142059
1715 from bs4 import Comment2060 from bs4 import Comment
1716 new_comment = soup.new_string("Nice to see you.", Comment)2061 new_comment = Comment("Nice to see you.")
1717 tag.append(new_comment)2062 tag.append(new_comment)
1718 tag2063 tag
1719 # <b>Hello there<!--Nice to see you.--></b>2064 # <b>Hello there<!--Nice to see you.--></b>
1720 tag.contents2065 tag.contents
1721 # [u'Hello', u' there', u'Nice to see you.']2066 # ['Hello', ' there', 'Nice to see you.']
17222067
1723# 这是Beautiful Soup 4.2.1 中新增的方法2068`(这是 Beautiful Soup 4.4.0 中新增的方法)`
17242069
1725创建一个tag最好的方法是调用工厂方法 ``BeautifulSoup.new_tag()`` :2070如果需要新创建一个 tag,最好的方法是调用工厂方法 ``BeautifulSoup.new_tag()``
17262071
1727::2072::
17282073
1729 soup = BeautifulSoup("<b></b>")2074 soup = BeautifulSoup("<b></b>", 'html.parser')
1730 original_tag = soup.b2075 original_tag = soup.b
17312076
1732 new_tag = soup.new_tag("a", href="http://www.example.com")2077 new_tag = soup.new_tag("a", href="http://www.example.com")
@@ -1738,58 +2083,62 @@ NavigableString() 和 .new_tag()
1738 original_tag2083 original_tag
1739 # <b><a href="http://www.example.com">Link text.</a></b>2084 # <b><a href="http://www.example.com">Link text.</a></b>
17402085
1741第一个参数作为tag的name,是必填,其它参数选填2086只有第一个参数用作 tag 的 name,是必填的。
17422087
1743insert()2088insert()
1744--------2089--------
17452090
1746``Tag.insert()`` 方法与 ``Tag.append()`` 方法类似,区别是不会把新元素添加到父节点 ``.contents`` 属性的最后,而是把元素插入到指定的位置.与Python列表总的 ``.insert()`` 方法的用法下同:2091``Tag.insert()`` 方法与 ``Tag.append()`` 方法类似,区别是不会把新元素添加到
2092父节点 ``.contents`` 属性的最后。而是把元素插入到按顺序指定的位置。与 Python 列表
2093中的 ``.insert()`` 方法的用法相同
17472094
1748::2095::
17492096
1750 markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'2097 markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
1751 soup = BeautifulSoup(markup)2098 soup = BeautifulSoup(markup, 'html.parser')
1752 tag = soup.a2099 tag = soup.a
17532100
1754 tag.insert(1, "but did not endorse ")2101 tag.insert(1, "but did not endorse ")
1755 tag2102 tag
1756 # <a href="http://example.com/">I linked to but did not endorse <i>example.com</i></a>2103 # <a href="http://example.com/">I linked to but did not endorse <i>example.com</i></a>
1757 tag.contents2104 tag.contents
1758 # [u'I linked to ', u'but did not endorse', <i>example.com</i>]2105 # ['I linked to ', 'but did not endorse', <i>example.com</i>]
17592106
1760insert_before() 和 insert_after()2107insert_before() 和 insert_after()
1761-----------------------------------2108-----------------------------------
17622109
1763``insert_before()`` 方法在当前tag或文本节点前插入内容:2110``insert_before()`` 方法可以在文档树中直接在目标之前添加 tag 或文本
17642111
1765::2112::
17662113
1767 soup = BeautifulSoup("<b>stop</b>")2114 soup = BeautifulSoup("<b>leave</b>", 'html.parser')
1768 tag = soup.new_tag("i")2115 tag = soup.new_tag("i")
1769 tag.string = "Don't"2116 tag.string = "Don't"
1770 soup.b.string.insert_before(tag)2117 soup.b.string.insert_before(tag)
1771 soup.b2118 soup.b
1772 # <b><i>Don't</i>stop</b>2119 # <b><i>Don't</i>leave</b>
17732120
1774``insert_after()`` 方法在当前tag或文本节点后插入内容:2121``insert_after()`` 方法可以在文档树中直接在目标之后添加 tag 或文本
17752122
1776::2123::
17772124
1778 soup.b.i.insert_after(soup.new_string(" ever "))2125 div = soup.new_tag('div')
2126 div.string = 'ever'
2127 soup.b.i.insert_after(" you ", div)
1779 soup.b2128 soup.b
1780 # <b><i>Don't</i> ever stop</b>2129 # <b><i>Don't</i> you <div>ever</div> leave</b>
1781 soup.b.contents2130 soup.b.contents
1782 # [<i>Don't</i>, u' ever ', u'stop']2131 # [<i>Don't</i>, ' you', <div>ever</div>, 'leave']
17832132
1784clear()2133clear()
1785--------2134--------
17862135
1787``Tag.clear()`` 方法移除当前tag的内容:2136``Tag.clear()`` 方法可以移除 tag 的内容:
17882137
1789::2138::
17902139
1791 markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'2140 markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
1792 soup = BeautifulSoup(markup)2141 soup = BeautifulSoup(markup, 'html.parser')
1793 tag = soup.a2142 tag = soup.a
17942143
1795 tag.clear()2144 tag.clear()
@@ -1799,12 +2148,12 @@ clear()
1799extract()2148extract()
1800----------2149----------
18012150
1802``PageElement.extract()`` 方法将当前tag移除文档树,并作为方法结果返回:2151``PageElement.extract()`` 方法将当前 tag 或文本从文档树中移除,并返回被删除的内容:
18032152
1804::2153::
18052154
1806 markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'2155 markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
1807 soup = BeautifulSoup(markup)2156 soup = BeautifulSoup(markup, 'html.parser')
1808 a_tag = soup.a2157 a_tag = soup.a
18092158
1810 i_tag = soup.i.extract()2159 i_tag = soup.i.extract()
@@ -1816,15 +2165,16 @@ extract()
1816 # <i>example.com</i>2165 # <i>example.com</i>
18172166
1818 print(i_tag.parent)2167 print(i_tag.parent)
1819 None2168 # None
18202169
1821这个方法实际上产生了2个文档树: 一个是用来解析原始文档的 ``BeautifulSoup`` 对象,另一个是被移除并且返回的tag.被移除并返回的tag可以继续调用 ``extract`` 方法:2170这个方法实际上产生了 2 个文档树: 一个是原始文档的 ``BeautifulSoup`` 对象,
2171另一个是被移除并且返回的文档树。还可以在新生成的文档树上继续调用 ``extract`` 方法:
18222172
1823::2173::
18242174
1825 my_string = i_tag.string.extract()2175 my_string = i_tag.string.extract()
1826 my_string2176 my_string
1827 # u'example.com'2177 # 'example.com'
18282178
1829 print(my_string.parent)2179 print(my_string.parent)
1830 # None2180 # None
@@ -1834,71 +2184,135 @@ extract()
1834decompose()2184decompose()
1835------------2185------------
18362186
1837``Tag.decompose()`` 方法将当前节点移除文档树并完全销毁:2187``Tag.decompose()`` 方法会将前节点从文档书中移除并完全销毁:
18382188
1839::2189::
18402190
1841 markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'2191 markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
1842 soup = BeautifulSoup(markup)2192 soup = BeautifulSoup(markup, 'html.parser')
1843 a_tag = soup.a2193 a_tag = soup.a
2194 i_tag = soup.i
18442195
1845 soup.i.decompose()2196 i_tag.decompose()
1846
1847 a_tag2197 a_tag
1848 # <a href="http://example.com/">I linked to</a>2198 # <a href="http://example.com/">I linked to</a>
18492199
2200被 decompose 的 Tag 或者 `NavigableString` 是不稳定的,什么时候都不要使用它。如果不确定
2201某些内容是否被 decompose 了,可以通过 ``.decomposed`` 属性进行检查 `(Beautiful Soup 4.9.0 新增)`
2202
2203::
2204
2205 i_tag.decomposed
2206 # True
2207
2208 a_tag.decomposed
2209 # False
2210
2211.. _replace_with():
2212
1850replace_with()2213replace_with()
1851---------------2214---------------
18522215
1853``PageElement.replace_with()`` 方法移除文档树中的某段内容,并用新tag或文本节点替代它:2216``PageElement.replace_with()`` 方法移除文档树中的某段内容,并用新 tag 或文本节点替代它:
18542217
1855::2218::
18562219
1857 markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'2220 markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
1858 soup = BeautifulSoup(markup)2221 soup = BeautifulSoup(markup, 'html.parser')
1859 a_tag = soup.a2222 a_tag = soup.a
18602223
1861 new_tag = soup.new_tag("b")2224 new_tag = soup.new_tag("b")
1862 new_tag.string = "example.net"2225 new_tag.string = "example.com"
1863 a_tag.i.replace_with(new_tag)2226 a_tag.i.replace_with(new_tag)
18642227
1865 a_tag2228 a_tag
1866 # <a href="http://example.com/">I linked to <b>example.net</b></a>2229 # <a href="http://example.com/">I linked to <b>example.com</b></a>
2230
2231 bold_tag = soup.new_tag("b")
2232 bold_tag.string = "example"
2233 i_tag = soup.new_tag("i")
2234 i_tag.string = "net"
2235 a_tag.b.replace_with(bold_tag, ".", i_tag)
2236
2237 a_tag
2238 # <a href="http://example.com/">I linked to <b>example</b>.<i>net</i></a>
18672239
1868``replace_with()`` 方法返回被替代的tag或文本节点,可以用来浏览或添加到文档树其它地方2240``replace_with()`` 方法返回被替代的 tag 或文本节点,可以用来检查或添加到文档树其它地方。
2241
2242`传递多个参数给 replace_with() 方法在 Beautiful Soup 4.10.0 版本中新增`
18692243
1870wrap()2244wrap()
1871------2245--------
18722246
1873``PageElement.wrap()`` 方法可以对指定的tag元素进行包装 [8]_ ,并返回包装后的结果:2247``PageElement.wrap()`` 方法可以对指定的tag元素进行包装 [8]_ ,并返回包装后的结果:
18742248
1875::2249::
18762250
1877 soup = BeautifulSoup("<p>I wish I was bold.</p>")2251 soup = BeautifulSoup("<p>I wish I was bold.</p>", 'html.parser')
1878 soup.p.string.wrap(soup.new_tag("b"))2252 soup.p.string.wrap(soup.new_tag("b"))
1879 # <b>I wish I was bold.</b>2253 # <b>I wish I was bold.</b>
18802254
1881 soup.p.wrap(soup.new_tag("div"))2255 soup.p.wrap(soup.new_tag("div"))
1882 # <div><p><b>I wish I was bold.</b></p></div>2256 # <div><p><b>I wish I was bold.</b></p></div>
18832257
1884该方法在 Beautiful Soup 4.0.5 中添加2258该方法在 Beautiful Soup 4.0.5 中添加。
18852259
1886unwrap()2260unwrap()
1887---------2261---------
18882262
1889``Tag.unwrap()`` 方法与 ``wrap()`` 方法相反.将移除tag内的所有tag标签,该方法常被用来进行标记的解包:2263``Tag.unwrap()`` 方法与 ``wrap()`` 方法相反。它将用 tag 内内容来替换 tag 本身,
2264该方法常被用来解包内容:
18902265
1891::2266::
18922267
1893 markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'2268 markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
1894 soup = BeautifulSoup(markup)2269 soup = BeautifulSoup(markup, 'html.parser')
1895 a_tag = soup.a2270 a_tag = soup.a
18962271
1897 a_tag.i.unwrap()2272 a_tag.i.unwrap()
1898 a_tag2273 a_tag
1899 # <a href="http://example.com/">I linked to example.com</a>2274 # <a href="http://example.com/">I linked to example.com</a>
19002275
1901与 ``replace_with()`` 方法相同, ``unwrap()`` 方法返回被移除的tag2276与 ``replace_with()`` 方法相同,``unwrap()`` 方法会返回被移除的 tag。
2277
2278smooth()
2279----------
2280
2281调用了一堆修改文档树的方法后,可能剩下的是 2 个或更多个彼此衔接的 NavigableString 对象。
2282Beautiful Soup 处理起来没有问题,但在刚刚解析的文档树中,可能会出现非预期情况
2283
2284::
2285
2286 soup = BeautifulSoup("<p>A one</p>", 'html.parser')
2287 soup.p.append(", a two")
2288
2289 soup.p.contents
2290 # ['A one', ', a two']
2291
2292 print(soup.p.encode())
2293 # b'<p>A one, a two</p>'
2294
2295 print(soup.p.prettify())
2296 # <p>
2297 # A one
2298 # , a two
2299 # </p>
2300
2301这时可以使用 ``Tag.smooth()`` 方法来清理文档树,把相邻的字符串平滑的链接到一起
2302
2303::
2304
2305 soup.smooth()
2306
2307 soup.p.contents
2308 # ['A one, a two']
2309
2310 print(soup.p.prettify())
2311 # <p>
2312 # A one, a two
2313 # </p>
2314
2315该方法在 Beautiful Soup 4.8.0 中添加。
19022316
1903输出2317输出
1904====2318====
@@ -1906,12 +2320,13 @@ unwrap()
1906格式化输出2320格式化输出
1907-----------2321-----------
19082322
1909``prettify()`` 方法将Beautiful Soup的文档树格式化后以Unicode编码输出,每个XML/HTML标签都独占一行2323``prettify()`` 方法将 Beautiful Soup 的文档树格式化后以 Unicode 编码输出,
2324每个 XML/HTML 标签都独占一行
19102325
1911::2326::
19122327
1913 markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'2328 markup = '<html><head><body><a href="http://example.com/">I linked to <i>example.com</i></a>'
1914 soup = BeautifulSoup(markup)2329 soup = BeautifulSoup(markup, 'html.parser')
1915 soup.prettify()2330 soup.prettify()
1916 # '<html>\n <head>\n </head>\n <body>\n <a href="http://example.com/">\n...'2331 # '<html>\n <head>\n </head>\n <body>\n <a href="http://example.com/">\n...'
19172332
@@ -1929,7 +2344,7 @@ unwrap()
1929 # </body>2344 # </body>
1930 # </html>2345 # </html>
19312346
1932``BeautifulSoup`` 对象和它的tag节点都可以调用 ``prettify()`` 方法:2347``BeautifulSoup`` 对象的根节点和它的所有 tag 节点都可以调用 ``prettify()`` 方法:
19332348
1934::2349::
19352350
@@ -1941,237 +2356,439 @@ unwrap()
1941 # </i>2356 # </i>
1942 # </a>2357 # </a>
19432358
2359因为格式化会添加额外的空格(为了换行显示),因为 ``prettify()`` 会改变 HTML 文档的内容,
2360所以不要用来格式化文档。 ``prettify()`` 方法的设计目标是为了帮助更好的显示和理解文档。
2361
1944压缩输出2362压缩输出
1945----------2363----------
19462364
1947如果只想得到结果字符串,不重视格式,那么可以对一个 ``BeautifulSoup`` 对象或 ``Tag`` 对象使用Python的 ``unicode()`` 或 ``str()`` 方法:2365如果只想得到结果字符串,不重视格式,那么可以对一个 ``BeautifulSoup`` 对象或 ``Tag`` 对象
2366使用 Python 的 ``unicode()`` 或 ``str()`` 方法:
19482367
1949::2368::
19502369
1951 str(soup)2370 str(soup)
1952 # '<html><head></head><body><a href="http://example.com/">I linked to <i>example.com</i></a></body></html>'2371 # '<html><head></head><body><a href="http://example.com/">I linked to <i>example.com</i></a></body></html>'
19532372
1954 unicode(soup.a)2373 str(soup.a)
1955 # u'<a href="http://example.com/">I linked to <i>example.com</i></a>'2374 # '<a href="http://example.com/">I linked to <i>example.com</i></a>'
19562375
1957``str()`` 方法返回UTF-8编码的字符串,可以指定 `编码`_ 的设置.2376``str()`` 方法返回 UTF-8 编码的字符串,查看定 `编码`_ 了解更多选项。
19582377
1959还可以调用 ``encode()`` 方法获得字节码或调用 ``decode()`` 方法获得Unicode.2378还可以调用 ``encode()`` 方法获得字节码或调用 ``decode()`` 方法获得Unicode。
19602379
1961输出格式2380输出格式
1962---------2381---------
19632382
1964Beautiful Soup输出是会将HTML中的特殊字符转换成Unicode,比如“&lquot;”:2383Beautiful Soup 输出是会将 HTML 中的特殊字符编码转换成 Unicode, 比如 “&lquot;”:
19652384
1966::2385::
19672386
1968 soup = BeautifulSoup("&ldquo;Dammit!&rdquo; he said.")2387 soup = BeautifulSoup("&ldquo;Dammit!&rdquo; he said.", 'html.parser')
1969 unicode(soup)2388 str(soup)
1970 # u'<html><head></head><body>\u201cDammit!\u201d he said.</body></html>'2389 # '“Dammit!” he said.'
19712390
1972如果将文档转换成字符串,Unicode编码会被编码成UTF-8.这样就无法正确显示HTML特殊字符了:2391如果将文档转换成字节编码,那么字节码 Unicode 会被编码成 UTF-8。并且无法再转换回 html 中的特殊字符编码:
19732392
1974::2393::
19752394
1976 str(soup)2395 soup.encode("utf8")
1977 # '<html><head></head><body>\xe2\x80\x9cDammit!\xe2\x80\x9d he said.</body></html>'2396 # b'\xe2\x80\x9cDammit!\xe2\x80\x9d he said.'
2397
2398默认情况下,只会转义 & 符号和尖角号。它们会被转义为 "&amp;","&lt;" 和 "&gt;",因此 Beautiful Soup
2399不会无意间生成错误格式的的 HTML 或 XML
2400
2401::
2402
2403 soup = BeautifulSoup("<p>The law firm of Dewey, Cheatem, & Howe</p>", 'html.parser')
2404 soup.p
2405 # <p>The law firm of Dewey, Cheatem, &amp; Howe</p>
2406
2407 soup = BeautifulSoup('<a href="http://example.com/?foo=val1&bar=val2">A link</a>', 'html.parser')
2408 soup.a
2409 # <a href="http://example.com/?foo=val1&amp;bar=val2">A link</a>
2410
2411修改默认转义规则的方法是,设置 ``prettify()``, ``encode()``, 或 ``decode()`` 方法的 ``formatter``
2412参数。Beautiful Soup 可以识别 5 种 ``formatter`` 值。
2413
2414默认的设置是 ``formatter="minimal"``。处置字符串时 Beautiful Soup 会确保生成合法的 HTML/XML
2415
2416::
2417
2418 french = "<p>Il a dit &lt;&lt;Sacr&eacute; bleu!&gt;&gt;</p>"
2419 soup = BeautifulSoup(french, 'html.parser')
2420 print(soup.prettify(formatter="minimal"))
2421 # <p>
2422 # Il a dit &lt;&lt;Sacré bleu!&gt;&gt;
2423 # </p>
2424
2425设置为 ``formatter="html"`` 时,Beautiful Soup 会尽可能把 Unicode 字符转换为 HTML 实体
2426
2427::
2428
2429 print(soup.prettify(formatter="html"))
2430 # <p>
2431 # Il a dit &lt;&lt;Sacr&eacute; bleu!&gt;&gt;
2432 # </p>
2433
2434设置为 ``formatter="html5"`` 时,结果与 ``formatter="html"`` 相似,区别是 Beautiful Soup
2435会忽略 HTML 标签种空标签里的斜杠符号,比如 “br” 标签
2436
2437::
2438
2439 br = BeautifulSoup("<br>", 'html.parser').br
2440
2441 print(br.encode(formatter="html"))
2442 # b'<br/>'
2443
2444 print(br.encode(formatter="html5"))
2445 # b'<br>'
2446
2447另外,如果属性的值为空字符串的,它会变为 HTML 风格的 boolean 属性
2448
2449::
2450
2451 option = BeautifulSoup('<option selected=""></option>').option
2452 print(option.encode(formatter="html"))
2453 # b'<option selected=""></option>'
2454
2455 print(option.encode(formatter="html5"))
2456 # b'<option selected></option>'
2457
2458这种机制在 Beautiful Soup 4.10.0 中添加。
2459
2460设置为 ``formatter=None`` 时,Beautiful Soup 在输出时不会修改任何字符串内容。这是效率最高的选项,
2461但可能导致输出非法的 HTML/XML,比如下面例子
2462
2463::
2464
2465 print(soup.prettify(formatter=None))
2466 # <p>
2467 # Il a dit <<Sacré bleu!>>
2468 # </p>
2469
2470 link_soup = BeautifulSoup('<a href="http://example.com/?foo=val1&bar=val2">A link</a>', 'html.parser')
2471 print(link_soup.a.encode(formatter=None))
2472 # b'<a href="http://example.com/?foo=val1&bar=val2">A link</a>'
2473
2474格式化对象
2475---------------
2476
2477如果需要更复杂的机制来控制输出内容,可以实例化 Beautiful Soup 的 formatter 实例,
2478然后用作 ``formatter`` 参数。
2479
2480.. py:class:: HTMLFormatter
2481
2482可以用来自定义 HTML 文档的格式化规则。
2483
2484下面的 formatter 例子,可以将字符串全部转化为大写,不论是文字节点中的字符还是属性值
2485
2486::
2487
2488 from bs4.formatter import HTMLFormatter
2489 def uppercase(str):
2490 return str.upper()
2491
2492 formatter = HTMLFormatter(uppercase)
2493
2494 print(soup.prettify(formatter=formatter))
2495 # <p>
2496 # IL A DIT <<SACRÉ BLEU!>>
2497 # </p>
2498
2499 print(link_soup.a.prettify(formatter=formatter))
2500 # <a href="HTTP://EXAMPLE.COM/?FOO=VAL1&BAR=VAL2">
2501 # A LINK
2502 # </a>
2503
2504下面的 formatter 例子,在美化文档时增加缩进长度
2505
2506::
2507
2508 formatter = HTMLFormatter(indent=8)
2509 print(link_soup.a.prettify(formatter=formatter))
2510 # <a href="http://example.com/?foo=val1&bar=val2">
2511 # A link
2512 # </a>
2513
2514.. py:class:: XMLFormatter
2515
2516可以用来自定义 XML 文档的格式化规则。
2517
2518编写自定义 formatter
2519----------------------
2520
2521:py:class:`HTMLFormatter` or :py:class:`XMLFormatter` 的子类可以控制更多的输出过程。
2522例如,Beautiful Soup 默认情况下会对属性中的 tag 进行排序
2523
2524::
2525
2526 attr_soup = BeautifulSoup(b'<p z="1" m="2" a="3"></p>', 'html.parser')
2527 print(attr_soup.p.encode())
2528 # <p a="3" m="2" z="1"></p>
2529
2530若想关闭这个功能,可以使用子类的 ``Formatter.attributes()`` 方法,该方法可以控制输出那些属性
2531以及这些属性的输出顺序。下面的例子会过滤掉文档中的 “m” 属性
2532
2533::
2534
2535 class UnsortedAttributes(HTMLFormatter):
2536 def attributes(self, tag):
2537 for k, v in tag.attrs.items():
2538 if k == 'm':
2539 continue
2540 yield k, v
2541
2542 print(attr_soup.p.encode(formatter=UnsortedAttributes()))
2543 # <p z="1" a="3"></p>
2544
2545危险提示:如果创建了 `CData` 对象,对象中的字符串对象始终表示原始内容,不会被格式化方法影响。
2546Beautiful Soup 输出时依然会调用自定义格式化方法,以防自定义方法中包含自定义的字符串计数方法,
2547但调用后不会使用返回结果,不影响原来的返回值。
2548
2549::
2550
2551 from bs4.element import CData
2552 soup = BeautifulSoup("<a></a>", 'html.parser')
2553 soup.a.string = CData("one < three")
2554 print(soup.a.prettify(formatter="html"))
2555 # <a>
2556 # <![CDATA[one < three]]>
2557 # </a>
19782558
1979get_text()2559get_text()
1980----------2560----------
19812561
1982如果只想得到tag中包含的文本内容,那么可以调用 ``get_text()`` 方法,这个方法获取到tag中包含的所有文版内容包括子孙tag中的内容,并将结果作为Unicode字符串返回:2562如果只想得到 tag 中包含的文本内容,那么可以调用 ``get_text()`` 方法,这个方法获取到 tag
2563包含的所有文本内容,包括子孙 tag 中的可读内容,并将结果作为单独的一个 Unicode 编码字符串返回:
19832564
1984::2565::
19852566
1986 markup = '<a href="http://example.com/">\nI linked to <i>example.com</i>\n</a>'2567 markup = '<a href="http://example.com/">\nI linked to <i>example.com</i>\n</a>'
1987 soup = BeautifulSoup(markup)2568 soup = BeautifulSoup(markup, 'html.parser')
19882569
1989 soup.get_text()2570 soup.get_text()
1990 u'\nI linked to example.com\n'2571 '\nI linked to example.com\n'
1991 soup.i.get_text()2572 soup.i.get_text()
1992 u'example.com'2573 'example.com''
19932574
1994可以通过参数指定tag的文本内容的分隔符:2575可以通过参数指定 tag 的文本内容的连接符:
19952576
1996::2577::
19972578
1998 # soup.get_text("|")2579 # soup.get_text("|")
1999 u'\nI linked to |example.com|\n'2580 '\nI linked to |example.com|\n'
20002581
2001还可以去除获得文本内容的前后空白:2582还可以去除每一个文本片段内容的前后空白:
20022583
2003::2584::
20042585
2005 # soup.get_text("|", strip=True)2586 # soup.get_text("|", strip=True)
2006 u'I linked to|example.com'2587 'I linked to|example.com'
20072588
2008或者使用 `.stripped_strings`_ 生成器,获得文本列表后手动处理列表:2589但这种情况,你可能应该使用 `.stripped_strings <string-generators>`_ 生成器,
2590获得文本列表后手动处理内容:
20092591
2010::2592::
20112593
2012 [text for text in soup.stripped_strings]2594 [text for text in soup.stripped_strings]
2013 # [u'I linked to', u'example.com']2595 # ['I linked to', 'example.com']
2596
2597*因为 Beautiful Soup 4.9.0 版本开始使用 lxml 或 html.parser,<script>,<style> 和
2598<template> 标签中的内容不会被当做普通的 '文本' 来处理,因此这些标签中的内容不会算作页面中的
2599可读内容的一部分。*
2600
2601*Beautiful Soup 4.10.0 版本以后,可以在 NavigableString 对象上调用 get_text(),.strings
2602或 .stripped_strings 属性,结果会返回对象本身或空,这种用法只有在对混合类型列表迭代时才会用到。*
20142603
2015指定文档解析器2604指定文档解析器
2016==============2605==============
20172606
2018如果仅是想要解析HTML文档,只要用文档创建 ``BeautifulSoup`` 对象就可以了.Beautiful Soup会自动选择一个解析器来解析文档.但是还可以通过参数指定使用那种解析器来解析当前文档.2607如果仅是想要解析HTML文档,只需要创建 ``BeautifulSoup`` 对象时传入文档就可以了。Beautiful Soup
2608会自动选择一个解析器来解析文档。同时还可以使用额外参数,来指定文档解析器。
2609
2610``BeautifulSoup`` 第一个参数应该是要被解析的文档字符串或是文件句柄 -- 待解析文件的句柄,
2611第二个参数用来标识怎样解析文档。
20192612
2020``BeautifulSoup`` 第一个参数应该是要被解析的文档字符串或是文件句柄,第二个参数用来标识怎样解析文档.如果第二个参数为空,那么Beautiful Soup根据当前系统安装的库自动选择解析器,解析器的优先数序: lxml, html5lib, Python标准库.在下面两种条件下解析器优先顺序会变化:2613如果不指定解析器,默认使用已安装的 `最佳` HTML 解析器。Beautiful Soup 把 lxml 解析器排在第一,
2614然后是 html5lib, 然后是 Python 标准库。在下面两种条件下解析器优先顺序会变化:
20212615
2022 * 要解析的文档是什么类型: 目前支持, “html”, “xml”, 和 “html5”2616 * 要解析的文档是什么类型: 目前支持, “html”,“xml”,和 “html5”
2023 * 指定使用哪种解析器: 目前支持, “lxml”, “html5lib”, 和 “html.parser”2617 * 指定使用哪种解析器: 目前支持,“lxml”,“html5lib”,和 “html.parser”(Python 标准库)
20242618
2025`安装解析器`_ 章节介绍了可以使用哪种解析器,以及如何安装.2619`安装解析器`_ 章节介绍了可以使用哪种解析器,以及如何安装。
20262620
2027如果指定的解析器没有安装,Beautiful Soup会自动选择其它方案.目前只有 lxml 解析器支持XML文档的解析,在没有安装lxml库的情况下,创建 ``beautifulsoup`` 对象时无论是否指定使用lxml,都无法得到解析后的对象2621如果指定的解析器没有安装,Beautiful Soup会自动选择其它方案。目前只有 lxml 解析器支持XML文档的解析,
2622在没有安装 lxml 库的情况下,无法自动选择 XML 文档解析器,手动指定 lxml 也不行。
20282623
2029解析器之间的区别2624解析器之间的区别
2030-----------------2625-----------------
20312626
2032Beautiful Soup为不同的解析器提供了相同的接口,但解析器本身是有区别的.同一篇文档被不同的解析器解析后可能会生成不同结构的树型文档.区别最大的是HTML解析器和XML解析器.以下是被Python自带的HTML解析器解析成的HTML片段:2627Beautiful Soup 为不同的解析器提供了相同的接口,但解析器本身时有区别的。同一篇文档被不同的解析器解析后
2628可能会生成不同结构的文档。区别最大的是 HTML 解析器和 XML 解析器,看下面片段被解析成 HTML 结构:
20332629
2034::2630::
20352631
2036 BeautifulSoup("<a><b /></a>")2632 BeautifulSoup("<a><b/></a>", "html.parser")
2037 # <html><head></head><body><a><b></b></a></body></html>2633 # <a><b></b></a>
20382634
2039因为空标签<b />不符合HTML标准,所以解析器把它解析成<b></b>2635因为空标签 <b /> 不符合 HTML 标准,html.parser 解析器把它解析成一对儿 <b></b>。
20402636
2041同样的文档使用XML解析如下(解析XML需要安装lxml库).注意,空标签<b />依然被保留,并且文档前添加了XML头,而不是被包含在<html>标签内:2637同样的文档使用 XML 解析结果如下(解析 XML 需要安装 lxml 库)。注意,空标签 <b /> 依然被保留,
2638并且文档前添加了 XML 头,而不是被包含在 <html> 标签内:
20422639
2043::2640::
20442641
2045 BeautifulSoup("<a><b /></a>", "xml")2642 print(BeautifulSoup("<a><b/></a>", "xml"))
2046 # <?xml version="1.0" encoding="utf-8"?>2643 # <?xml version="1.0" encoding="utf-8"?>
2047 # <a><b/></a>2644 # <a><b/></a>
20482645
2049HTML解析器之间也有区别,如果被解析的HTML文档是标准格式,那么解析器之间没有任何差别,只是解析速度不同,结果都会返回正确的文档树.2646HTML 解析器之间也有区别,如果被解析的HTML文档是标准格式,那么解析器之间没有任何差别。
2647只是解析速度不同,结果都会返回正确的文档树。
20502648
2051但是如果被解析文档不是标准格式,那么不同的解析器返回结果可能不同.下面例子中,使用lxml解析错误格式的文档,结果</p>标签被直接忽略掉了:2649但是如果被解析文档不是标准格式,那么不同的解析器返回结果可能不同。下面例子中,使用 lxml
2650解析错误格式的文档,结果 </p> 标签被直接忽略掉了:
20522651
2053::2652::
20542653
2055 BeautifulSoup("<a></p>", "lxml")2654 BeautifulSoup("<a></p>", "lxml")
2056 # <html><body><a></a></body></html>2655 # <html><body><a></a></body></html>
20572656
2058使用html5lib库解析相同文档会得到不同的结果:2657使用 html5lib 库解析相同文档会得到不同的结果:
20592658
2060::2659::
20612660
2062 BeautifulSoup("<a></p>", "html5lib")2661 BeautifulSoup("<a></p>", "html5lib")
2063 # <html><head></head><body><a><p></p></a></body></html>2662 # <html><head></head><body><a><p></p></a></body></html>
20642663
2065html5lib库没有忽略掉</p>标签,而是自动补全了标签,还给文档树添加了<head>标签.2664html5lib 库没有忽略掉 </p> 标签,而是自动补全了标签,还给文档树添加了 <head> 标签。
20662665
2067使用pyhton内置库解析结果如下:2666使用 pyhton 内置库解析结果如下:
20682667
2069::2668::
20702669
2071 BeautifulSoup("<a></p>", "html.parser")2670 BeautifulSoup("<a></p>", "html.parser")
2072 # <a></a>2671 # <a></a>
20732672
2074与lxml [7]_ 库类似的,Python内置库忽略掉了</p>标签,与html5lib库不同的是标准库没有尝试创建符合标准的文档格式或将文档片段包含在<body>标签内,与lxml不同的是标准库甚至连<html>标签都没有尝试去添加.2673与 lxml [7]_ 库类似的,Python 内置库忽略掉了 </p> 标签,与 html5lib 库不同的是标准库没有
2674尝试创建符合标准的文档格式或将文档片段包含在 <body> 标签内,与lxml不同的是标准库甚至连 <html>
2675标签都没有尝试去添加。
20752676
2076因为文档片段“<a></p>”是错误格式,所以以上解析方式都能算作"正确",html5lib库使用的是HTML5的部分标准,所以最接近"正确".不过所有解析器的结构都能够被认为是"正常"的.2677因为文档片段 “<a></p>” 是错误格式,所以以上解析方式都能算作 "正确",html5lib 库使用的是 HTML5
2678的部分标准,所以最接近"正确"。不过所有解析器的结构都能够被认为是"正常"的。
20772679
2078不同的解析器可能影响代码执行结果,如果在分发给别人的代码中使用了 ``BeautifulSoup`` ,那么最好注明使用了哪种解析器,以减少不必要的麻烦.2680不同的解析器可能影响代码执行结果,如果在分发给别人的代码中使用了 ``BeautifulSoup`` ,
2681那么最好注明使用了哪种解析器,以减少不必要的麻烦。
20792682
2080编码2683编码
2081====2684====
20822685
2083任何HTML或XML文档都有自己的编码方式,比如ASCII 或 UTF-8,但是使用Beautiful Soup解析后,文档都被转换成了Unicode:2686任何 HTML 或 XML 文档都有自己的编码方式,比如ASCII 或 UTF-8。但是使用 Beautiful Soup 解析后,
2687文档都被转换成了 Unicode:
20842688
2085::2689::
20862690
2087 markup = "<h1>Sacr\xc3\xa9 bleu!</h1>"2691 markup = "<h1>Sacr\xc3\xa9 bleu!</h1>"
2088 soup = BeautifulSoup(markup)2692 soup = BeautifulSoup(markup, 'html.parser')
2089 soup.h12693 soup.h1
2090 # <h1>Sacré bleu!</h1>2694 # <h1>Sacré bleu!</h1>
2091 soup.h1.string2695 soup.h1.string
2092 # u'Sacr\xe9 bleu!'2696 # 'Sacr\xe9 bleu!'
20932697
2094这不是魔术(但很神奇),Beautiful Soup用了 `编码自动检测`_ 子库来识别当前文档编码并转换成Unicode编码. ``BeautifulSoup`` 对象的 ``.original_encoding`` 属性记录了自动识别编码的结果:2698这不是魔术(但很神奇),Beautiful Soup 用了 `编码自动检测 <Unicode, Dammit>`_ 子库来识别当前
2699文档编码并转换成 Unicode 编码。``BeautifulSoup`` 对象的 ``.original_encoding`` 属性记录了
2700自动识别编码的结果:
20952701
2096::2702::
20972703
2098 soup.original_encoding2704 soup.original_encoding
2099 'utf-8'2705 'utf-8'
21002706
2101`编码自动检测`_ 功能大部分时候都能猜对编码格式,但有时候也会出错.有时候即使猜测正确,也是在逐个字节的遍历整个文档后才猜对的,这样很慢.如果预先知道文档编码,可以设置编码参数来减少自动检查编码出错的概率并且提高文档解析速度.在创建 ``BeautifulSoup`` 对象的时候设置 ``from_encoding`` 参数.2707`编码自动检测 <Unicode, Dammit>`_ 功能大部分时候都能猜对编码格式,但有时候也会出错。有时候即使
2708猜测正确,也是在逐个 字节的遍历整个文档后才猜对的,这样很慢。如果预先知道文档编码,可以设置编码参数
2709来减少自动检查编码 出错的概率并且提高文档解析速度。在创建 ``BeautifulSoup`` 对象的时候设置
2710``from_encoding`` 参数。
21022711
2103下面一段文档用了ISO-8859-8编码方式,这段文档太短,结果Beautiful Soup以为文档是用ISO-8859-7编码:2712下面一段文档用了 ISO-8859-8 编码方式,这段文档太短,结果 Beautiful Soup 以为文档是用 ISO-8859-7 编码:
21042713
2105::2714::
21062715
2107 markup = b"<h1>\xed\xe5\xec\xf9</h1>"2716 markup = b"<h1>\xed\xe5\xec\xf9</h1>"
2108 soup = BeautifulSoup(markup)2717 soup = BeautifulSoup(markup, 'html.parser')
2109 soup.h12718 print(soup.h1)
2110 <h1>νεμω</h1>2719 # <h1>νεμω</h1>
2111 soup.original_encoding2720 print(soup.original_encoding)
2112 'ISO-8859-7'2721 # iso-8859-7
21132722
2114通过传入 ``from_encoding`` 参数来指定编码方式:2723通过传入 ``from_encoding`` 参数来指定编码方式:
21152724
2116::2725::
21172726
2118 soup = BeautifulSoup(markup, from_encoding="iso-8859-8")2727 soup = BeautifulSoup(markup, 'html.parser', from_encoding="iso-8859-8")
2119 soup.h12728 print(soup.h1)
2120 <h1>םולש</h1>2729 # <h1>םולש</h1>
2121 soup.original_encoding2730 print(soup.original_encoding)
2122 'iso8859-8'2731 # iso8859-8
2732
2733如果仅知道文档采用了 Unicode 编码,但不知道具体编码。可以先自己猜测,猜测错误(依旧是乱码)时,
2734可以把错误编码作为 ``exclude_encodings`` 参数,这样文档就不会尝试使用这种编码了解码了。
21232735
2124如果仅知道文档采用了Unicode编码, 但不知道具体编码. 可以先自己猜测, 猜测错误(依旧是乱码)时,2736译者备注: 在没有指定编码的情况下,BS会自己猜测编码,把不正确的编码排除掉,BS就更容易猜到正确编码。
2125可以把错误编码作为 ``exclude_encodings`` 参数, 这样文档就不会尝试使用这种编码了解码了.
2126译者备注: 在没有指定编码的情况下, BS会自己猜测编码, 把不正确的编码排除掉, BS就更容易猜到正确编码.
21272737
2128::2738::
21292739
2130 soup = BeautifulSoup(markup, exclude_encodings=["ISO-8859-7"])2740 soup = BeautifulSoup(markup, 'html.parser', exclude_encodings=["iso-8859-7"])
2131 soup.h12741 print(soup.h1)
2132 <h1>םולש</h1>2742 # <h1>םולש</h1>
2133 soup.original_encoding2743 print(soup.original_encoding)
2134 'WINDOWS-1255'2744 # WINDOWS-1255
21352745
2136猜测结果是 Windows-1255 编码, 猜测结果可能不够准确, 但是 Windows-1255 编码是 ISO-8859-8 的扩展集,2746猜测的结果 Windows-1255 可能不是 100% 准确,但是 Windows-1255 编码是 ISO-8859-8 的扩展集,
2137所以猜测结果已经十分接近了, 并且不影响使用. (``exclude_encodings`` 参数是 4.4.0版本的新功能)2747所以猜测结果已经十分接近了,并不影响使用。(``exclude_encodings`` 参数是 4.4.0版本的新功能)
21382748
2139少数情况下(通常是UTF-8编码的文档中包含了其它编码格式的文件),想获得正确的Unicode编码就不得不将文档中少数特殊编码字符替换成特殊Unicode编码,“REPLACEMENT CHARACTER” (U+FFFD, �) [9]_ . 如果Beautifu Soup猜测文档编码时作了特殊字符的替换,那么Beautiful Soup会把 ``UnicodeDammit`` 或 ``BeautifulSoup`` 对象的 ``.contains_replacement_characters`` 属性标记为 ``True`` .这样就可以知道当前文档进行Unicode编码后丢失了一部分特殊内容字符.如果文档中包含�而 ``.contains_replacement_characters`` 属性是 ``False`` ,则表示�就是文档中原来的字符,不是转码失败.2749少数情况下(通常是UTF-8编码的文档中包含了其它编码格式的文件),想获得正确的 Unicode 编码就不得不将
2750文档中少数特殊编码字符替换成特殊 Unicode 编码,“REPLACEMENT CHARACTER” (U+FFFD, �) [9]_ 。
2751如果 Beautifu Soup 猜测文档编码时作了特殊字符的替换,那么 Beautiful Soup 会把 ``UnicodeDammit``
2752或 ``BeautifulSoup`` 对象的 ``.contains_replacement_characters`` 属性标记为 ``True`` 。
2753这样就可以知道当前文档进行 Unicode 编码后丢失了一部分特殊内容字符。如果文档中包含 � 而
2754``.contains_replacement_characters`` 属性是 ``False`` ,则表示 � 就是文档中原来的字符,
2755不是转码失败。
21402756
2141输出编码2757输出编码
2142--------2758--------
21432759
2144通过Beautiful Soup输出文档时,不管输入文档是什么编码方式,输出编码均为UTF-8编码,下面例子输入文档是Latin-1编码:2760通过 Beautiful Soup 输出文档时,不管输入文档是什么编码方式,输出编码均为UTF-8编码,
2761下面例子输入文档是 Latin-1 编码:
21452762
2146::2763::
21472764
2148 markup = b'''2765 markup = b'''
2149 <html>2766 <html>
2150 <head>2767 <head>
2151 <meta content="text/html; charset=ISO-Latin-1" http-equiv="Content-type" />2768 <meta content="text/html; charset=ISO-Latin-1" http-equiv="Content-type" />
2152 </head>2769 </head>
2153 <body>2770 <body>
2154 <p>Sacr\xe9 bleu!</p>2771 <p>Sacr\xe9 bleu!</p>
2155 </body>2772 </body>
2156 </html>2773 </html>
2157 '''2774 '''
2158
2159 soup = BeautifulSoup(markup)
2160 print(soup.prettify())
2161 # <html>
2162 # <head>
2163 # <meta content="text/html; charset=utf-8" http-equiv="Content-type" />
2164 # </head>
2165 # <body>
2166 # <p>
2167 # Sacré bleu!
2168 # </p>
2169 # </body>
2170 # </html>
21712775
2172注意,输出文档中的<meta>标签的编码设置已经修改成了与输出编码一致的UTF-8.2776 soup = BeautifulSoup(markup, 'html.parser')
2777 print(soup.prettify())
2778 # <html>
2779 # <head>
2780 # <meta content="text/html; charset=utf-8" http-equiv="Content-type" />
2781 # </head>
2782 # <body>
2783 # <p>
2784 # Sacré bleu!
2785 # </p>
2786 # </body>
2787 # </html>
21732788
2174如果不想用UTF-8编码输出,可以将编码方式传入 ``prettify()`` 方法:2789注意,输出文档中的 <meta> 标签内容中的编码信息已经修改成了与输出编码一致的 UTF-8。
2790
2791如果不想用 UTF-8 编码输出,可以将编码方式传入 ``prettify()`` 方法:
21752792
2176::2793::
21772794
@@ -2181,103 +2798,107 @@ html5lib库没有忽略掉</p>标签,而是自动补全了标签,还给文档树
2181 # <meta content="text/html; charset=latin-1" http-equiv="Content-type" />2798 # <meta content="text/html; charset=latin-1" http-equiv="Content-type" />
2182 # ...2799 # ...
21832800
2184还可以调用 ``BeautifulSoup`` 对象或任意节点的 ``encode()`` 方法,就像Python的字符串调用 ``encode()`` 方法一样:2801还可以调用 ``BeautifulSoup`` 对象或任意节点的 ``encode()`` 方法,就像 Python 的字符串
2802调用 ``encode()`` 方法一样:
21852803
2186::2804::
21872805
2188 soup.p.encode("latin-1")2806 soup.p.encode("latin-1")
2189 # '<p>Sacr\xe9 bleu!</p>'2807 # b'<p>Sacr\xe9 bleu!</p>'
21902808
2191 soup.p.encode("utf-8")2809 soup.p.encode("utf-8")
2192 # '<p>Sacr\xc3\xa9 bleu!</p>'2810 # b'<p>Sacr\xc3\xa9 bleu!</p>'
21932811
2194如果文档中包含当前编码不支持的字符,那么这些字符将被转换成一系列XML特殊字符引用,下面例子中包含了Unicode编码字符SNOWMAN:2812如果文档中包含当前编码不支持的字符,那么这些字符将被转换成一系列 XML 特殊字符引用,下面例子中
2813包含了 Unicode 编码字符 SNOWMAN:
21952814
2196::2815::
21972816
2198 markup = u"<b>\N{SNOWMAN}</b>"2817 markup = u"<b>\N{SNOWMAN}</b>"
2199 snowman_soup = BeautifulSoup(markup)2818 snowman_soup = BeautifulSoup(markup, 'html.parser')
2200 tag = snowman_soup.b2819 tag = snowman_soup.b
22012820
2202SNOWMAN字符在UTF-8编码中可以正常显示(看上去像是☃),但有些编码不支持SNOWMAN字符,比如ISO-Latin-1或ASCII,那么在这些编码中SNOWMAN字符会被转换成“&#9731”:2821SNOWMAN 字符在 UTF-8 编码中可以正常显示(看上去是 ☃),但有些编码不支持 SNOWMAN 字符,比如
2822ISO-Latin-1 或 ASCII,那么在这些编码中 SNOWMAN 字符会被转换成 “&#9731”:
22032823
2204::2824::
22052825
2206 print(tag.encode("utf-8"))2826 print(tag.encode("utf-8"))
2207 # <b>☃</b>2827 # b'<b>\xe2\x98\x83</b>'
22082828
2209 print tag.encode("latin-1")2829 print(tag.encode("latin-1"))
2210 # <b>&#9731;</b>2830 # b'<b>&#9731;</b>'
22112831
2212 print tag.encode("ascii")2832 print(tag.encode("ascii"))
2213 # <b>&#9731;</b>2833 # b'<b>&#9731;</b>'
22142834
2215Unicode, Dammit! (乱码, 靠!)2835Unicode, Dammit
2216-----------------------------2836----------------------
22172837
2218译者备注: UnicodeDammit 是BS内置库, 主要用来猜测文档编码.2838译者备注: Unicode Dammit 是 Beautiful Soup 内置库,主要用来猜测文档编码。
22192839
2220`编码自动检测`_ 功能可以在Beautiful Soup以外使用,检测某段未知编码时,可以使用这个方法:2840`编码自动检测 <Unicode, Dammit>`_ 功能可以在 Beautiful Soup 以外使用。当遇到一段未知编码
2841的文档时,可以通过下面方法把它转换为 Unicode 编码
22212842
2222::2843::
22232844
2224 from bs4 import UnicodeDammit2845 from bs4 import UnicodeDammit
2225 dammit = UnicodeDammit("Sacr\xc3\xa9 bleu!")2846 dammit = UnicodeDammit(b"\xc2\xabSacr\xc3\xa9 bleu!\xc2\xbb")
2226 print(dammit.unicode_markup)2847 print(dammit.unicode_markup)
2227 # Sacré bleu!2848 # «Sacré bleu!»
2228 dammit.original_encoding2849 dammit.original_encoding
2229 # 'utf-8'2850 # 'utf-8'
22302851
2231如果Python中安装了 ``chardet`` 或 ``cchardet`` 那么编码检测功能的准确率将大大提高.2852如果安装了 Python 的 ``chardet`` 或 ``cchardet`` 库,那么编码检测功能的准确率将大大提高。
2232输入的字符越多,检测结果越精确,如果事先猜测到一些可能编码,2853输入的字符越多,检测结果越准确,如果事先猜测到一些可能编码,那么可以将猜测的编码作为参数,
2233那么可以将猜测的编码作为参数,这样将优先检测这些编码:2854这样将优先检测这些编码:
22342855
2235::2856::
22362857
2237
2238 dammit = UnicodeDammit("Sacr\xe9 bleu!", ["latin-1", "iso-8859-1"])2858 dammit = UnicodeDammit("Sacr\xe9 bleu!", ["latin-1", "iso-8859-1"])
2239 print(dammit.unicode_markup)2859 print(dammit.unicode_markup)
2240 # Sacré bleu!2860 # Sacré bleu!
2241 dammit.original_encoding2861 dammit.original_encoding
2242 # 'latin-1'2862 # 'latin-1'
22432863
2244`编码自动检测`_ 功能中有2项功能是Beautiful Soup库中用不到的2864`编码自动检测 <Unicode, Dammit>`_ 功能中有 2 项功能是 Beautiful Soup 库中用不到的
22452865
2246智能引号2866智能引号
2247...........2867^^^^^^^^^^^
22482868
2249使用Unicode时,Beautiful Soup还会智能的把引号 [10]_ 转换成HTML或XML中的特殊字符:2869使用 Unicode 时,Beautiful Soup 还会智能的把引号 [10]_ 转换成 HTML 或 XML 中的特殊字符:
22502870
2251::2871::
22522872
2253 markup = b"<p>I just \x93love\x94 Microsoft Word\x92s smart quotes</p>"2873 markup = b"<p>I just \x93love\x94 Microsoft Word\x92s smart quotes</p>"
22542874
2255 UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="html").unicode_markup2875 UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="html").unicode_markup
2256 # u'<p>I just &ldquo;love&rdquo; Microsoft Word&rsquo;s smart quotes</p>'2876 # '<p>I just &ldquo;love&rdquo; Microsoft Word&rsquo;s smart quotes</p>'
22572877
2258 UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="xml").unicode_markup2878 UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="xml").unicode_markup
2259 # u'<p>I just &#x201C;love&#x201D; Microsoft Word&#x2019;s smart quotes</p>'2879 # '<p>I just &#x201C;love&#x201D; Microsoft Word&#x2019;s smart quotes</p>'
22602880
2261也可以把引号转换为ASCII码:2881也可以把引号转换为 ASCII 码:
22622882
2263::2883::
22642884
2265 UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="ascii").unicode_markup2885 UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="ascii").unicode_markup
2266 # u'<p>I just "love" Microsoft Word\'s smart quotes</p>'2886 # '<p>I just "love" Microsoft Word\'s smart quotes</p>'
22672887
2268很有用的功能,但是Beautiful Soup没有使用这种方式.默认情况下,Beautiful Soup把引号转换成Unicode:2888虽然这个功能很有用,但是 Beautiful Soup 没有使用这种方式。默认情况下,Beautiful Soup
2889把引号转换成 Unicode:
22692890
2270::2891::
22712892
2272 UnicodeDammit(markup, ["windows-1252"]).unicode_markup2893 UnicodeDammit(markup, ["windows-1252"]).unicode_markup
2273 # u'<p>I just \u201clove\u201d Microsoft Word\u2019s smart quotes</p>'2894 # '<p>I just “love” Microsoft Word’s smart quotes</p>'
22742895
2275矛盾的编码2896矛盾的编码
2276...........2897^^^^^^^^^^^^^
22772898
2278有时文档的大部分都是用UTF-8,但同时还包含了Windows-1252编码的字符,就像微软的智能引号 [10]_ 一样.2899有时文档的大部分都是用 UTF-8,但同时还包含了 Windows-1252 编码的字符,就像微软的智能引号 [10]_ 一样。
2279一些包含多个信息的来源网站容易出现这种情况. ``UnicodeDammit.detwingle()``2900一些包含多个信息的来源网站容易出现这种情况。``UnicodeDammit.detwingle()`` 方法可以把这类文档转换成纯
2280方法可以把这类文档转换成纯UTF-8编码格式,看个简单的例子:2901UTF-8 编码格式,看个简单的例子:
22812902
2282::2903::
22832904
@@ -2285,7 +2906,8 @@ Unicode, Dammit! (乱码, 靠!)
2285 quote = (u"\N{LEFT DOUBLE QUOTATION MARK}I like snowmen!\N{RIGHT DOUBLE QUOTATION MARK}")2906 quote = (u"\N{LEFT DOUBLE QUOTATION MARK}I like snowmen!\N{RIGHT DOUBLE QUOTATION MARK}")
2286 doc = snowmen.encode("utf8") + quote.encode("windows_1252")2907 doc = snowmen.encode("utf8") + quote.encode("windows_1252")
22872908
2288这段文档很杂乱,snowmen是UTF-8编码,引号是Windows-1252编码,直接输出时不能同时显示snowmen和引号,因为它们编码不同:2909这段文档很杂乱,snowmen 是 UTF-8 编码,引号是 Windows-1252 编码,直接输出时不能同时显示
2910snowmen 和引号,因为它们编码不同:
22892911
2290::2912::
22912913
@@ -2295,8 +2917,9 @@ Unicode, Dammit! (乱码, 靠!)
2295 print(doc.decode("windows-1252"))2917 print(doc.decode("windows-1252"))
2296 # ☃☃☃“I like snowmen!”2918 # ☃☃☃“I like snowmen!”
22972919
2298如果对这段文档用UTF-8解码就会得到 ``UnicodeDecodeError`` 异常,如果用Windows-1252解码就回得到一堆乱码.2920如果对这段文档用 UTF-8 解码就会产生 ``UnicodeDecodeError`` 异常,如果用 Windows-1252
2299幸好, ``UnicodeDammit.detwingle()`` 方法会把这段字符串转换成UTF-8编码,允许我们同时显示出文档中的snowmen和引号:2921解码就会得到一堆乱码。幸好,``UnicodeDammit.detwingle()`` 方法会把这段字符串转换成 UTF-8
2922编码,允许我们同时显示出文档中的 snowmen 和引号:
23002923
2301::2924::
23022925
@@ -2304,29 +2927,71 @@ Unicode, Dammit! (乱码, 靠!)
2304 print(new_doc.decode("utf8"))2927 print(new_doc.decode("utf8"))
2305 # ☃☃☃“I like snowmen!”2928 # ☃☃☃“I like snowmen!”
23062929
2307``UnicodeDammit.detwingle()`` 方法只能解码包含在UTF-8编码中的Windows-1252编码内容,但这解决了最常见的一类问题.2930``UnicodeDammit.detwingle()`` 方法只能解码包含在 UTF-8 编码中的 Windows-1252 编码内容,
2931(反过来的话,大概也可以)但这是最常见的用法。
2932
2933在创建 ``BeautifulSoup`` 或 ``UnicodeDammit`` 对象前一定要先对文档调用
2934``UnicodeDammit.detwingle()`` 确保文档的编码方式正确。Beautiful Soup
2935会假设文档只包含一种编码,如果尝试去解析一段同时包含 UTF-8 和 Windows-1252 编码的文档,
2936就有可能被误判成整个文档都是 Windows-1252 编码,解析结果就会得到一堆乱码,
2937比如: ☃☃☃“I like snowmen!”。
23082938
2309在创建 ``BeautifulSoup`` 或 ``UnicodeDammit`` 对象前一定要先对文档调用 ``UnicodeDammit.detwingle()`` 确保文档的编码方式正确.如果尝试去解析一段包含Windows-1252编码的UTF-8文档,就会得到一堆乱码,比如: ☃☃☃“I like snowmen!”.2939``UnicodeDammit.detwingle()`` 方法在 Beautiful Soup 4.1.0 版本中新增。
23102940
2311``UnicodeDammit.detwingle()`` 方法在Beautiful Soup 4.1.0版本中新增2941行编号
2942==========
2943
2944``html.parser`` 和 ``html5lib`` 解析器可以跟踪原始文档中发现的每个 Tag。查看原始信息可以
2945使用 ``Tag.sourceline`` (行号)和 ``Tag.sourcepos`` (标签所在行的起始位置)
2946
2947::
2948
2949 markup = "<p\n>Paragraph 1</p>\n <p>Paragraph 2</p>"
2950 soup = BeautifulSoup(markup, 'html.parser')
2951 for tag in soup.find_all('p'):
2952 print(repr((tag.sourceline, tag.sourcepos, tag.string)))
2953 # (1, 0, 'Paragraph 1')
2954 # (3, 4, 'Paragraph 2')
2955
2956注意,这两个解析器的 ``sourceline`` 和 ``sourcepos`` 会有些许的不同。html.parser 将
2957标签开始的 小于号作为标签起始符号,而 html5lib 将标签开始的大于号作为标签起始符号
2958
2959::
2960
2961 soup = BeautifulSoup(markup, 'html5lib')
2962 for tag in soup.find_all('p'):
2963 print(repr((tag.sourceline, tag.sourcepos, tag.string)))
2964 # (2, 0, 'Paragraph 1')
2965 # (3, 6, 'Paragraph 2')
2966
2967可以在 BeautifulSoup 构造函数中配置 ``store_line_numbers=False`` 来关闭这个功能
2968
2969::
2970
2971 markup = "<p\n>Paragraph 1</p>\n <p>Paragraph 2</p>"
2972 soup = BeautifulSoup(markup, 'html.parser', store_line_numbers=False)
2973 print(soup.p.sourceline)
2974 # None
2975
2976这个功能在 4.8.1 版本中引入,lxml 解析器不支持这个功能。
23122977
2313比较对象是否相同2978比较对象是否相同
2314=================2979=================
23152980
2316两个 ``NavigableString`` 或 ``Tag`` 对象具有相同的HTML或XML结构时,2981两个 ``NavigableString`` 或 ``Tag`` 对象具有相同的 HTML 或 XML 结构时,
2317Beautiful Soup就判断这两个对象相同. 这个例子中, 2个 <b> 标签在 BS 中是相同的,2982Beautiful Soup就判断这两个对象相同。这个例子中,2个 <b> 标签在 BS 中是相同的,
2318尽管他们在文档树的不同位置, 但是具有相同的表象: "<b>pizza</b>"2983尽管他们在文档树的不同位置,但是具有相同的表象: "<b>pizza</b>"
23192984
2320::2985::
23212986
2322 markup = "<p>I want <b>pizza</b> and more <b>pizza</b>!</p>"2987 markup = "<p>I want <b>pizza</b> and more <b>pizza</b>!</p>"
2323 soup = BeautifulSoup(markup, 'html.parser')2988 soup = BeautifulSoup(markup, 'html.parser')
2324 first_b, second_b = soup.find_all('b')2989 first_b, second_b = soup.find_all('b')
2325 print first_b == second_b2990 print(first_b == second_b)
2326 # True2991 # True
23272992
2328 print first_b.previous_element == second_b.previous_element2993 print(first_b.previous_element == second_b.previous_element)
2329 # False2994 # False
23302995
2331如果想判断两个对象是否严格的指向同一个对象可以通过 ``is`` 来判断2996如果想判断两个对象是否严格的指向同一个对象可以通过 ``is`` 来判断
23322997
@@ -2342,12 +3007,12 @@ Beautiful Soup就判断这两个对象相同. 这个例子中, 2个 <b> 标签
23423007
2343::3008::
23443009
2345 import copy3010 import copy
2346 p_copy = copy.copy(soup.p)3011 p_copy = copy.copy(soup.p)
2347 print p_copy3012 print(p_copy)
2348 # <p>I want <b>pizza</b> and more <b>pizza</b>!</p>3013 # <p>I want <b>pizza</b> and more <b>pizza</b>!</p>
23493014
2350复制后的对象跟与对象是相等的, 但指向不同的内存地址3015复制后的对象跟与对象是相等的,但指向不同的内存地址
23513016
2352::3017::
23533018
@@ -2357,8 +3022,8 @@ Beautiful Soup就判断这两个对象相同. 这个例子中, 2个 <b> 标签
2357 print soup.p is p_copy3022 print soup.p is p_copy
2358 # False3023 # False
23593024
2360源对象和复制对象的区别是源对象在文档树中, 而复制后的对象是独立的还没有添加到文档树中.3025源对象和复制对象的区别是源对象在文档树中,而复制后的对象是独立的还没有添加到文档树中。
2361复制后对象的效果跟调用了 ``extract()`` 方法相同.3026复制后对象的效果跟调用了 ``extract()`` 方法相同。
23623027
2363::3028::
23643029
@@ -2367,16 +3032,29 @@ Beautiful Soup就判断这两个对象相同. 这个例子中, 2个 <b> 标签
23673032
2368这是因为相等的对象不能同时插入相同的位置3033这是因为相等的对象不能同时插入相同的位置
23693034
3035高级自定义解析
3036================
3037
3038Beautiful Soup 提供多种途径自定义解析器如果解析 HTML 和 XML。本章覆盖了最常用的自定义方法。
23703039
2371解析部分文档3040解析部分文档
2372============3041-------------
23733042
2374如果仅仅因为想要查找文档中的<a>标签而将整片文档进行解析,实在是浪费内存和时间.最快的方法是从一开始就把<a>标签以外的东西都忽略掉. ``SoupStrainer`` 类可以定义文档的某段内容,这样搜索文档时就不必先解析整篇文档,只会解析在 ``SoupStrainer`` 中定义过的文档. 创建一个 ``SoupStrainer`` 对象并作为 ``parse_only`` 参数给 ``BeautifulSoup`` 的构造方法即可.3043如果仅仅因为想要查找文档中的 <a> 标签而将整片文档进行解析,实在是浪费内存和时间。最快的方法
3044是从一开始 就把 <a> 标签以外的东西都忽略掉。 ``SoupStrainer`` 类可以选择解析哪部分文档内容,
3045创建一个 ``SoupStrainer`` 对象并作为 ``parse_only`` 参数给 ``BeautifulSoup`` 的构造
3046方法即可。
3047
3048(注意,*这个功能在 html5lib 解析器中无法使用*。如果使用 html5lib 解析器,整篇文档都会被解析,
3049这是因为 html5lib 会重新排列文档树的结构,如果部分节点不在文档树中,会导致崩溃。为了避免混淆,
3050下面的例子中 Beautiful Soup 都强制指定使用了 Python 内置解析器。)
23753051
2376SoupStrainer3052SoupStrainer
2377-------------3053-------------
23783054
2379``SoupStrainer`` 类接受与典型搜索方法相同的参数:`name`_ , `attrs`_ , `recursive`_ , `string`_ , `**kwargs`_ 。下面举例说明三种 ``SoupStrainer`` 对象:3055``SoupStrainer`` 类接受与典型搜索方法相同的参数: `name`_ , `attrs`_ ,
3056`recursive <recursive>`_ , `string <string>`_ , `**kwargs <kwargs>`_ 。
3057下面举例说明三种 ``SoupStrainer`` 对象:
23803058
2381::3059::
23823060
@@ -2387,7 +3065,7 @@ SoupStrainer
2387 only_tags_with_id_link2 = SoupStrainer(id="link2")3065 only_tags_with_id_link2 = SoupStrainer(id="link2")
23883066
2389 def is_short_string(string):3067 def is_short_string(string):
2390 return len(string) < 103068 return string is not None and len(string) < 10
23913069
2392 only_short_strings = SoupStrainer(string=is_short_string)3070 only_short_strings = SoupStrainer(string=is_short_string)
23933071
@@ -2395,9 +3073,8 @@ SoupStrainer
23953073
2396::3074::
23973075
2398 html_doc = """3076 html_doc = """<html><head><title>The Dormouse's story</title></head>
2399 <html><head><title>The Dormouse's story</title></head>3077 <body>
2400 <body>
2401 <p class="title"><b>The Dormouse's story</b></p>3078 <p class="title"><b>The Dormouse's story</b></p>
24023079
2403 <p class="story">Once upon a time there were three little sisters; and their names were3080 <p class="story">Once upon a time there were three little sisters; and their names were
@@ -2434,27 +3111,147 @@ SoupStrainer
2434 # ...3111 # ...
2435 #3112 #
24363113
2437还可以将 ``SoupStrainer`` 作为参数传入 `搜索文档树`_ 中提到的方法.这可能不是个常用用法,所以还是提一下:3114还可以将 ``SoupStrainer`` 作为参数传入 `搜索文档树`_ 中提到的方法。虽然不常用,但还是提一下:
24383115
2439::3116::
24403117
2441 soup = BeautifulSoup(html_doc)3118 soup = BeautifulSoup(html_doc, 'html.parser')
2442 soup.find_all(only_short_strings)3119 soup.find_all(only_short_strings)
2443 # [u'\n\n', u'\n\n', u'Elsie', u',\n', u'Lacie', u' and\n', u'Tillie',3120 # ['\n\n', '\n\n', 'Elsie', ',\n', 'Lacie', ' and\n', 'Tillie',
2444 # u'\n\n', u'...', u'\n']3121 # '\n\n', '...', '\n']
3122
3123自定义包含多个值的属性
3124----------------------
3125
3126在 HTML 文档中,像 ``class`` 这样的属性的值是一个列表,像 ``id`` 这样的属性的值是一个单一字符串,
3127因为 HTML 标准定义了这些属性的不同行为
3128
3129::
3130
3131 markup = '<a class="cls1 cls2" id="id1 id2">'
3132 soup = BeautifulSoup(markup, 'html.parser')
3133 soup.a['class']
3134 # ['cls1', 'cls2']
3135 soup.a['id']
3136 # 'id1 id2'
3137
3138设置 ``multi_valued_attributes=None`` 可以禁用多值的自动识别,然后全部属性的值都变成一个字符串
3139
3140::
3141
3142 soup = BeautifulSoup(markup, 'html.parser', multi_valued_attributes=None)
3143 soup.a['class']
3144 # 'cls1 cls2'
3145 soup.a['id']
3146 # 'id1 id2'
3147
3148如果给 ``multi_valued_attributes`` 参数传入一个字典,可以实现一点点解析自定义。如果需要这么做,
3149查看 ``HTMLTreeBuilder.DEFAULT_CDATA_LIST_ATTRIBUTES`` 了解 Beautiful Soup 的默认配置,
3150这些均是基于 HTML 标准配置的。
3151
3152`(这个功能添加于 Beautiful Soup 4.8.0)`
3153
3154处理重复属性
3155---------------
3156
3157使用 ``html.parser`` 解析器时,可以通过设置 ``on_duplicate_attribute`` 参数,来定义当
3158Beautiful Soup 在 tag 中发现重复的属性名字时如何处理
3159::
3160
3161 markup = '<a href="http://url1/" href="http://url2/">'
3162
3163默认行为是,重名属性会使用最后出现的值
3164
3165::
3166
3167 soup = BeautifulSoup(markup, 'html.parser')
3168 soup.a['href']
3169 # http://url2/
3170
3171 soup = BeautifulSoup(markup, 'html.parser', on_duplicate_attribute='replace')
3172 soup.a['href']
3173 # http://url2/
3174
3175当 ``on_duplicate_attribute='ignore'`` 时,Beautiful Soup 会使用第一个出现的值,然后忽略
3176后出现的值
3177
3178::
3179
3180 soup = BeautifulSoup(markup, 'html.parser', on_duplicate_attribute='ignore')
3181 soup.a['href']
3182 # http://url1/
3183
3184(lxml 和 html5lib 总是采用这种处理方式,它们的默认行为不能通过 Beautiful Soup 配置。)
3185
3186如果需要复杂的控制,可以传入一个方法,当属性值重复时会被调用
3187
3188::
3189
3190 def accumulate(attributes_so_far, key, value):
3191 if not isinstance(attributes_so_far[key], list):
3192 attributes_so_far[key] = [attributes_so_far[key]]
3193 attributes_so_far[key].append(value)
3194
3195 soup = BeautifulSoup(markup, 'html.parser', on_duplicate_attribute=accumulate)
3196 soup.a['href']
3197 # ["http://url1/", "http://url2/"]
3198
3199这个特性新增于 Beautiful Soup 4.9.1。
3200
3201实例化自定义子类
3202------------------
3203
3204当解析器传递给 Beautiful Soup 一个标签或一个字符串后,Beautiful Soup 会实例化为 `Tag` 或
3205`NavigableString` 对象,并包含相关信息。如果想修改默认行为,可以让 Beautiful Soup 实例化
3206`Tag` 或 `NavigableString` 的子类,子类中可以自定义行为
3207
3208::
3209
3210 from bs4 import Tag, NavigableString
3211 class MyTag(Tag):
3212 pass
3213
3214
3215 class MyString(NavigableString):
3216 pass
3217
3218
3219 markup = "<div>some text</div>"
3220 soup = BeautifulSoup(markup, 'html.parser')
3221 isinstance(soup.div, MyTag)
3222 # False
3223 isinstance(soup.div.string, MyString)
3224 # False
3225
3226 my_classes = { Tag: MyTag, NavigableString: MyString }
3227 soup = BeautifulSoup(markup, 'html.parser', element_classes=my_classes)
3228 isinstance(soup.div, MyTag)
3229 # True
3230 isinstance(soup.div.string, MyString)
3231 # True
3232
3233这种用法可用在于 Beautiful Soup 与测试框架集成。
3234
3235这个特性新增于 Beautiful Soup 4.8.1。
24453236
2446常见问题3237常见问题
2447========3238========
24483239
3240.. _diagnose:
3241
2449代码诊断3242代码诊断
2450----------3243----------
24513244
2452如果想知道Beautiful Soup到底怎样处理一份文档,可以将文档传入 ``diagnose()`` 方法(Beautiful Soup 4.2.0中新增),Beautiful Soup会输出一份报告,说明不同的解析器会怎样处理这段文档,并标出当前的解析过程会使用哪种解析器:3245如果想知道 Beautiful Soup 到底怎样处理一份文档,可以将文档传入 ``diagnose()``
3246方法(Beautiful Soup 4.2.0中新增), Beautiful Soup 会输出一份报告,
3247说明不同的解析器会怎样处理这段文档,并标出当前的解析过程会使用哪种解析器:
24533248
2454::3249::
24553250
2456 from bs4.diagnose import diagnose3251 from bs4.diagnose import diagnose
2457 data = open("bad.html").read()3252 with open("bad.html") as fp:
3253 data = fp.read()
3254
2458 diagnose(data)3255 diagnose(data)
24593256
2460 # Diagnostic running on Beautiful Soup 4.2.03257 # Diagnostic running on Beautiful Soup 4.2.0
@@ -2466,93 +3263,150 @@ SoupStrainer
2466 # Here's what html.parser did with the document:3263 # Here's what html.parser did with the document:
2467 # ...3264 # ...
24683265
2469``diagnose()`` 方法的输出结果可能帮助你找到问题的原因,如果不行,还可以把结果复制出来以便寻求他人的帮助3266``diagnose()`` 方法的输出结果可能帮助你找到问题的原因,如果不行,还可以把结果复制出来以
3267便寻求他人的帮助。
24703268
2471文档解析错误3269文档解析错误
2472-------------3270-------------
24733271
2474文档解析错误有两种.一种是崩溃,Beautiful Soup尝试解析一段文档结果却抛除了异常,通常是 ``HTMLParser.HTMLParseError`` .还有一种异常情况,是Beautiful Soup解析后的文档树看起来与原来的内容相差很多.3272文档解析错误有两种。一种是崩溃,Beautiful Soup 尝试解析一段文档结果却抛除了异常,通常是
3273``HTMLParser.HTMLParseError`` 。还有一种异常情况,是Beautiful Soup 解析后的文档树
3274看起来与原来的内容相差很多。
24753275
2476这些错误几乎都不是Beautiful Soup的原因,这不会是因为Beautiful Soup的代码写的太优秀,而是因为Beautiful Soup没有包含任何文档解析代码.异常产生自被依赖的解析器,如果解析器不能很好的解析出当前的文档,那么最好的办法是换一个解析器.更多细节查看 `安装解析器`_ 章节.3276这些错误几乎都不是 Beautiful Soup 的原因,这不是因为 Beautiful Soup 的代码写得多优秀,
3277而是因为 Beautiful Soup 没有包含任何文档解析代码。异常产生自被依赖的解析器,如果解析器不能
3278很好的解析出当前的文档,那么最好的办法是换一个解析器。更多细节查看 `安装解析器`_ 章节。
24773279
2478最常见的解析错误是 ``HTMLParser.HTMLParseError: malformed start tag`` 和 ``HTMLParser.HTMLParseError: bad end tag`` .这都是由Python内置的解析器引起的,解决方法是 `安装lxml或html5lib`_3280最常见的解析错误是 ``HTMLParser.HTMLParseError: malformed start tag`` 和
3281``HTMLParser.HTMLParseError: bad end tag`` 。这都是由Python内置的解析器引起的,
3282解决方法是 `安装 lxml 或 html5lib <安装解析器>`_ 。
24793283
2480最常见的异常现象是当前文档找不到指定的Tag,而这个Tag光是用眼睛就足够发现的了. ``find_all()`` 方法返回 [] ,而 ``find()`` 方法返回 None .这是Python内置解析器的又一个问题: 解析器会跳过那些它不知道的tag.解决方法还是 `安装lxml或html5lib`_3284最常见的非预期行为是发现不了一个确定存在稳当中的 Tag。光是用眼睛就能轻易发现,但用 ``find_all()``
3285方法返回 [] ,用 ``find()`` 方法返回 None 。这是 Python 内置解析器的又一个问题: 解析器会跳过那些
3286它不知道的 tag。解决方法还是 `安装 lxml 或 html5lib <安装解析器>`_
24813287
2482版本错误3288版本错误
2483----------3289----------
24843290
2485* ``SyntaxError: Invalid syntax`` (异常位置在代码行: ``ROOT_TAG_NAME = u'[document]'`` ),因为Python2语法的代码(没有经过迁移)直接在Python3中运行3291* ``SyntaxError: Invalid syntax`` (异常位置在代码行: ``ROOT_TAG_NAME = u'[document]'`` ),
3292 原因是用 Python2 版本的 Beautiful Soup 未经过代码转换,直接在 Python3 中运行。
24863293
2487* ``ImportError: No module named HTMLParser`` 因为在Python3中执行Python2版本的Beautiful Soup3294* ``ImportError: No module named HTMLParser`` 因为在 Python3 中执行 Python2 版本的 Beautiful Soup。
24883295
2489* ``ImportError: No module named html.parser`` 因为在Python2中执行Python3版本的Beautiful Soup3296* ``ImportError: No module named html.parser`` 因为在 Python2 中执行 Python3 版本的 Beautiful Soup
24903297
2491* ``ImportError: No module named BeautifulSoup`` 因为在没有安装BeautifulSoup3库的Python环境下执行代码,或忘记了BeautifulSoup4的代码需要从 ``bs4`` 包中引入3298* ``ImportError: No module named BeautifulSoup`` 因为在没有安装 Beautiful Soup3 库的 Python 环境下执行代码,
3299 或忘记了 Beautiful Soup4 的代码需要从 ``bs4`` 包中引入。
24923300
2493* ``ImportError: No module named bs4`` 因为当前Python环境下还没有安装BeautifulSoup43301* ``ImportError: No module named bs4`` 因为当前 Python 环境下还没有安装 Beautiful Soup4。
24943302
2495解析成XML3303解析成XML
2496----------3304----------
24973305
2498默认情况下,Beautiful Soup会将当前文档作为HTML格式解析,如果要解析XML文档,要在 ``BeautifulSoup`` 构造方法中加入第二个参数 "xml":3306默认情况下,Beautiful Soup 会将当前文档作为 HTML 格式解析,如果要解析 XML 文档,要在
3307``BeautifulSoup`` 构造方法中加入第二个参数 "xml":
24993308
2500::3309::
25013310
2502 soup = BeautifulSoup(markup, "xml")3311 soup = BeautifulSoup(markup, "xml")
25033312
2504当然,还需要 `安装lxml`_3313当然,还需要 `安装 lxml <安装解析器>`_
25053314
2506解析器的错误3315其它解析器的错误
2507------------3316------------------
25083317
2509* 如果同样的代码在不同环境下结果不同,可能是因为两个环境下使用不同的解析器造成的.例如这个环境中安装了lxml,而另一个环境中只有html5lib, `解析器之间的区别`_ 中说明了原因.修复方法是在 ``BeautifulSoup`` 的构造方法中中指定解析器3318* 如果同样的代码在不同环境下结果不同,可能是因为两个环境下使用不同的解析器造成的。
3319 例如这个环境中安装了 lxml,而另一个环境中只有 html5lib, `解析器之间的区别`_ 中说明了原因。
3320 修复方法是在 ``BeautifulSoup`` 的构造方法中中指定解析器。
25103321
2511* 因为HTML标签是 `大小写敏感 <http://www.w3.org/TR/html5/syntax.html#syntax>`_ 的,所以3种解析器再出来文档时都将tag和属性转换成小写.例如文档中的 <TAG></TAG> 会被转换为 <tag></tag> .如果想要保留tag的大写的话,那么应该将文档 `解析成XML`_ .3322* 因为HTML标签是 `大小写敏感 <http://www.w3.org/TR/html5/syntax.html#syntax>`_ 的,
3323 所以解析器会将 tag 和属性都转换成小写。例如文档中的 <TAG></TAG> 会被转换为 <tag></tag> 。
3324 如果想要保留 tag 的大写的话,那么应该将文档 `解析成XML`_ 。
25123325
2513杂项错误3326杂项错误
2514--------3327--------
25153328
2516* ``UnicodeEncodeError: 'charmap' codec can't encode character u'\xfoo' in position bar`` (或其它类型的 ``UnicodeEncodeError`` )的错误,主要是两方面的错误(都不是Beautiful Soup的原因),第一种是正在使用的终端(console)无法显示部分Unicode,参考 `Python wiki <http://wiki.Python.org/moin/PrintFails>`_ ,第二种是向文件写入时,被写入文件不支持部分Unicode,这时只要用 ``u.encode("utf8")`` 方法将编码转换为UTF-8.3329* ``UnicodeEncodeError: 'charmap' codec can't encode character
3330 '\xfoo' in position bar`` (或其它类型的 ``UnicodeEncodeError`` )的错误,
3331 主要是两方面的原因,第一种是正在使用的终端(console)无法显示部分Unicode,参考
3332 `Python wiki <http://wiki.Python.org/moin/PrintFails>`_ ,第二种是向文件
3333 写入时,被写入文件不支持部分 Unicode,这时需要用 ``u.encode("utf8")`` 方法将
3334 编码转换为UTF-8。
3335
3336* ``KeyError: [attr]`` 因为调用 ``tag['attr']`` 方法而引起,因为这个 tag 没有定义
3337 该属性。出错最多的是 ``KeyError: 'href'`` 和 ``KeyError: 'class'`` 。如果不确定
3338 某个属性是否存在时,用 ``tag.get('attr')`` 方法去获取它,跟获取 Python 字典的 key 一样。
25173339
2518* ``KeyError: [attr]`` 因为调用 ``tag['attr']`` 方法而引起,因为这个tag没有定义该属性.出错最多的是 ``KeyError: 'href'`` 和 ``KeyError: 'class'`` .如果不确定某个属性是否存在时,用 ``tag.get('attr')`` 方法去获取它,跟获取Python字典的key一样3340* ``AttributeError: 'ResultSet' object has no attribute 'foo'`` 错误通常是
3341 因为把 ``find_all()`` 的返回结果当作一个 tag 或文本节点使用,实际上返回结果是一个
3342 列表或 ``ResultSet`` 对象的字符串,需要对结果进行循环才能得到每个节点的 ``.foo``
3343 属性。 或者使用 ``find()`` 方法仅获取到一个节点。
25193344
2520* ``AttributeError: 'ResultSet' object has no attribute 'foo'`` 错误通常是因为把 ``find_all()`` 的返回结果当作一个tag或文本节点使用,实际上返回结果是一个列表或 ``ResultSet`` 对象的字符串,需要对结果进行循环才能得到每个节点的 ``.foo`` 属性.或者使用 ``find()`` 方法仅获取到一个节点3345* ``AttributeError: 'NoneType' object has no attribute 'foo'`` 这个错误通常是
3346 在调用了 ``find()`` 方法后直节点取某个属性 foo。但是 ``find()`` 方法并没有找到任何
3347 结果,所以它的返回值是 ``None`` 。需要找出为什么 ``find()`` 的返回值是 ``None``。
25213348
2522* ``AttributeError: 'NoneType' object has no attribute 'foo'`` 这个错误通常是在调用了 ``find()`` 方法后直节点取某个属性 .foo 但是 ``find()`` 方法并没有找到任何结果,所以它的返回值是 ``None`` .需要找出为什么 ``find()`` 的返回值是 ``None`` .3349* ``AttributeError: 'NavigableString' object has no attribute 'foo'`` 这种问题
3350 通常是因为吧一个字符串当做一个 tag 来处理。可能在迭代一个列表时,期望其中都是 tag,但实际上
3351 列表里既包含 tag 也包含字符串。
25233352
2524如何提高效率3353如何提高效率
2525------------3354------------
25263355
2527Beautiful Soup对文档的解析速度不会比它所依赖的解析器更快,如果对计算时间要求很高或者计算机的时间比程序员的时间更值钱,那么就应该直接使用 `lxml <http://lxml.de/>`_ .3356Beautiful Soup对文档的解析速度不会比它所依赖的解析器更快,如果对计算时间要求很高或者
3357计算机的时间比程序员的时间更值钱,那么就应该直接使用 `lxml <http://lxml.de/>`_ 。
3358
3359换句话说,还有提高 Beautiful Soup 效率的办法,使用lxml作为解析器。Beautiful Soup
3360用 lxml 做解析器比用 html5lib 或 Python 内置解析器速度快很多。
3361
3362安装 `cchardet <http://pypi.Python.org/pypi/cchardet/>`_ 后文档的解码的编码检测
3363速度会更快。
3364
3365`解析部分文档`_ 不会节省多少解析时间,但是会节省很多内存,并且搜索时也会变得更快。
3366
3367翻译这篇文档
3368=============
3369
3370非常感谢欢迎翻译 Beautiful Soup 的文档。翻译内容应当基于 MIT 协议,就像 Beautiful Soup 和
3371英文文档一样。
25283372
2529换句话说,还有提高Beautiful Soup效率的办法,使用lxml作为解析器.Beautiful Soup用lxml做解析器比用html5lib或Python内置解析器速度快很多.3373有两种方式将翻译内容添加到 Beautiful Soup 的网站上:
25303374
2531安装 `cchardet <http://pypi.Python.org/pypi/cchardet/>`_ 后文档的解码的编码检测会速度更快33751. 在 Beautiful Soup 代码库上创建一个分支,添加翻译,然后合并到主分支。就像修改源代码一样。
25323376
2533`解析部分文档`_ 不会节省多少解析时间,但是会节省很多内存,并且搜索时也会变得更快.33772. 向 Beautiful Soup 讨论组里发送一个消息,带上翻译的链接,或翻译内容的附件。
3378
3379使用中文或葡萄牙语的翻译作为模型。尤其注意,请翻译源文件 ``doc/source/index.rst``,
3380而不是 HTML 版本的文档。这样才能将文档发布为多种格式,而不局限于 HTML。
25343381
2535Beautiful Soup 33382Beautiful Soup 3
2536=================3383=================
25373384
2538Beautiful Soup 3是上一个发布版本,目前已经停止维护.Beautiful Soup 3库目前已经被几个主要的linux平台添加到源里:3385Beautiful Soup 3 是上一个发布版本,目前已经停止维护。Beautiful Soup 3 库目前已经被
3386几个主要的 linux 发行版添加到源里:
25393387
2540``$ apt-get install Python-beautifulsoup``3388``$ apt-get install Python-beautifulsoup``
25413389
2542在PyPi中分发的包名字是 ``BeautifulSoup`` :3390在 PyPi 中分发的包名字是 ``BeautifulSoup`` :
25433391
2544``$ easy_install BeautifulSoup``3392``$ easy_install BeautifulSoup``
25453393
2546``$ pip install BeautifulSoup``3394``$ pip install BeautifulSoup``
25473395
2548或通过 `Beautiful Soup 3.2.0源码包 <http://www.crummy.com/software/BeautifulSoup/bs3/download/3.x/BeautifulSoup-3.2.0.tar.gz>`_ 安装3396或通过 `Beautiful Soup 3.2.0源码包
3397<http://www.crummy.com/software/BeautifulSoup/bs3/download/3.x/BeautifulSoup-3.2.0.tar.gz>`_ 安装。
3398
3399如果是通过 ``easy_install beautifulsoup`` 或 ``easy_install
3400BeautifulSoup`` 安装,然后代码无法运行,那么可能是安装了错误的 Beautiful Soup 3 版本。
3401应该这样安装 ``easy_install beautifulsoup4``。
25493402
2550Beautiful Soup 3的在线文档查看 `这里 <http://www.crummy.com/software/BeautifulSoup/bs3/documentation.html>`_ .3403Beautiful Soup 3 的在线文档查看 `这里 <http://www.crummy.com/software/BeautifulSoup/bs3/documentation.html>`_ .
25513404
2552迁移到BS43405迁移到 BS4
2553----------3406----------
25543407
2555只要一个小变动就能让大部分的Beautiful Soup 3代码使用Beautiful Soup 4的库和方法----修改 ``BeautifulSoup`` 对象的引入方式:3408大部分使用 Beautiful Soup 3 编写的代码都可以在 Beautiful Soup 4 上运行,
3409只有一个小变动。只要把引用包的名字从 :py:class:`BeautifulSoup` 改为 ``bs4``,比如:
25563410
2557::3411::
25583412
@@ -2564,23 +3418,31 @@ Beautiful Soup 3的在线文档查看 `这里 <http://www.crummy.com/software/Be
25643418
2565 from bs4 import BeautifulSoup3419 from bs4 import BeautifulSoup
25663420
2567* 如果代码抛出 ``ImportError`` 异常“No module named BeautifulSoup”,原因可能是尝试执行Beautiful Soup 3,但环境中只安装了Beautiful Soup 4库3421* 如果代码抛出 ``ImportError`` 异常 "No module named BeautifulSoup",
3422 原因可能是尝试执行 Beautiful Soup 3,但环境中只安装了 Beautiful Soup 4。
25683423
2569* 如果代码跑出 ``ImportError`` 异常“No module named bs4”,原因可能是尝试运行Beautiful Soup 4的代码,但环境中只安装了Beautiful Soup 3.3424* 如果代码抛出 ``ImportError`` 异常 "No module named bs4",原因可能是尝试
3425 运行 Beautiful Soup 4 的代码,但环境中只安装了Beautiful Soup 3。
25703426
2571虽然BS4兼容绝大部分BS3的功能,但BS3中的大部分方法已经不推荐使用了,就方法按照 `PEP8标准 <http://www.Python.org/dev/peps/pep-0008/>`_ 重新定义了方法名.很多方法都重新定义了方法名,但只有少数几个方法没有向下兼容.3427尽管 BS4 兼容绝大部分 BS3 的功能,但 BS3 中的大部分方法已经不推荐使用了,旧方法标记废弃,
3428并按照 `PEP8标准 <http://www.Python.org/dev/peps/pep-0008/>`_ 重新命名了新方法。
3429虽然有大量的重命名和修改,但只有少数几个方法没有向下兼容。
25723430
2573上述内容就是BS3迁移到BS4的注意事项3431下面内容就是 BS3 迁移到 BS4 的注意事项:
25743432
2575需要的解析器3433解析器的变化
2576............3434^^^^^^^^^^^^^^^
25773435
2578Beautiful Soup 3曾使用Python的 ``SGMLParser`` 解析器,这个模块在Python3中已经被移除了.Beautiful Soup 4默认使用系统的 ``html.parser`` ,也可以使用lxml或html5lib扩展库代替.查看 `安装解析器`_ 章节3436Beautiful Soup 3 曾使用 Python 的 ``SGMLParser`` 解析器,这个模块在 Python3
3437中已经被移除了。Beautiful Soup 4 默认使用系统的 ``html.parser`` , 也可以使用
3438lxml 或 html5lib 扩展库代替。查看 `安装解析器`_ 章节。
25793439
2580因为解析器 ``html.parser`` 与 ``SGMLParser`` 不同. BS4 和 BS3 处理相同的文档会产生不同的对象结构. 使用lxml或html5lib解析文档的时候, 如果添加了 ``html.parser`` 参数, 解析的对象又回发生变化. 如果发生了这种情况, 只能修改对应的处文档结果处理代码了.3440因为解析器 ``html.parser`` 与 ``SGMLParser`` 不同。BS4 和 BS3 处理相同的文档会
3441产生不同的对象结构。使用 lxml 或 html5lib 解析文档的时候,如果添加了 ``html.parser``
3442参数,解析的对象又会发生变化。如果发生了这种情况,只能修改对应的文档处理代码了。
25813443
2582方法名的变化3444方法名的变化
2583............3445^^^^^^^^^^^^^^
25843446
2585* ``renderContents`` -> ``encode_contents``3447* ``renderContents`` -> ``encode_contents``
25863448
@@ -2614,32 +3476,33 @@ Beautiful Soup 3曾使用Python的 ``SGMLParser`` 解析器,这个模块在Pytho
26143476
2615* ``previousSibling`` -> ``previous_sibling``3477* ``previousSibling`` -> ``previous_sibling``
26163478
2617Beautiful Soup构造方法的参数部分也有名字变化:3479Beautiful Soup 构造方法的参数部分也有名字变化:
26183480
2619* ``BeautifulSoup(parseOnlyThese=...)`` -> ``BeautifulSoup(parse_only=...)``3481* ``BeautifulSoup(parseOnlyThese=...)`` -> ``BeautifulSoup(parse_only=...)``
26203482
2621* ``BeautifulSoup(fromEncoding=...)`` -> ``BeautifulSoup(from_encoding=...)``3483* ``BeautifulSoup(fromEncoding=...)`` -> ``BeautifulSoup(from_encoding=...)``
26223484
2623为了适配Python3,修改了一个方法名:3485为了适配 Python3,修改了一个方法名:
26243486
2625* ``Tag.has_key()`` -> ``Tag.has_attr()``3487* ``Tag.has_key()`` -> ``Tag.has_attr()``
26263488
2627修改了一个属性名,让它看起来更专业点:3489修改了一个属性名,让它看起来更专业点:
26283490
2629* ``Tag.isSelfClosing`` -> ``Tag.is_empty_element``3491* ``Tag.isSelfClosing`` -> ``Tag.is_empty_element``
26303492
2631修改了下面3个属性的名字,以免雨Python保留字冲突.这些变动不是向下兼容的,如果在BS3中使用了这些属性,那么在BS4中这些代码无法执行.3493修改了下面 3 个属性的名字,以免与 Python 保留字冲突。这些变动不是向下兼容的,如果在 BS3
3494中使用了这些属性,那么在 BS4 中这些代码无法执行。
26323495
2633* UnicodeDammit.Unicode -> UnicodeDammit.Unicode_markup``3496* ``UnicodeDammit.Unicode -> UnicodeDammit.Unicode_markup``
26343497
2635* ``Tag.next`` -> ``Tag.next_element``3498* ``Tag.next`` -> ``Tag.next_element``
26363499
2637* ``Tag.previous`` -> ``Tag.previous_element``3500* ``Tag.previous`` -> ``Tag.previous_element``
26383501
2639生成器3502生成器
2640.......3503^^^^^^^
26413504
2642将下列生成器按照PEP8标准重新命名,并转换成对象的属性:3505将下列生成器按照 PEP8 标准重新命名,并转换成对象的属性:
26433506
2644* ``childGenerator()`` -> ``children``3507* ``childGenerator()`` -> ``children``
26453508
@@ -2655,7 +3518,7 @@ Beautiful Soup构造方法的参数部分也有名字变化:
26553518
2656* ``parentGenerator()`` -> ``parents``3519* ``parentGenerator()`` -> ``parents``
26573520
2658所以迁移到BS4版本时要替换这些代码:3521所以要把这样的代码:
26593522
2660::3523::
26613524
@@ -2669,74 +3532,74 @@ Beautiful Soup构造方法的参数部分也有名字变化:
2669 for parent in tag.parents:3532 for parent in tag.parents:
2670 ...3533 ...
26713534
2672(两种调用方法现在都能使用)3535(其实老方法也可以继续使用)
26733536
2674BS3中有的生成器循环结束后会返回 ``None`` 然后结束.这是个bug.新版生成器不再返回 ``None`` .3537有的生成器循环结束后会返回 ``None`` 然后结束。这是个 bug。新版生成器不再返回 ``None`` 。
26753538
2676BS4中增加了2个新的生成器, `.strings 和 stripped_strings`_ . ``.strings`` 生成器返回NavigableString对象, ``.stripped_strings`` 方法返回去除前后空白的Python的string对象.3539BS4 中增加了 2 个新的生成器, `.strings 和 stripped_strings`_ 。 ``.strings`` 生成器
3540返回 NavigableString 对象, ``.stripped_strings`` 方法返回去除前后空白的 Python 的
3541string 对象。
26773542
2678XML3543XML
2679....3544^^^^^
26803545
2681BS4中移除了解析XML的 ``BeautifulStoneSoup`` 类.如果要解析一段XML文档,使用 ``BeautifulSoup`` 构造方法并在第二个参数设置为“xml”.同时 ``BeautifulSoup`` 构造方法也不再识别 ``isHTML`` 参数.3546BS4 中移除了解析 XML 的 ``BeautifulStoneSoup`` 类。如果要解析一段 XML 文档,使用
3547``BeautifulSoup`` 构造方法并在第二个参数设置为“xml”。同时 ``BeautifulSoup`` 构造
3548方法也不再识别 ``isHTML`` 参数。
26823549
2683Beautiful Soup处理XML空标签的方法升级了.旧版本中解析XML时必须指明哪个标签是空标签. 构造方法的 ``selfClosingTags`` 参数已经不再使用.新版Beautiful Soup将所有空标签解析为空元素,如果向空元素中添加子节点,那么这个元素就不再是空元素了.3550Beautiful Soup 处理 XML 空标签的方法升级了。旧版本中解析 XML 时必须指明哪个标签是空标签。
3551构造方法的 ``selfClosingTags`` 参数已经不再使用。新版 Beautiful Soup 将所有空标签解析
3552为空元素,如果向空元素中添加子节点,那么这个元素就不再是空元素了。
26843553
2685实体3554实体
2686.....3555^^^^^
26873556
2688HTML或XML实体都会被解析成Unicode字符,Beautiful Soup 3版本中有很多处理实体的方法,在新版中都被移除了. ``BeautifulSoup`` 构造方法也不再接受 ``smartQuotesTo`` 或 ``convertEntities`` 参数. `编码自动检测`_ 方法依然有 ``smart_quotes_to`` 参数,但是默认会将引号转换成Unicode.内容配置项 ``HTML_ENTITIES`` , ``XML_ENTITIES`` 和 ``XHTML_ENTITIES`` 在新版中被移除.因为它们代表的特性已经不再被支持.3557输入的 HTML 或 XML 实体都会被解析成 Unicode 字符。Beautiful Soup 3 版本中有很多相似处理
3558实体的方法,在新版中都被移除了。 ``BeautifulSoup`` 构造方法也不再接受 ``smartQuotesTo``
3559或 ``convertEntities`` 参数。 `编码自动检测 <Unicode, Dammit>`_ 方法依然有 ``smart_quotes_to``
3560参数,但是默认会将引号转换成 Unicode。内容配置项 ``HTML_ENTITIES`` , ``XML_ENTITIES`` 和
3561``XHTML_ENTITIES`` 在新版中被移除。因为它们代表的特性(转换部分而不是全部实体到 Unicode 字符)
3562已经不再支持。
26893563
2690如果在输出文档时想把Unicode字符转换成HTML实体,而不是输出成UTF-8编码,那就需要用到 `输出格式`_ 的方法.3564如果在输出文档时想把 Unicode 字符转回 HTML 实体,而不是输出成 UTF-8 编码,那就需要用到
3565`输出格式`_ 的方法。
26913566
2692迁移杂项3567迁移杂项
2693.........3568^^^^^^^^^
3569
3570`Tag.string <string>`_ 属性现在是一个递归操作。如果 A 标签只包含了一个 B 标签,那么 A 标签的。
3571string 属性值与 B 标签的 string 属性值相同。
26943572
2695`Tag.string`_ 属性现在是一个递归操作.如果A标签只包含了一个B标签,那么A标签的.string属性值与B标签的.string属性值相同.3573`多值属性`_ 比如 ``class`` 属性包含一个他们的值的列表,而不是一个字符串。这可能会影响到如何按照
3574CSS 类名哦搜索 tag。
26963575
2697`多值属性`_ 比如 ``class`` 属性包含一个他们的值的列表,而不是一个字符串.这可能会影响到如何按照CSS类名哦搜索tag.3576Tag 对象实现了一个 ``__hash__`` 方法,这样当两个 Tag 对象生成相同的摘要时会被认为相等。这可能会
3577改变你的脚本行为,如果你吧 Tag 对象放到字典或集合中。
26983578
2699如果使用 ``find*`` 方法时同时传入了 `string 参数`_ 和 `name 参数`_ .Beautiful Soup会搜索指定name的tag,并且这个tag的 `Tag.string`_ 属性包含text参数的内容.结果中不会包含字符串本身.旧版本中Beautiful Soup会忽略掉tag参数,只搜索text参数.3579如果使用 ``find*`` 方法时同时传入了 `string 参数`_ 和一个指定 tag 的参数比如 `name 参数`_ 。
3580Beautiful Soup 会搜索符合指定参数的 tag,并且这个 tag 的 `Tag.string <string>`_ 属性包含
3581`string 参数`_ 参数的内容。结果中 `不会` 包含字符串本身。旧版本中 Beautiful Soup 会忽略掉指定
3582tag 的参数,只搜索符合 string 的内容。
27003583
2701``BeautifulSoup`` 构造方法不再支持 markupMassage 参数.现在由解析器负责文档的解析正确性.3584``BeautifulSoup`` 构造方法不再支持 markupMassage 参数。现在由解析器负责文档的解析正确性。
27023585
2703很少被用到的几个解析器方法在新版中被移除,比如 ``ICantBelieveItsBeautifulSoup`` 和 ``BeautifulSOAP`` .现在由解析器完全负责如何解释模糊不清的文档标记.3586很少被用到的几个解析器方法在新版中被移除,比如 ``ICantBelieveItsBeautifulSoup`` 和 ``BeautifulSOAP`` 。
3587现在由解析器完全负责如何解释模糊不清的文档标记。
27043588
2705``prettify()`` 方法在新版中返回Unicode字符串,不再返回字节流.3589``prettify()`` 方法在新版中返回 Unicode 字符串,不再返回字节串。
27063590
2707附录3591附录
2708=====3592=====
27093593
2710.. _`BeautifulSoup3 文档`: http://www.crummy.com/software/BeautifulSoup/bs3/documentation.zh.html3594.. [1] BeautifulSoup 的 google 讨论组不是很活跃,可能是因为库已经比较完善了吧,但是作者还是会很热心的尽量帮你解决问题的。
2711.. _name: `name 参数`_3595.. [2] 文档被解析成树形结构,所以下一步解析过程应该是当前节点的子节点
2712.. _attrs: `按CSS搜索`_3596.. [3] 过滤器只能作为搜索文档的参数,或者说应该叫参数类型更为贴切,原文中用了 ``filter`` 因此翻译为过滤器
2713.. _recursive: `recursive 参数`_3597.. [4] 元素参数,HTML 文档中的一个 tag 节点,不能是文本节点
2714.. _string: `string 参数`_
2715.. _**kwargs: `keyword 参数`_
2716.. _.next_siblings: `.next_siblings 和 .previous_siblings`_
2717.. _.previous_siblings: `.next_siblings 和 .previous_siblings`_
2718.. _.next_elements: `.next_elements 和 .previous_elements`_
2719.. _.previous_elements: `.next_elements 和 .previous_elements`_
2720.. _.stripped_strings: `.strings 和 stripped_strings`_
2721.. _安装lxml: `安装解析器`_
2722.. _安装lxml或html5lib: `安装解析器`_
2723.. _编码自动检测: `Unicode, Dammit! (乱码, 靠!)`_
2724.. _Tag.string: `.string`_
2725
2726
2727.. [1] BeautifulSoup的google讨论组不是很活跃,可能是因为库已经比较完善了吧,但是作者还是会很热心的尽量帮你解决问题的.
2728.. [2] 文档被解析成树形结构,所以下一步解析过程应该是当前节点的子节点
2729.. [3] 过滤器只能作为搜索文档的参数,或者说应该叫参数类型更为贴切,原文中用了 ``filter`` 因此翻译为过滤器
2730.. [4] 元素参数,HTML文档中的一个tag节点,不能是文本节点
2731.. [5] 采用先序遍历方式3598.. [5] 采用先序遍历方式
2732.. [6] CSS选择器是一种单独的文档搜索语法, 参考 http://www.w3school.com.cn/css/css_selector_type.asp3599.. [6] CSS选择器是一种单独的文档搜索语法,参考 http://www.w3school.com.cn/css/css_selector_type.asp
2733.. [7] 原文写的是 html5lib, 译者觉得这是原文档的一个笔误3600.. [7] 原文写的是 html5lib, 译者觉得这是原文档的一个笔误
2734.. [8] wrap含有包装,打包的意思,但是这里的包装不是在外部包装而是将当前tag的内部内容包装在一个tag里.包装原来内容的新tag依然在执行 `wrap()`_ 方法的tag内3601.. [8] wrap含有包装,打包的意思,但是这里的包装不是在外部包装而是将当前tag的内部内容包装在一个tag里。
2735.. [9] 文档中特殊编码字符被替换成特殊字符(通常是�)的过程是Beautful Soup自动实现的,如果想要多种编码格式的文档被完全转换正确,那么,只好,预先手动处理,统一编码格式3602 包装原来内容的新tag依然在执行 `wrap()`_ 方法的tag内
2736.. [10] 智能引号,常出现在microsoft的word软件中,即在某一段落中按引号出现的顺序每个引号都被自动转换为左引号,或右引号.3603.. [9] 文档中特殊编码字符被替换成特殊字符(通常是�)的过程是Beautful Soup自动实现的,
27373604 如果想要多种编码格式的文档被完全转换正确,那么,只好,预先手动处理,统一编码格式
2738原文: http://www.crummy.com/software/BeautifulSoup/bs4/doc/3605.. [10] 智能引号,常出现在 microsoft 的 word 软件中,即在某一段落中按引号出现的顺序每个引号都被自动转换为左引号,或右引号。
2739
2740翻译: Deron Wang
2741
2742查看 `BeautifulSoup3 文档`_

Subscribers

People subscribed via source and target branches