開始
首先必須要導(dǎo)入 bs4 庫
from bs4 import BeautifulSoup
我自己常用的兩種解析器
soup = BeautifulSoup(markup, "html.parser")
soup = BeautifulSoup(markup, "lxml")
如果要使用lxml必須先安裝
pip install lxml
四大對象種類
- Tag
- NavigableString
- BeautifulSoup
- Comment
Tag
Tag就是HTML中的一個個標(biāo)簽, 例如
<title>The Dormouse's story</title>
<a class="sister" id="link1">Elsie</a>
驗證一下對象類型
print(type(soup.a))
#<class 'bs4.element.Tag'>
對于Tag, 有兩個重要的屬性, name和attrs
name
例如一個b標(biāo)簽, 那么它的name就是b, 一個p標(biāo)簽的name就是p
soup = BeautifulSoup('<b class="boldest">Extremely bold</b>', 'lxml')
tag = soup.b
print(tag.name)
#b
attrs
attrs是一個字典類型的, 對應(yīng)的是屬性-值, 如print soup.p.attrs,輸出的就是{'class': ['title'], 'name': 'dromouse'}, 當(dāng)然你也可以得到具體的值, 如print(soup.p.attrs['class']),輸出的就是[title]是一個列表的類型,因為一個屬性可能對應(yīng)多個值,當(dāng)然你也可以通過get方法得到屬性的, 如:print(soup.p.get('class')). 還可以直接使用print(soup.p['class'])
print(soup.p.attrs)
#{'class':['title'], 'name':'dromouse'}
get
get方法用于得到標(biāo)簽下的屬性值, 注意這是一個重要的方法, 在許多場合都能用到, 比如你要得到<img src="#">標(biāo)簽下的圖像url, 那么就可以用soup.img.get('src'), 具體解析如下:
print soup.p.get("src") #得到第一個p標(biāo)簽下的src屬性
單獨獲取某個屬性
print(soup.p['class']
#['title']
也可以像下面這樣
print(soup.p.get('class')
#['title']
或者下面那樣
print(soup.p.attrs['class']
#['title']
find_all()
find_all(name , attrs , recursive , text , **kwargs)
find_all() 方法搜索當(dāng)前tag的所有tag子節(jié)點, 并判斷是否符合過濾器的條件
注意:如果一個指定名字的參數(shù)不是搜索內(nèi)置的參數(shù)名, 搜索時會把該參數(shù)當(dāng)作指定名字tag的屬性來搜索, 如果包含一個名字為 id 的參數(shù),Beautiful Soup會搜索每個tag的”id”屬性
find_all() 的返回值是一個Tag組成的列表, 方法調(diào)用非常靈活, 所有的參數(shù)都是可選的, 這里有幾個例子:
soup.find_all("title")
# [<title>The Dormouse's story</title>]
soup.find_all("p", "title")
# [<p class="title"><b>The Dormouse's story</b></p>]
soup.find_all("a")
# [<a class="sister" id="link1">Elsie</a>,
# <a class="sister" id="link2">Lacie</a>,
# <a class="sister" id="link3">Tillie</a>]
soup.find_all(id="link2")
# [<a class="sister" id="link2">Lacie</a>]
import re
soup.find(text=re.compile("sisters"))
# u'Once upon a time there were three little sisters; and their names were\n'
name 參數(shù)
name 參數(shù)可以查找所有名字為 name 的tag,字符串對象會被自動忽略掉
soup.find_all("title")
# [<title>The Dormouse's story</title>]
傳字符串
soup.find_all('b')
# [<b>The Dormouse's story</b>]
print soup.find_all('a')
#[<a class="sister" id="link1"><!-- Elsie --></a>...]
傳正則表達(dá)式
如果傳入正則表達(dá)式作為參數(shù),Beautiful Soup會通過正則表達(dá)式的 match() 來匹配內(nèi)容.下面例子中找出所有以b開頭的標(biāo)簽,這表示<body>和<b>標(biāo)簽都應(yīng)該被找到:
for tag in soup.find_all(re.compile("^b")):
print(tag.name)
# body
# b
傳列表
如果傳入列表參數(shù),Beautiful Soup會將與列表中任一元素匹配的內(nèi)容返回.下面代碼找到文檔中所有<a>標(biāo)簽和<b>標(biāo)簽:
soup.find_all(["a", "b"])
attrs參數(shù)
find_all()中第二個參數(shù)是標(biāo)簽的class屬性值
soup.find_all("a", class_="sister")
等效于
soup.find_all("p", "sister") # p指定了tag的name, sister指定了所有tag的class屬性如果是'sister'就會被返回
keyword參數(shù)
如果一個指定名字的參數(shù)不是搜索內(nèi)置的參數(shù)名,搜索時會把該參數(shù)當(dāng)作指定名字tag的屬性來搜索,如果包含一個名字為 id 的參數(shù), Beautiful Soup會搜索每個tag的”id”屬性
soup.find_all(id='link2')
# [<a class="sister" id="link2">Lacie</a>]
soup.find_all(href=re.compile("elsie"))
# [<a class="sister" id="link1">Elsie</a>]
多個指定名字參數(shù)同時過濾tag的多個屬性
soup.find_all(href=re.compile("elsie"), id='link1')
# [<a class="sister" id="link1">three</a>]
定義一個字典來搜索包含特殊屬性的tag
soup.find_all(attrs={"data-foo": "value"})
# [<div data-foo="value">foo!</div>]
text參數(shù)
soup.find_all(text="Elsie")
# 'Elsie'
soup.find_all(text=["Tillie", "Elsie"])
['Elsie', 'Tillie']
soup.find_all(text=re.compile("Dormouse"))
['The Dormouse's story]
find()方法
find( name , attrs , recursive , text , **kwargs )
它與 find_all() 方法唯一的區(qū)別是 find_all() 方法的返回結(jié)果是值包含一個元素的列表,而 find() 方法直接返回結(jié)果
get_text()
如果只想得到tag中包含的文本內(nèi)容,那么可以使用 get_text() 方法, 這個方法獲取到tag中包含的所有文版內(nèi)容包括子孫tag中的內(nèi)容, 并將結(jié)果作為Unicode字符串返回:
markup = '<a >\nI linked to <i>example.com</i>\n</a>'
soup = BeautifulSoup(markup)
soup.get_text()
u'\nI linked to example.com\n'
soup.i.get_text()
u'example.com'
可以通過參數(shù)指定tag的文本內(nèi)容的分隔符:
# soup.get_text("|")
u'\nI linked to |example.com|\n'
還可以去除獲得文本內(nèi)容的前后空白:
# soup.get_text("|", strip=True)
u'I linked to|example.com'
或者使用 .stripped_strings 生成器,獲得文本列表后手動處理列表:
[text for text in soup.stripped_strings]
# [u'I linked to', u'example.com']
css選擇器
我們在寫 CSS 時,標(biāo)簽名不加任何修飾,類名前加點,id名前加#,在這里我們也可以利用類似的方法來篩選元素,用到的方法是 soup.select(),返回類型是 list
通過標(biāo)簽名查找
print soup.select('title')
#[<title>The Dormouse's story</title>]
print soup.select('a')
#[<a class="sister" id="link1"><!-- Elsie --></a>, <a class="sister" id="link2">Lacie</a>, <a class="sister" id="link3">Tillie</a>]
通過類名查找
print soup.select('.sister')
#[<a class="sister" id="link1"><!-- Elsie --></a>, <a class="sister" id="link2">Lacie</a>, <a class="sister" id="link3">Tillie</a>]
通過id名查找
print soup.select('#link1')
#[<a class="sister" id="link1"><!-- Elsie --></a>]
組合查找
學(xué)過css的都知道css選擇器,如p #link1是查找p標(biāo)簽下的id屬性為link1的標(biāo)簽
print soup.select('p #link1') #查找p標(biāo)簽中內(nèi)容為id屬性為link1的標(biāo)簽
#[<a class="sister" id="link1"><!-- Elsie --></a>]
print soup.select("head > title") #直接查找子標(biāo)簽
#[<title>The Dormouse's story</title>]
屬性查找
查找時還可以加入屬性元素,屬性需要用中括號括起來,注意屬性和標(biāo)簽屬于同一節(jié)點,所以中間不能加空格,否則會無法匹配到。
print soup.select('a[class="sister"]')
#[<a class="sister" id="link1"><!-- Elsie --></a>, <a class="sister" id="link2">Lacie</a>, <a class="sister" id="link3">Tillie</a>]
print soup.select('a[)
#[<a class="sister" id="link1"><!-- Elsie --></a>]
同樣,屬性仍然可以與上述查找方式組合,不在同一節(jié)點的空格隔開,同一節(jié)點的不加空格,代碼如下:
print soup.select('p a[)
#[<a class="sister" id="link1"><!-- Elsie --></a>]
以上的 select 方法返回的結(jié)果都是列表形式,可以遍歷形式輸出,然后用 get_text() 方法來獲取它的內(nèi)容
soup = BeautifulSoup(html, 'lxml')
print type(soup.select('title'))
print soup.select('title')[0].get_text()
for title in soup.select('title'):
print title.get_text()