使用"解析HTML标记:"用lxml

时间:2015-08-31 11:34:21

标签: python html parsing lxml

我是python的新手,我试图用lxml解析一个Html页面。我想从<p>标记中获取文字。但在其中我有一个奇怪的标签:

  <p style="margin-left:0px;padding:0 0 0 0;float:left;">
       <g:plusone size="medium">
       </g:plusone>
      </p>

如何在<p>内忽略此标记?我想用&#34;:&#34;切割所有标签在任何html页面内,因为lxml的另一个功能无法正常使用这样的标签。

parser=etree.HTMLParser() 
tree = etree.parse('problemtags.html',parser) 
root=tree.getroot() 
text = [ b.text for b in root.iterfind(".//p")] 

我希望在<p>标签内部获得一些文字。但是当我看起来像这样时,它会像上面那样在片段上失败。它写道:&#34; b&#39;标记g:plusone无效&#39;&#34;。我只需要 - 它会忽略所有这样的incorect标签。我不确切知道将来有多少这样的标签,但我认为问题确实存在于&#34;:&#34;现在,因为当我使用&#34; .tag&#34;并获得名称,它只是&#34; plusone&#34;而不是&#34; g:plusone&#34;。

2 个答案:

答案 0 :(得分:0)

这是我发现清理html的方法:

from lxml import etree
from StringIO import StringIO

s = '''<p style="margin-left:0px;padding:0 0 0 0;float:left;">
   <g:plusone size="medium">
   </g:plusone>
  </p>'''

parser = etree.HTMLParser()
tree = etree.parse(StringIO(s), parser)
result = etree.tostring(tree.getroot(),pretty_print=True,method="html")
print result

打印

<html><body><p style="margin-left:0px;padding:0 0 0 0;float:left;">
       <plusone size="medium">
       </plusone>
      </p></body></html>

要从etree._ElementTree获取etree.Element引用,即etree._Element,只需

root = tree.getroot()
print type(root) # prints lxml.etree._Element

根据_Element-class,lxml.etree._Element是文档实例引用的类,换句话说,它是实例化etree.Element的结果,例如

el = etree.Element("an_etree.Element_reference")
print type(el) # prints lxml.etree._Element

答案 1 :(得分:0)

g:是名称空间前缀。实际的标记名称仅为plusone。因此,lxml仅在返回plusone作为标记名称时是正确的。请参阅命名空间here的摘要。

据我了解,lxml的HTML Parser不支持名称空间。但是,XML Parser是。据推测,假设这个HTML文档包含XML,它很可能实际上是一个XHTML文档(如果没有,那么它可能是一个无效的HTML文档,你不能指望lxml正确地解析它)。因此,您需要通过XML Parser而不是HTML Parser运行它。 lxml的命名空间API在tutorial

中进行了解释

但是,使用您提供的片段,解析器将返回:

>>> d = etree.fromstring('''<p style="margin-left:0px;padding:0 0 0 0;float:left;">
...        <g:plusone size="medium">
...        </g:plusone>
...       </p>''')
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
  File "lxml.etree.pyx", line 3032, in lxml.etree.fromstring (src\lxml\lxml.etree.c:68121)
  File "parser.pxi", line 1786, in lxml.etree._parseMemoryDocument (src\lxml\lxml.etree.c:102470)
  File "parser.pxi", line 1674, in lxml.etree._parseDoc (src\lxml\lxml.etree.c:101299)
  File "parser.pxi", line 1074, in lxml.etree._BaseParser._parseDoc (src\lxml\lxml.etree.c:96481)
  File "parser.pxi", line 582, in lxml.etree._ParserContext._handleParseResultDoc (src\lxml\lxml.etree.c:91290)
  File "parser.pxi", line 683, in lxml.etree._handleParseResult (src\lxml\lxml.etree.c:92476)
  File "parser.pxi", line 622, in lxml.etree._raiseParseError (src\lxml\lxml.etree.c:91772)
lxml.etree.XMLSyntaxError: Namespace prefix g on plusone is not defined, line 2, column 23

请注意,它会抱怨&#34; Namespace prefix g on plusone is not defined。&#34;据推测,在文档的其他位置定义了名称空间前缀。由于我不知道那是什么,我只是做一些事情并定义你的片段中的plusone标签:

>>> d = etree.fromstring('''<p style="margin-left:0px;padding:0 0 0 0;float:left;">
...        <g:plusone xmlns:g="something" size="medium">
...        </g:plusone>
...       </p>''')
>>> d
<Element p at 0x2563cd8>
>>> d.tag
'p'
>>> d[0]
<Element {something}plusone at 0x2563940>
>>> d[0].tag
'{something}plusone' 

请注意,在这种情况下,g:前缀替换为实际名称空间({something},因为我设置如下:xmlns:g="something")。通常命名空间实际上是URI。因此,您可能会发现您的代码看起来像这样:{http://where.it/is/from.xml}plusone

尽管如此,我觉得在没有必要时使用命名空间相当麻烦。实际上,您可能会发现使用忽略命名空间的HTML解析器更容易。现在您知道标记名为plusone,而不是g:plusone,您可以仅使用HTML解析器继续工作。