python beautifulsoup python beautifulsoup4( 二 )


首先声明一个html变量,它是一个HTML字符串,注意html和body标签都没有闭合 。
经过初始化,使用prettify()方法把要解析的字符串以标准缩进格式输出,发现结果中自动补全了html和body标签 。这一步不是prettify()方法做的,而是在初始化BeautifulSoup时就完成了 。然后调用soup.title.string拿到title里面的文本内容 。
通过简单调用几个属性完成文本提取,是不是非常方便呢?
节点选择器
直接调用节点的名称就可以选择节点元素,再调用 string 属性就可以得到节点内的文本了,这种选择方式速度非常快 。如果单个节点结构层次非常清晰,可以选用这种方式来解析 。
选择元素
还是以上面的HTML代码为例,详细说明选择元素的方法:
from bs4 import BeautifulSoupsoup = BeautifulSoup(html, 'lxml')print(soup.title)print(type(soup.title))print(soup.title.string)print(soup.head)print(soup.p)'''<title>The Dormouse's story</title><class 'bs4.element.Tag'>The Dormouse's story<head><title>The Dormouse's story</title></head><p class="title" name="dromouse"><b>The Dormouse's story</b></p>'''
首先输出title节点的选择结果,包含标签 。
接下来输出它的类型,是一个bs4.element.Tag类型,Tag具有一些属性,比如string 。
调用string属性可以看到输出节点的文本内容 。
继续尝试head、p节点 。发现p只取了第一个匹配的节点 。说明当有多个节点时只取一个 。
获取属性
每个节点可能有多个属性比如id 、class等,选择元素后可以调用attrs获取所有属性:
print(soup.p.attrs)print(soup.p.attrs['name'])'''{'class': ['title'], 'name': 'dromouse'}dromouse'''
可以看到attrs返回结果是字典,它把选择节点所有属性都组合成一个字典 。取值直接按字典方式即可 。
当然还有一种更简单的获取方式:不写attrs,直接在元素后面中括号取值也行:
print(soup.p['name'])print(soup.p['class'])'''dromouse['title']'''
但是注意区分:有的返回字符串、有的返回字符串组成的列表 。
对于class,一个节点元素可能有多个class,所以返回的是列表 。
子节点和子孙节点
选取节点元素之后,如果想要获取它的直接子节点,可以调用 contents 属性,示例如下:
html4 = """<html><head><title>The Dormouse's story</title></head><body><p class="story">钢铁知识库<a href="http://a.com" class="钢铁学数据分析" id="link1"><span>Elsie</span></a><a href="http://b.com" class="钢铁学自动化" id="link2">Lacie</a>and<a href="http://example.com" class="cccc" id="link3">Tillie</a>钢铁学爬虫.</p><p class="story">...</p>"""from bs4 import BeautifulSoupsoup = BeautifulSoup(html4, 'lxml')print(soup.p.contents)'''['\n钢铁知识库\n', <a class="钢铁学数据分析" href="http://a.com" id="link1"><span>Elsie</span></a>, '\n', <a class="钢铁学自动化" href="http://b.com" id="link2">Lacie</a>, ' \nand\n', <a class="cccc" href="http://example.com" id="link3">Tillie</a>, '\n钢铁学爬虫.\n']'''
可以看到返回结果是列表形式 。p 节点里既包含文本,又包含文本,最后统一返回列表 。
需要注意,列表中的每个元素都是 p 节点的直接子节点 。比如第一个 a 节点里面的span节点,这相当于子孙节点了,但返回结果并没有单独把span节点列出来 。所以说,contents属性得到的结果是直接子节点的列表 。
同样,我们可以调用children属性得到相应的结果:
from bs4 import BeautifulSoupsoup = BeautifulSoup(html, 'lxml')print(soup.p.children)for i, child in enumerate(soup.p.children):print(i, child)'''<list_iterator object at 0x0000000001D9A1C0>0钢铁知识库1 <a class="钢铁学数据分析" href="http://a.com" id="link1"><span>Elsie</span></a>2 3 <a class="钢铁学自动化" href="http://b.com" id="link2">Lacie</a>4and5 <a class="cccc" href="http://example.com" id="link3">Tillie</a>6钢铁学爬虫.'''
还是同样的 HTML 文本,这里调用了 children 属性来选择,返回结果是生成器类型 。接下来,我们用 for 循环输出相应的内容 。
如果要得到所有的子孙节点的话,可以调用 descendants 属性:


推荐阅读