溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Python爬蟲(chóng)網(wǎng)頁(yè),解析工具lxml.html(二)

發(fā)布時(shí)間:2020-08-10 00:59:52 來(lái)源:ITPUB博客 閱讀:245 作者:程序員啟航 欄目:編程語(yǔ)言

【前情回顧】如何靈活的解析網(wǎng)頁(yè),提取我們想要的數(shù)據(jù),是我們寫(xiě)爬蟲(chóng)時(shí)非常關(guān)心和需要解決的問(wèn)題。

從Python的眾多的可利用工具中,我們選擇了lxml的,它的好我們知道,它的妙待我們探討。前面我們已經(jīng)從HTML字符串轉(zhuǎn)換成的HtmlElement對(duì)象,接下來(lái)我們就探討該如何操作這個(gè)的HtmlElement對(duì)象。

Python爬蟲(chóng)網(wǎng)頁(yè),解析工具lxml.html(二)

lxml.html的HtmlElement對(duì)象的各種屬性和方法

這個(gè)的HtmlElement對(duì)象有各種方法,我們重點(diǎn)討論跟解析網(wǎng)頁(yè)相關(guān)的函數(shù),而修改這個(gè)對(duì)象的方法若與提取內(nèi)容相關(guān)也一并介紹,介紹過(guò)程結(jié)合下面這段HTML代碼以便更好說(shuō)明問(wèn)題:

<div class="post" id="123">
    <p class="para">abc<a href="/to-go">link</a></p>
</div>

.attrib屬性和.get()方法

前者是html tag的屬性集合,以字典表示;后者是取得某個(gè)屬性的值,相當(dāng)于字典的.get()方法??词纠?

In [35]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
In [37]: doc.attrib
Out[37]: {'class': 'post', 'id': '123'}
In [38]: doc.get('class')
Out[38]: 'post'

.drop_tag()方法

移除該html標(biāo)簽,但保留它的子節(jié)點(diǎn)和文本并合并到該標(biāo)簽的父節(jié)點(diǎn)。

In [46]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
In [47]: doc.find('.//p').drop_tag()
In [48]: lxml.html.tostring(doc)
Out[48]: b'<div class="post" id="123">abc<a href="/to-go">link</a></div>'

.drop_tree()方法

移除該節(jié)及其子節(jié)點(diǎn)和文本,而它后面的文本(尾文)合并到前面一個(gè)節(jié)點(diǎn)或父節(jié)點(diǎn)。

In [50]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
In [51]: doc.find('.//p').drop_tree()
In [52]: lxml.html.tostring(doc)
Out[52]: b'<div class="post" id="123"></div>'

.find(path),. find(path),. findtext(path)方法

通過(guò)路徑(Xpath的)或標(biāo)簽查找特定節(jié)點(diǎn),前者返回找到的第一個(gè),第二個(gè)返回找到的全部HTML元素,第三個(gè)返回找到的第一個(gè)的節(jié)點(diǎn)的文本(的.text)

In [55]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
In [56]: doc.find('p')
Out[56]: <Element p at 0x7fc40a4dd6d8>
In [57]: doc.find('.//a')
Out[57]: <Element a at 0x7fc409fee4a8>
In [58]: doc.findall('p')
Out[58]: [<Element p at 0x7fc40a4dd6d8>]
In [76]: doc.findtext('.//a')
Out[76]: 'link'

.find_class(CLASS_NAME)方法

通過(guò)類(lèi)名稱(chēng)查找所有含有CLASS_NAME的元素,返回的HtmlElement的列表

In [70]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p><p class="para p2"></p></div>')
In [71]: doc.find_class('para')
Out[71]: [<Element p at 0x7fc40a3ff278>, <Element p at 0x7fc40a3ffc78>]

.get_element_by_id(id)方法

得到第一個(gè)ID為輸入ID的節(jié)點(diǎn)。如果有多個(gè)相同ID的節(jié)點(diǎn)(按道理講,一個(gè)HTML文檔里面的ID是唯一的)只返回第一個(gè)。

In [79]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
In [80]: doc.get_element_by_id('123')
Out[80]: <Element div at 0x7fc409fda2c8>

.getchildren(),getparent()方法

顧名思義,獲得孩子節(jié)點(diǎn)和父節(jié)點(diǎn)。需要注意的是,還是可以有多個(gè)(返回列表),父親只有一個(gè)。

In [83]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
In [84]: doc.getchildren()
Out[84]: [<Element p at 0x7fc410836b38>]
In [85]: doc.getparent()
Out[85]: <Element body at 0x7fc40a3ff9a8>
# 注意:輸入的本沒(méi)有body,div已經(jīng)是最上層節(jié)點(diǎn),它的父節(jié)點(diǎn)就是body了

.getnext()。getprevious()方法

獲取后一個(gè)或前一個(gè)節(jié)點(diǎn),如果沒(méi)有則返回?zé)o。

In [109]: doc = lxml.html.fromstring('<div><p>abc</p><p>xyz</p></div>')
In [110]: doc.getnext()
In [111]: doc.find('p').getnext()
Out[111]: <Element p at 0x7fc409fdad68>
In [112]: doc.find('p').getprevious()

.getiterator(),. iter()方法

從該節(jié)點(diǎn)開(kāi)始,按文檔順序(深度優(yōu)先)遍歷所有子節(jié)點(diǎn)??梢灾付ㄖ槐闅v某些標(biāo)簽。

In [127]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
In [128]: for itr in doc.getiterator():
     ...:     print(itr.tag)
     ...: 
div
p
a
In [129]: for itr in doc.iter():
     ...:     print(itr.tag)
     ...: 
div
p
a

.iterchildren()方法

只遍歷子節(jié)點(diǎn)。

.iterancestors()。iterdescendants()方法

前者遍歷前輩(從父親節(jié)點(diǎn)開(kāi)始),后者遍歷后輩(從子輩開(kāi)始),都跳過(guò)該節(jié)點(diǎn)。

In [134]: doc = lxml.html.fromstring('<div class="post" id="123"><p class="para">abc<a href="/to-go">link</a></p></div>')
In [135]: a = doc.find('.//a')
In [136]: for itr in doc.iterancestors():
     ...:     print(itr.tag)
     ...: 
body
html
In [137]: for itr in a.iterancestors():
     ...:     print(itr.tag)
     ...: 
p
div
body
html
In [138]: for itr in doc.iterdescendants():
     ...:     print(itr.tag)
     ...: 
p
a

.iterfind(path)方法

遍歷所有符合路徑的子節(jié)點(diǎn),類(lèi)似于的findall()

.make_links_absolute(BASE_URL)

很多網(wǎng)頁(yè)的鏈接都是類(lèi)似HREF =” /路徑/ a.html”沒(méi)有寫(xiě)全網(wǎng)址,這個(gè)方法的作用就是補(bǔ)全網(wǎng)址。

.tag屬性

該節(jié)點(diǎn)的html標(biāo)簽名稱(chēng)

.text .tail屬性

都是該節(jié)點(diǎn)的文本內(nèi)容,不同的是一個(gè)在標(biāo)簽內(nèi),一個(gè)在尾部:

<p>text</p>tail

再看下面的代碼

In [173]: doc = lxml.html.fromstring('<div><p class="para">abc<a href="/to-go">link</a>worod</p>apple</div>')
In [174]: p = doc.find('p')
In [175]: p.text
Out[175]: 'abc'
In [176]: p.tail
Out[176]: 'apple'

.text_content()方法

返回給節(jié)點(diǎn)及其子節(jié)點(diǎn)包含的所有文本

In [178]: doc.text_content()
Out[178]: 'abclinkworodapple'

以上就是我們從網(wǎng)頁(yè)提取內(nèi)容時(shí)用到的主要屬性和方法。下一節(jié),我們將以實(shí)例講解具體提取數(shù)據(jù)的過(guò)程。


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI