BeautifulSoup4基础

对象的种类
BeautifulSoup会将HTML文档抓换成一个树形结构, 每个节点都是Python对象,所有对象可以分为4类:Tag,NavigableString,BeautifulSoup,Comment。

Tag

Tag与XML或HTML中的tag相同:

soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
tag = soup.b
print(type(tag))
print(tag)

--<class 'bs4.element.Tag'>
--<b class="boldest">Extremely bold</b>
name

每一个Tag都有自己的name,可以通过.name。改变tag的name,将会影响通过当前BS对象生成的HTML文档

soup = BeautifulSoup('<b class="boldest">Extremely bold</b>',"html.parser")
tag = soup.b
print(tag)
print(tag.name)
tag.name="blockquote"
print(tag)

---<b class="boldest">Extremely bold</b>
---b
---<blockquote class="boldest">Extremely bold</blockquote>
attributes

一个tag可能有多个属性

soup = BeautifulSoup('<b class="boldest">Extremely bold</b>',"html.parser")
tag = soup.b
print(tag['class'])
print(tag.attrs)

---['boldest']
---{'class': ['boldest']}
tag的属性可以被添加,删除或修改

soup = BeautifulSoup('<b class="boldest">Extremely bold</b>',"html.parser")
tag = soup.b

更改属性

tag['class']="verybold"
tag['id']=1
print(tag)

删除属性

del tag['class']
print(tag)
print(tag.get('class'))

---<b class="verybold" id="1">Extremely bold</b>
---<b id="1">Extremely bold</b>


多值属性

多值属性即为可包含多个值的属性,最常见的即为class
xml中没有多值属性

多值属性的返回类型是list

css_soup = BeautifulSoup('<p class="body strikeout"></p>',"html.parser")
print(css_soup.p['class'])

---['body', 'strikeout']
若某个属性看起来像多值属性,但是在任何版本HTML中都没有被定义为多值属性,那么BS会将这个属性作为字符串返回

id_soup = BeautifulSoup('<p id="my id"></p>',"html.parser")
print(id_soup.p['id'])

---my id
NavigableString

NavigableString不支持.content,.string,find()方法。

如果想在Beautiful Soup之外使用NavigableString对象,需要调用unicode()方法,将该对象转换成普通的Unicode字符串,否则就算Beautiful Soup已方法已经执行结束,该对象的输出也会带有对象的引用地址.这样会浪费内存.

soup = BeautifulSoup('<b class="boldest">Extremely bold</b>',"html.parser")
tag = soup.b
print(tag.string)
print(type(tag.string))
tag.string.replace_with("No long bold")
print(tag)

---Extremely bold
---<class 'bs4.element.NavigableString'>
---<b class="boldest">No long bold</b>
BeautifulSoup
BeautifulSoup对象表示的是一个文档的全部内容.大部分时候,可以把它当作 Tag 对象,它支持 遍历文档树 和 搜索文档树 中描述的大部分的方法.

BeautifuSoup没有name和attribute属性。但有一个值为[document]的特殊属性.name

soup = BeautifulSoup('<b class="boldest">Extremely bold</b>',"html.parser")
print(soup.name)

---[document]
Comment

遍历文档树
html_doc = """
<html><head><title>The Dormouse's story</title></head>

<p class="title"><b>The Dormouse's story</b></p>

<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>

<p class="story">...</p>
"""
.content和.children

tag的.contents属性可以将tag的子节点以列表的方式输出:
通过tag的.children生成器,可以对tag的子节点进行循环:

print(soup.title.contents)
print(soup.title.contents[0])

---["The Dormouse's story"]
---The Dormouse's story
for i in soup.head.children:
print(i)

---<title>The Dormouse's story</title>
.descendants

.descendants属性可以对所有tag的子孙节点进行递归循环

print(soup.head.contents)
for child in soup.head.descendants:
print(child)

print(len(list(soup.children)))
print(len(list(soup.descendants)))

---[<title>The Dormouse's story</title>]
---<title>The Dormouse's story</title>
---The Dormouse's story
---2
---25
.string

如果tag只有一个NavigableString类型子节点,那么这个tag可以使用.string得到子节点

print(soup.head.string)

---The Dormouse's story
.strings和stripped_strings

如果tag中有多个字符串,可以使用.strings循环获取
使用.stripped_strings可以去除多余空白内容:

for string in soup.stripped_strings:
print(repr(string))
.parent和.parents

通过.parent属性来获取某个元素的父节点
通过元素的.parents属性可以递归得到元素的所有父辈节点。

for parent in soup.a.parents:
if parent is None:
print(parent)
else:
print(parent.name)

---p
---html
---[document]
兄弟节点

.next_sibling和.previous_sibling

使用。next_sibling和.previous_sibling属性来查询兄弟节点

实际文档中的tag的 .next_sibling 和 .previous_sibling 属性通常是字符串或空白。因为中间可能会隔着一些字符以及标点。

.next_siblings和.previous_siblings

for sibling in soup.a.next_siblings:
print(repr(sibling))

---',\n'
---<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
---' and\n'
---<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
';\nand they lived at the bottom of a well.'
重现解析过程

.next_element和.previous_element

next_element属性指向解析过程中下一个被解析的对象(字符串或tag),结果可能与.next_sibling相同,但通常是不一样的.

last_a_tag=soup.find("a",id="link3")
print(last_a_tag)
print(last_a_tag.next_sibling)
print(last_a_tag.next_element)

---<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
---;
---and they lived at the bottom of a well.
---Tillie
.next_elements和.previous_elements

搜索文档树
过滤器

字符串

正则表达式

for tag in soup.find_all(re.compile("^b")):
print(tag.name)
列表

如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回.

True

True可以匹配任何值,但是不会返回字符串节点

方法

如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数,如果这个方法返回True表示当前元素匹配并且被找到,如果不是则反回False。

def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id')
find_all()

name参数

keyword参数

soup.find_all(id='link2')

按CSS搜索

因为class是python保留字,所以用class_
例:
soup.find_all("a",class_="sister")

class_参数同样接受不同类型的过滤器 ,字符串,正则表达式,方法或 True :

tag的class属性是 多值属性 .按照CSS类名搜索tag时,可以分别搜索tag中的每个CSS类名:

text参数

通过text参数可以搜搜文档中的字符串内容.

limit参数

limit参数限制返回结果的数量

recursive参数

调用tag的find_all()方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False.

简写

soup.find_all("a")
soup("a")
soup.title.find_all(text=True)
soup.title(text=True)
find()

只返回一个结果

find_parents()和find_parent()

find_next_siblings()和find_next_sibling()`

find_all_next()和find_next()

find_all_previous()和find_previous()

CSS选择器

在Tag或BeautifulSoup对象的.select()方法中传入字符串参数,即可使用CSS选择器的语法找到tag:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容