搜索文檔樹(shù)里面主要講find()以及find_all()的用法喜庞。在講這兩個(gè)用法之前先來(lái)說(shuō)說(shuō)過(guò)濾器,什么過(guò)濾器呢棋返?顧名思義延都,過(guò)濾器就是按照條件過(guò)濾掉不符合的,留下符合的睛竣。那么在Python中這些條件可以是什么呢晰房?我們來(lái)依次介紹????
1.字符串(這個(gè)沒(méi)什么好講的)
2.正則表達(dá)式(不知道的可以百度一下什么意思)
3.列表:如果傳入列表參數(shù),Beautiful Soup會(huì)將與列表中任一元素匹配的內(nèi)容返回.
4.True:True可以匹配任何值
再來(lái)說(shuō)說(shuō)方法,什么時(shí)候用這個(gè)方法呢?當(dāng)你沒(méi)有合適的過(guò)濾器的時(shí)候殊者,那便可以定義一個(gè)方法与境,方法只接受一個(gè)元素,如果返回True那么表示當(dāng)前元素與之匹配并且被找到猖吴,反之將會(huì)返回false
你可以定義一個(gè)尋找包含class但是不包含id的標(biāo)簽
def has_class_but_no_id(tag):
? ? return tag.has_attr('class') and not tag.has_attr('id')
好了可以來(lái)講講find_all()和find()了
先來(lái)說(shuō)說(shuō).find_all()摔刁,它的具體使用規(guī)則如下
.find_all(tag,attributes,recursive,text,limit,keywords)
雖然這里有這么多個(gè)參數(shù)但是其實(shí)我們絕大多數(shù)時(shí)候只使用前兩個(gè)參數(shù)
那么我們一一介紹一下這些參數(shù)
tag:就是之前講的標(biāo)簽名(像<h1>什么之類(lèi)的),你可以傳入一個(gè)標(biāo)簽名或者多個(gè) 標(biāo)簽組成的列表
attributes:是一個(gè)用python字典封裝的一個(gè)標(biāo)簽的若干屬性以及其值海蔽,例如:.find_all("span",{"class":{"green","red"}})這就可以找出所有class為green和red的span標(biāo)簽
recursive:是一個(gè)遞歸參數(shù)共屈,他是一個(gè)布爾變量如果設(shè)為T(mén)rue那么會(huì)根據(jù)要求查找所有子標(biāo)簽以及子標(biāo)簽的子標(biāo)簽,如果設(shè)為False那么只會(huì)查找文檔的一級(jí)標(biāo)簽党窜。當(dāng)然他的默認(rèn)值是True拗引。一般我們也用不到去修改它。
text:他和attributes有點(diǎn)像但又很是不同幌衣,他是用標(biāo)簽里面的文本去匹配而不是標(biāo)簽的屬性
limit:只適用于find_all()方法矾削,你可以指定有多少項(xiàng)結(jié)果返回過(guò)來(lái),要注意的是豁护,設(shè)置了limit后返回的是按照順序返回的哼凯,不一定是你想要的結(jié)果。
keyword:可以讓你選擇那些具有指定屬性的標(biāo)簽择镇,例如:.find_all(id = "text")這個(gè)可以找出所有id=text的標(biāo)簽
但是要記住,不要濫用keyword括改,keyword只是BeautifulSoup中的一個(gè)冗余功能腻豌,雖然在有些場(chǎng)景下它顯得特別有用,但是任何能夠用keyword解決的問(wèn)題都可以用其他方式解決嘱能,
就上一個(gè)例子來(lái)說(shuō)
和.find_all("",{"id":"text"})是完全一樣的
接下來(lái)我們會(huì)來(lái)說(shuō)說(shuō)keyword的一些“缺點(diǎn)”
我們知道class是Python中的一個(gè)保留字,是不能當(dāng)做變量名來(lái)使用的。但是HTML標(biāo)簽中經(jīng)常會(huì)有class的屬性這時(shí)候.find_all(class = "green")就么沒(méi)有用了力试。你可以用以下方法解決
.find_all(class_="green")來(lái)代替毛仪,也就是在class后面加一個(gè)_(下劃線),但是這個(gè)方法顯得有點(diǎn)臃腫
我們完全可以用以下方法來(lái)代替.find_all("", {"class":"green"})
再順便說(shuō)一下对粪,用標(biāo)簽參數(shù)將tag以列表的形式傳入是或關(guān)系的過(guò)濾器而keyword的與的選擇器
再來(lái)說(shuō)說(shuō).find右冻,.find其實(shí)就是.find_all()的一種特殊情況,也就是limit = 1的特殊情況著拭。而.find_all()方法是返回一個(gè)列表而find方法是直接返回結(jié)果
.find_all()和.find只會(huì)去搜索子孫節(jié)點(diǎn)纱扭,如果要搜尋父節(jié)點(diǎn)的話那就要用.find_parents()和.find_parent()這個(gè)兩個(gè)的參數(shù)和.find_all()和.find()的一樣。其中.find_parents()和.parents功效相似儡遮,.find_parent()和.parent功效相似乳蛾。BeautifulSoup還有一些其他的搜索API其中一半是和find()的參數(shù)一樣一半是和.find_all()的參數(shù)一樣,
其他的幾個(gè)分別是(中括號(hào)中的是與之功效相似的):
.find_next_siblings()[.next_siblings],.find_next_sibling()[.next_sibling],.find_previous_siblings()[.previous_siblings],.find_previous_sibling()[.previous_sibling],.find_all_next()[.next_elements],.find_next()[.next_element],.find_all_previous()[.previous_elements],.find_previous()[.previous_elements]
CSS選擇器
BeautifulSoup對(duì)象支持絕大多數(shù)CSS選擇器,在Tag和BeautifulSoup對(duì)象的.select()方法中傳入字符串參數(shù)就可以找到相應(yīng)的tag(返回結(jié)果一般是列表的形式)那么我們就來(lái)說(shuō)說(shuō)它的使用方法。
1.可以直接通過(guò)標(biāo)簽選擇:
? ? ? ? ? ? ? ? 例如(還是以第二篇的那個(gè)HTML為例子):
? ? ? ? ? ? ? ? ? ? ????????soup.select("title")
????????????????????????????那么就可以得到以下結(jié)果:[<title>The Dormouse's story</title>]肃叶,通過(guò)這個(gè)方法可以得到所有title標(biāo)簽
????????????????也可以用這個(gè)語(yǔ)法:
???????????????????????????? soup.select("p:nth-of-type(3)")
? ? ? ? ? ? ? ? ? ? ? ? ? ? 那么就可以得到以下的結(jié)果:[<p class = "story">....</p>]
????????????????????????????在這個(gè)例子中p:nth-of-type(3)這條語(yǔ)法相當(dāng)于是選擇第三個(gè)p標(biāo)簽蹂随,相當(dāng)于soup.select(p)[2])
? ? ? ? ? ? ? ? 我們也可以通過(guò)tag逐層尋找:
????????????????????????????soup.select("body a")這方法可以找到body下所有的a標(biāo)簽
? ? ? ? ? ? ? ? ? ? ? ? ? ? 也可以用這個(gè)soup.select("body > a")(這里的body和>和a之間一定要有空格)這個(gè)方法的話可以得到的是body下屬的第一個(gè)a標(biāo)簽
? ? ? ? ? ? ? ? 也可以來(lái)組合一下:
? ? ? ? ? ? ? ? ????????????soup.select("p > a:nth-of-type(2)")
? ? ? ? ? ? ? ? 當(dāng)然也會(huì)有尋找兄弟節(jié)點(diǎn)的方法:
? ? ? ? ? ? ? ? ? ? ? ? ? ? soup.select("#link1 ~ .mysis")這個(gè)方法可以找到id = link1后的所有兄弟節(jié)點(diǎn)標(biāo)簽
? ? ? ? ? ? ? ? ? ? ? ? ? ? 而這個(gè)方法soup.select("#link1 + .mysis")是可以得到id = link1的下一個(gè)兄弟標(biāo)簽
2.我們也可以通過(guò)類(lèi)名來(lái)尋找
? ? ? ? ? ? ? ? 例如:
????????????????????????????soup.select(".story")這個(gè)方法可以找到所有class為story的標(biāo)簽
? ??????????????????????????soup.select("p.sister")這個(gè)方法可以找到所有class為story的p標(biāo)簽
3.也可以通過(guò)id去查找
? ? ? ? ? ? ? ? 例如:
? ??????????????????????????soup.select("#link1")這個(gè)方法可以找到所有id = #link的標(biāo)簽
? ??????????????????????????soup.select("a#link2")而這個(gè)方法可以得到所有id = #link的a標(biāo)簽
4.也可以通過(guò)屬性來(lái)查找
? ? ? ? ? ? ? ? ? ? ? ? ? ? 一、是否存在某種屬性:
????????????????????????????????????????soup.select('a[href]')尋找存在href屬性的標(biāo)簽
? ? ? ? ? ? ? ? ? ? ? ? ? ? 二因惭、通過(guò)屬性的值去尋找:
? ??????????????????????????????????????soup.select('a[)這條指令可以找到所有href值為http://example.com/elsie的a標(biāo)簽
5.也可以通過(guò)語(yǔ)言來(lái)設(shè)置:
????????????????????????????看這個(gè)例子:
language = """
<p lang = "en">Hello</p>
<p lang = "en-us">Howdy,y'all</p>
<p lang="en-gb">Pip-pip, old fruit</p>
<p lang="fr">Bonjour mes amis</p>
"""
soup = BeautifulSoup(language,'lxml')
soup.select('p[lang|=en]')這條指令可以得到一下結(jié)果:[<p lang= "en">Hello</p>,<p lang="en-us">Howdy,y'all</p>,<p lang="en-gb">Pip-pip, old fruit</p>]