.attrib 屬性和 .get()方法
前者是html tag的屬性集合禽最,以字典表示;后者是取得某個屬性的值袱饭,相當于字典的.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 tag虑乖,但保留它的子節(jié)點和文本并合并到該tag的父節(jié)點懦趋。
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()方法 ('.//p')
移除該節(jié)及其子節(jié)點和文本,而它后面的文本(tail text)合并到前面一個節(jié)點或父節(jié)點疹味。
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>'
.drop_tree()方法
移除該節(jié)及其子節(jié)點和文本仅叫,而它后面的文本(tail text)合并到前面一個節(jié)點或父節(jié)點。
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>'
通過path(Xpath)或tag查找特定節(jié)點佛猛,前者返回找到的第一個惑芭,第二個返回找到的全部HTMLElement,第三個返回找到的第一個的節(jié)點的文本(.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)方法
通過class名稱查找所有含有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) 方法
得到第一個id為輸入id的節(jié)點遂跟。如果有多個相同id的節(jié)點(按道理講,一個HTML文檔里面的id是唯一的)只返回第一個婴渡。
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é)點和父節(jié)點边臼。需要注意的是哄尔,還是可以有多個(返回list),父親只有一個柠并。
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>
# 注意:輸入的本沒有body岭接,div已經(jīng)是最上層節(jié)點富拗,它的父節(jié)點就是body了
.getnext() .getprevious() 方法
獲取后一個或前一個節(jié)點,如果沒有則返回None鸣戴。
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é)點開始,按文檔順序(深度優(yōu)先)遍歷所有子節(jié)點窄锅〈辞В可以指定只遍歷某些tag。
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é)點入偷。
.iterancestors() .iterdescendants()方法
前者遍歷前輩(從父親節(jié)點開始)追驴,后者遍歷后輩(從子輩開始),都跳過該節(jié)點疏之。
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) 方法
遍歷所有符合path的子節(jié)點殿雪,類似于findall()
.make_links_absolute(base_url)
很多網(wǎng)頁的鏈接都是類似href=”/path/a.html”沒有寫全網(wǎng)址,這個方法的作用就是補全網(wǎng)址体捏。
.tag 屬性
該節(jié)點的html tag 名稱
.text and .tail 屬性
都是該節(jié)點的文本內(nèi)容冠摄,不同的是一個在tag內(nèi),一個在尾部:
<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é)點及其子節(jié)點包含的所有文本
In [178]: doc.text_content()
Out[178]: 'abclinkworodapple'
lxml.html 從html字符串生成文檔樹結(jié)構(gòu)
我們下載得到的網(wǎng)頁就是一串html字符串几缭,如何把它輸入給lxml.html模塊河泳,從而生成html文檔的樹結(jié)構(gòu)呢?
該模塊提供了幾種不同的方法:
parse(filename_url_or_file):
輸入的是一個文件名年栓、URL或文件對象(有read()方法)拆挥。
document_fromstring(string):
輸入的是一個html的字符串,創(chuàng)建一個HTML文檔樹結(jié)構(gòu)某抓,它的根節(jié)點就是, 和 子節(jié)點纸兔。
fragment_fromstring(string, create_parent=False):
返回輸入字符串的HTML片段。這個片段壁紙只含有一個element(元素)否副,也就是單一節(jié)點汉矿,除非給出了create_parent 參數(shù),否則會報錯备禀。
fragments_fromstring(string):
返回包含輸入字符串中所有片段的列表洲拇。
fromstring(string):
返回值依據(jù)輸入字符串而定,如果輸入看起來像是一個文檔曲尸,則返回document_fromstring(string)赋续,如果是一個單一片段,則返回fragment_fromstring(string)另患。
下面我們通過具體示例來說明上面幾個方法的不同纽乱。
document_fromstring 的使用方法
In [1]: import lxml.html as lh
In [2]: z = lh.document_fromstring('<span>abc</span><span>xyz</span>')
# 可以看到,它自動加了根節(jié)點<html>
In [3]: z
Out[3]: <Element html at 0x7fc410667b88>
In [4]: z.tag
Out[4]: 'html'
# 還加了<body>節(jié)點
In [5]: z.getchildren()
Out[5]: [<Element body at 0x7fc4101a3ae8>]
# 把字符串的兩個節(jié)點放在了<body>里面
In [6]: z.getchildren()[0].getchildren()
Out[6]: [<Element span at 0x7fc410092bd8>, <Element span at 0x7fc410667c28>]
fragment_fromstring 的使用
In [11]: z = lh.fragment_fromstring(‘<div>abc</div><div>xyz</div>’)
---------------------------------------------------------------------------
ParserError Traceback (most recent call last)
<ipython-input-11-a11f9a0f71d1> in <module>()
----> 1 z = lh.fragment_fromstring(‘<div>abc</div><div>xyz</div>’)
~/.virtualenvs/py3.6/lib/python3.6/site-packages/lxml/html/__init__.py in fragment_fromstring(html, create_parent, base_url, parser, **kw)
850 raise etree.ParserError(
851 “Multiple elements found (%s)”
--> 852 % ‘, ‘.join([_element_name(e) for e in elements]))
853 el = elements[0]
854 if el.tail and el.tail.strip():
ParserError: Multiple elements found (div, div)
# 可以看到昆箕,輸入是兩個節(jié)點(element)時就會報錯
# 如果加上 create_parent 參數(shù)鸦列,就沒問題了
In [12]: z = lh.fragment_fromstring('<div>abc</div><div>xyz</div>', create_parent='p')
In [13]: z.tag
Out[13]: 'p'
In [14]: z.getchildren()
Out[14]: [<Element div at 0x7fc40a41a818>, <Element div at 0x7fc40a41aea8>]
fragments_fromstring 的使用
# 輸入字符串含有一個節(jié)點租冠,則返回包含這一個節(jié)點的列表
In [17]: lh.fragments_fromstring('<div>abc</div>')
Out[17]: [<Element div at 0x7fc40a124ea8>]
# 輸入字符串含有多個節(jié)點,則返回包含這多個節(jié)點的列表
In [18]: lh.fragments_fromstring('<div>abc</div><div>xyz</div>')
Out[18]: [<Element div at 0x7fc40a124b88>, <Element div at 0x7fc40a124f98>]
fromstring 的使用
In [27]: z = lh.fromstring('<div>abc</div><div>xyz</div>')
In [28]: z
Out[28]: <Element div at 0x7fc40a0eb368>
In [29]: z.getchildren()
Out[29]: [<Element div at 0x7fc410135548>, <Element div at 0x7fc40a0eb2c8>]
In [30]: type(z)
Out[30]: lxml.html.HtmlElement
這里薯嗤,fromstring輸入的如果是多個節(jié)點肺稀,它會給加一個父節(jié)點并返回。但是像html網(wǎng)頁都是從節(jié)點開始的应民,我們使用fromstring() 和 document_fromstring() 都可以得到完整的網(wǎng)頁結(jié)構(gòu)。
從上面代碼中我們可以看到夕吻,那幾個函數(shù)返回的都是HtmlElement對象
from : https://www.yuanrenxue.com/crawler/extract-data-lxml-xpath.html