05 頁面解析
一、BeautifulSoup
BeautifulSoup 是一個可以從HTML或XML文件中提取數(shù)據(jù)的Python庫沧竟,它的使用方式相對于正則來說更加的簡單方便碗殷,常常能夠節(jié)省我們大量的時間。
官方中文文檔的:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html
BeautifulSoup的安裝也是非常方便的,pip安裝即可抹镊。
pip install beautifulsoup4
1、簡單例子
# 實(shí)例BeautifulSoup對象
soup = BeautifulSoup(html_doc,'lxml')
print(soup.title) # 獲取title標(biāo)簽
print(soup.title.name) # 獲取title標(biāo)簽的標(biāo)簽名
print(soup.title.string) # 獲取title標(biāo)簽的文字內(nèi)容
print(soup.title.parent.name) # 獲取title標(biāo)簽父標(biāo)簽的標(biāo)簽名
print(soup.a) # 獲取第一個a標(biāo)簽 # <a href="homepage.html">首頁</a>
print(soup.a.attrs) # 獲取屬性 {'href': 'homepage.html'}
print(soup.a.string) # 首頁
print(soup.p['class'])
print(soup.find_all('a')) # 獲取所有的a標(biāo)簽
print(soup.find(id='link3')) # 獲取id為link3的標(biāo)簽
print(type(soup)) # <class 'bs4.BeautifulSoup'>
print(soup.name) # [document]
print(soup.attrs) # {}
print(soup.li) # <li><a href="homepage.html"><!--首頁--></a></li>
print(soup.li.string) # 首頁
2瞪慧、指定解析器
BeautifulSoup解析網(wǎng)頁需要指定一個可用的解析器髓考,以下是主要幾種解析器:
由于這個解析的過程在大規(guī)模的爬取中是會影響到整個爬蟲系統(tǒng)的速度的,所以推薦使用的是lxml弃酌,速度會快很多氨菇,而lxml需要單獨(dú)安裝:
pip install lxml
soup = BeautifulSoup(html_doc, 'lxml') # 指定
提示:如果一段HTML或XML文檔格式不正確的話,那么在不同的解析器中返回的結(jié)果可能是不一樣的,所以要指定某一個解析器妓湘。
3查蓉、節(jié)點(diǎn)對象
5、Tag與遍歷文檔樹
tag對象可以說是BeautifulSoup中最為重要的對象榜贴,通過BeautifulSoup來提取數(shù)據(jù)基本都圍繞著這個對象來進(jìn)行操作豌研。
首先,一個節(jié)點(diǎn)中是可以包含多個子節(jié)點(diǎn)和多個字符串的唬党。例如html節(jié)點(diǎn)中包含著head和body節(jié)點(diǎn)鹃共。所以BeautifulSoup就可以將一個HTML的網(wǎng)頁用這樣一層層嵌套的節(jié)點(diǎn)來進(jìn)行表示。
6驶拱、find_all()
上方這種直接通過屬性來進(jìn)行訪問屬性的方法霜浴,很多時候只能適用于比較簡單的一些場景,所以BeautifulSoup還提供了搜索整個文檔樹的方法find_all()蓝纲。
通過name搜索阴孟,find_all('b')可以直接查找出整個文檔樹中所有的b標(biāo)簽,并返回列表
通過屬性搜索税迷,我們在搜索的時候一般只有標(biāo)簽名是不夠的永丝,因為可能同名的標(biāo)簽很多,那么這時候我們就要通過標(biāo)簽的屬性來進(jìn)行搜索箭养。這時候我們可以通過傳遞給attrs一個字典參數(shù)來搜索屬性慕嚷。
soup.find_all(attrs={'class': 'sister'})
通過文本搜索,在find_all()方法中,還可以根據(jù)文本內(nèi)容來進(jìn)行搜索闯冷。soup.find_all(text="Elsie")
限制查找范圍為子節(jié)點(diǎn)
find_all()方法會默認(rèn)的去所有的子孫節(jié)點(diǎn)中搜索砂心,而如果將recursive參數(shù)設(shè)置為False,則可以將搜索范圍限制在直接子節(jié)點(diǎn)中蛇耀。 soup.html.find_all("title", recursive=False)
通過正則表達(dá)式來篩選查找結(jié)果在BeautifulSoup中辩诞,也是可以與re模塊進(jìn)行相互配合的,將re.compile編譯的對象傳入find_all()方法纺涤,即可通過正則來進(jìn)行搜索译暂。
tags = soup.find_all(re.compile("^b"))
7、css選擇器查找
在BeautifulSoup中撩炊,同樣也支持使用CSS選擇器來進(jìn)行搜索外永。使用select(),在其中傳入字符串參數(shù)拧咳,就可以使用CSS選擇器的語法來找到tag伯顶。
print(soup.select('.top .menu'))
# [<ul class="menu">
# <li><a href="homepage.html"><!--首頁--></a></li>
# <li><a href="online.html">在線課堂</a></li>
# <li><a href="consult.html">付費(fèi)咨詢</a></li>
# <li><a href="search.html">搜索</a></li>
# </ul>]
二、xpath
XPath 是一門在 XML 文檔中查找信息的語言骆膝。XPath 可用來在 XML 文檔中對元素和屬性進(jìn)行遍歷祭衩。
相比于BeautifulSoup,Xpath在提取數(shù)據(jù)時會更有效率阅签。
在python中很多庫都提供XPath的功能掐暮,但是最流行的還是lxml這個庫,效率最高政钟。在之前BeautifulSoup中我們也介紹了lxml是如何安裝的路克。
pip install lxml
1、語法
XPath 使用路徑表達(dá)式在 XML/HTML 文檔中選取節(jié)點(diǎn)养交。節(jié)點(diǎn)是通過沿著路徑或者 step 來選取的精算。
nodename 選取當(dāng)前節(jié)點(diǎn)的所有nodename子節(jié)點(diǎn)
/ 從根節(jié)點(diǎn)選取
// 從匹配選擇的當(dāng)前節(jié)點(diǎn)選擇文檔中的節(jié)點(diǎn),而不考慮它們的位置碎连。
. 選取當(dāng)前節(jié)點(diǎn)
.. 選取當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)
@ 選取屬性
例子
//bookstore/book[1] 選取屬于 bookstore 子元素的第一個 book 元素灰羽。
//bookstore/book[last()] 選取屬于 bookstore 子元素的最后一個 book 元素。
//bookstore/book[last()-1] 選取屬于 bookstore 子元素的倒數(shù)第二個 book 元素破花。
//bookstore/book[position()<3] 選取最前面的兩個屬于 bookstore 元素的子元素的 book 元素。
//title[@lang] 選取所有擁有名為 lang 的屬性的 title 元素疲吸。
//title[@lang='eng'] 選取所有 title 元素座每,且這些元素?fù)碛兄禐?eng 的 lang 屬性。
//bookstore/book[price>35.00] 選取 bookstore 元素的所有 book 元素摘悴,且其中的 price 元素的值須大于 35.00峭梳。
//bookstore/book[price>35.00]/title 選取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值須大于 35.00。
- 匹配任何元素節(jié)點(diǎn) //bookstore/* 選取bookstore元素的所有子元素葱椭。
- 匹配任何屬性節(jié)點(diǎn) //* 選取文檔中國的所有元素
de() 匹配任何類型的節(jié)點(diǎn) //title[@*] 選取所有帶有屬性的title元素
- 匹配任何屬性節(jié)點(diǎn) //* 選取文檔中國的所有元素
選取多個路徑
通過在路徑表達(dá)式中使用"|"運(yùn)算符捂寿,您可以選取若干個路徑。
在下面的表格中孵运,我們列出了一些路徑表達(dá)式秦陋,以及這些表達(dá)式的結(jié)果:
//book/title | //book/price 選取book元素的所有title和price元素
//title | //price 選取文檔中所有的title和price元素
//bookstore/book/title | //price 選取bookstore元素的book元素的所有title元素,以及文檔中所有的price元素
用text()獲取某個節(jié)點(diǎn)下的文本
用string()獲取某個節(jié)點(diǎn)下所有的文本
2治笨、例子
from lxml import etree
import requests
# 獲取網(wǎng)頁源代碼
resp = requests.get('http://www.baidu.com').content.decode()
# 實(shí)例化
selector = etree.HTML(resp)
print(selector.xpath('//div[@id="u1"]/a[@class="mnav"]/@href'))
print(selector.xpath('//div[@id="u1"]/a[@class="mnav"]/text()')) # ['新聞', 'hao123', '地圖', '視頻', '貼吧']
print(selector.xpath('//a/text()'))
# 模糊匹配 匹配 id中含有“a“的標(biāo)簽
print(selector.xpath('//div[contains(@id,"a")]'))
print(selector.xpath('//a[1]/text()'))