2010-09-10 16 views
4

假設我有這種HTML,從中我需要選擇「文本2」使用LXML/ElementTree的:掌握LXML非連續文本/ ElementTree的

<div>text1<span>childtext1</span>text2<span>childtext2</span>text3</div> 

如果我已經有div元素作爲mydiv,那麼mydiv.text只返回「text1」。

使用itertext()看起來有問題或麻煩,因爲它遍歷div下的整個樹。

是否有任何簡單/優雅的方式從元素中提取非第一個文本塊?

+1

這看起來像一個錯誤。你有沒有嘗試過使用'findtext(path)'? – 2010-09-18 06:55:43

+2

因爲我的回答顯然不能回答你的問題,你能否進一步解釋你在找什麼? – llasram 2010-09-19 09:18:51

回答

12

好,lxml.etree提供完整的XPath支持,允許您解決文本項:

>>> import lxml.etree 
>>> fragment = '<div>text1<span>childtext1</span>text2<span>childtext2</span>text3</div>' 
>>> div = lxml.etree.fromstring(fragment) 
>>> div.xpath('./text()') 
['text1', 'text2', 'text3'] 
+0

doc.xpath('/ div/text()')[1:2]會給你非第一個文本元素 – shahjapan 2010-09-24 06:51:58

+1

好吧,「一種方式來提取非第一個文本塊」包括許多可能性後,你得到所有文本項列表,如'random.choice(div.xpath('./text()')[1:])或set(div.xpath('./ text()')[1: ])。流行()'。但是,由於OP知道足夠了解lxml,所以我認爲數字列表操作就是小豆。 – 2010-09-24 07:43:35

6

這樣的文本將在您的元素的子元素的tail屬性中。如果你的元素是在elem則:

elem[0].tail 

會給你的第一個孩子的元素中的尾文本,你的情況"text2"你正在尋找。

4

正如llasram所說,任何不在text屬性中的文本都將在子節點的tail屬性中。

作爲一個例子,這裏的提取文本塊(第一和其他)中的一個節點的所有最簡單的方法:

html = '<div>text1<span>childtext1</span>text2<span>childtext2</span>text3</div>' 

import lxml.html # ...or lxml.etree as appropriate 
div = lxml.html.fromstring(html) 

texts = [div.text] + [child.tail for child in div] 
# Result: texts == ['text1', 'text2', 'text3'] 
# ...and you are guaranteed that div[x].tail == texts[x+1] 
# (which can be useful if you need to access or modify the DOM) 

如果你寧願犧牲這層關係,以防止texts從可能含有空字符串,你可以使用它代替:

texts = [div.text] + [child.tail for child in div if child.tail] 

我還沒有與普通的舊STDLIB ElementTree的測試,這一點,但它應該與工作了。 (事只有一次,我看到了巴蒂爾Holloway的具體LXML-解決發生在我身上),我只是喜歡LXML因爲它有更好的支持HTML的ideosyncracies我通常已經安裝了lxml.html.clean

1

使用node.text_content()讓所有節點下面的文本,作爲一個字符串。