python之lxml快速上手_Element(二)

来源:互联网 发布:js动态添加tr td 编辑:程序博客网 时间:2024/06/07 03:57

使用XPath查找文本(Using XPath to find text)

另一个在树状结构文档中抽取文本的方式是:XPath,它同样允许你抽取单独的文本块并放到list中。

>>> print(html.xpath("string()")) # lxml.etree only!TEXTTAIL>>> print(html.xpath("//text()")) # lxml.etree only!['TEXT', 'TAIL']

如果你想重复利用上述代码,你可以把它封装到一个函数中:

# 注意,此处使用text(),而不是string()、concat(),后续有说明>>> build_text_list = etree.XPath("//text()") # lxml.etree only!>>> print(build_text_list(html))['TEXT', 'TAIL']

注意,由XPath返回的文本结果是一个非常“智能”的对象,它知道自己的出身。你可以使用getparent()来了解它来自哪里(即获取它的父节点),就像你对Element对象所做的那样。

>>> texts = build_text_list(html)>>> print(texts[0])TEXT>>> parent = texts[0].getparent()>>> print(parent.tag)body>>> print(texts[1])TAIL>>> print(texts[1].getparent().tag)br

你还可以知道它到底是普通的文本内容,还是尾部文本(tail text):

>>> print(texts[0].is_text)True>>> print(texts[1].is_text)False>>> print(texts[1].is_tail)True

既然text()函数返回的文本对象可以告诉你它的“归属”(即获取它的父节点),当你使用XPath函数string()、concat()时,它将不再告诉你它的“归属”。

>>> stringify = etree.XPath("string()")>>> print(stringify(html))TEXTTAIL>>> print(stringify(html).getparent())None

树的迭代(Tree iteration)

为了应对上面的问题,你可能需要递归遍历并使用对它拥有的节点做一些事情,而树的迭代恰好是一个很方便的解决方案。为实现这一目的,Elements提供了树迭代器。就像生成器一样,在有序的文档(document order)返回(yield)节点。

>>> root = etree.Element("root")>>> etree.SubElement(root, "child").text = "Child 1">>> etree.SubElement(root, "child").text = "Child 2">>> etree.SubElement(root, "another").text = "Child 3">>> print(etree.tostring(root, pretty_print=True))<root>  <child>Child 1</child>  <child>Child 2</child>  <another>Child 3</another></root>>>> for element in root.iter():...     print("%s - %s" % (element.tag, element.text))root - Nonechild - Child 1child - Child 2another - Child 3

如果你仅仅对某一些标签感兴趣,你可以把它的标签名传递给iter()来为你过滤掉不需要的标签。从lxml 3.0开始,你也可以同时传递多个标签名:

>>> for element in root.iter("child"):...     print("%s - %s" % (element.tag, element.text))child - Child 1child - Child 2>>> for element in root.iter("another", "child"):...     print("%s - %s" % (element.tag, element.text))child - Child 1child - Child 2another - Child 3

默认情况下,迭代器会返回树的所有节点,包括ProcessingInstructions(处理指令),Comments(注释)、Entity instances(实体实例)。如果你想确认只有元素节点(Elements)返回,你可以把Element工厂函数作为tag关键字参数传递给iter():

>>> root.append(etree.Entity("#234"))>>> root.append(etree.Comment("some comment"))>>> for element in root.iter():...     if isinstance(element.tag, basestring):...         print("%s - %s" % (element.tag, element.text))...     else:...         print("SPECIAL: %s - %s" % (element, element.text))root - Nonechild - Child 1child - Child 2another - Child 3SPECIAL: &#234; - &#234;SPECIAL: <!--some comment--> - some comment>>> for element in root.iter(tag=etree.Element):...     print("%s - %s" % (element.tag, element.text))root - Nonechild - Child 1child - Child 2another - Child 3>>> for element in root.iter(tag=etree.Entity):...     print(element.text)&#234;

注意,传递通配符“*”仍具会返回所有元素节点(仅包含Element)。

序列化(Serialisation)

序列化通常使用tostring()函数,它会返回一个字符串,或者你也可以使用ElementTree.write()方法将其写入到一个文件、类文件对象、一个URL。两种调用方式都接收同样的关键字参数,比如pretty_print(格式化输出),encoding(编码格式)可以指定除ASCII之外的输出编码格式,以及xml_declaration(是否加入XML声明):

>>> root = etree.XML('<root><a><b/></a></root>')>>> etree.tostring(root)b'<root><a><b/></a></root>'>>> print(etree.tostring(root, xml_declaration=True))<?xml version='1.0' encoding='ASCII'?><root><a><b/></a></root>>>> print(etree.tostring(root, encoding='iso-8859-1'))<?xml version='1.0' encoding='iso-8859-1'?><root><a><b/></a></root>>>> print(etree.tostring(root, pretty_print=True))<root>  <a>    <b/>  </a></root>

注意,美化输出(指定pretty_print=True时)会在文件最末位加一空白行。
在lxml 2.0及之后的版本,序列化函数能做的不仅局限于XML序列化。你也可以将其序列化成HTML,或者抽取文本,只需要通过method关键字参数:

>>> root = etree.XML(...    '<html><head/><body><p>Hello<br/>World</p></body></html>')>>> etree.tostring(root) # default: method = 'xml'b'<html><head/><body><p>Hello<br/>World</p></body></html>'>>> etree.tostring(root, method='xml') # same as aboveb'<html><head/><body><p>Hello<br/>World</p></body></html>'>>> etree.tostring(root, method='html')b'<html><head></head><body><p>Hello<br>World</p></body></html>'>>> print(etree.tostring(root, method='html', pretty_print=True))<html><head></head><body><p>Hello<br>World</p></body></html>>>> etree.tostring(root, method='text')b'HelloWorld'

与XML序列化一样,简单文本的序列化的默认编码格式也是ASCII

>>> br = next(root.iter('br'))  # get first result of iteration>>> br.tail = u'W\xf6rld'>>> etree.tostring(root, method='text')  # doctest: +ELLIPSISTraceback (most recent call last):  ...UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' ...>>> etree.tostring(root, method='text', encoding="UTF-8")b'HelloW\xc3\xb6rld'

在下面的例子中,序列化成一个python Unicode字符串,比字节串(byte strings)更加易于处理。只需指定encoding为unicode即可:

>>> etree.tostring(root, encoding='unicode', method='text')u'HelloW\xf6rld'
0 0
原创粉丝点击