我使用lxml.html解析html文件.... html文件包含带小写字母和大写字母的标签。我的代码的一部分如下所示:
response = urllib2.urlopen(link)
html = response.read().decode('cp1251')
content_html = etree.HTML(html_1)
first_link_xpath = content_html.xpath('//TR')
print (first_link_xpath)
我的HTML文件的一小部分如下所示:
<TR>
<TR vAlign="top" align="left">
<!--<TD><B onmouseover="tips.Display('Metadata_WEB', event)" onmouseout="tips.Hide('Metadata_WEB')">Meta Data:</B></TD>-->
<TD></TD>
</TR>
</TR>
因此,当我为以下html示例运行上面的代码时,它会给出一个空列表。然后我尝试运行这一行first_link_xpath = content_html_1.xpath('//tr/node()')
,所有大写标签在输出中都表示为\r\n\t\t\t\t'
:这个问题背后的原因是什么?
NOte:如果问题不具说服力,请告知我们进行修改
答案 0 :(得分:1)
为了跟进unutbu的答案,我建议你比较lxml
XML和HTML解析器,特别是它们如何通过使用lxml.etree.tostring()
询问树的表示来表示文档。您可以看到不同的标签,标签案例和层次结构(可能与人们的想法不同;)
$ python
>>> import lxml.etree
>>> doc = """<TR>
... <TR vAlign="top" align="left">
... <!--<TD><B onmouseover="tips.Display('Metadata_WEB', event)" onmouseout="tips.Hide('Metadata_WEB')">Meta Data:</B></TD>-->
... <TD></TD>
... </TR>
... </TR>"""
>>> xmldoc = lxml.etree.fromstring(doc)
>>> xmldoc
<Element TR at 0x1e79b90>
>>> htmldoc = lxml.etree.HTML(doc)
>>> htmldoc
<Element html at 0x1f0baa0>
>>> lxml.etree.tostring(xmldoc)
'<TR>\n <TR vAlign="top" align="left">\n <!--<TD><B onmouseover="tips.Display(\'Metadata_WEB\', event)" onmouseout="tips.Hide(\'Metadata_WEB\')">Meta Data:</B></TD>-->\n <TD/>\n </TR>\n </TR>'
>>> lxml.etree.tostring(htmldoc)
'<html><body><tr/><tr valign="top" align="left"><!--<TD><B onmouseover="tips.Display(\'Metadata_WEB\', event)" onmouseout="tips.Hide(\'Metadata_WEB\')">Meta Data:</B></TD>--><td/>\n </tr></body></html>'
>>>
您可以看到HTML解析器创建了封闭的html
和body
标记,并且在开头有一个空的tr
节点,因为在HTML中{{1 }}不能直接跟随tr
(您提供的HTML片段被破坏,无论是拼写错误,还是原始文档也被破坏)
然后,再次按照unutbu的建议,您可以尝试不同的XPath表达式:
tr
确实,正如unutbu强调的那样,对于HTML,XPath表达式应该使用小写标签来选择元素。
对我而言,'\ r \ n \ t \ t \ t \ t'输出不是错误,它只是各种>>> xmldoc.xpath('//tr')
[]
>>> xmldoc.xpath('//TR')
[<Element TR at 0x1e79b90>, <Element TR at 0x1f0baf0>]
>>> xmldoc.xpath('//TR/node()')
['\n ', <Element TR at 0x1f0baf0>, '\n ', <!--<TD><B onmouseover="tips.Display('Metadata_WEB', event)" onmouseout="tips.Hide('Metadata_WEB')">Meta Data:</B></TD>-->, '\n ', <Element TD at 0x1f0bb40>, '\n ', '\n ']
>>>
>>> htmldoc.xpath('//tr')
[<Element tr at 0x1f0bbe0>, <Element tr at 0x1f0bc30>]
>>> htmldoc.xpath('//TR')
[]
>>> htmldoc.xpath('//tr/node()')
[<!--<TD><B onmouseover="tips.Display('Metadata_WEB', event)" onmouseout="tips.Hide('Metadata_WEB')">Meta Data:</B></TD>-->, <Element td at 0x1f0bbe0>, '\n ']
>>>
和tr
标记之间的空白。对于文本内容,如果您不想要此空白,则可以使用td
,其中lxml.etree.tostring(element, memthod="text", encoding=unicode).strip()
来自XPath。 (这适用于前导和尾随空格)。
(请注意,element
参数很重要,默认情况下,它将输出上面测试过的HTML表示。)
method
您可以验证文本表示是否都是空格。
答案 1 :(得分:0)
HTML解析器将所有标记名称转换为小写。这就是xpath('//TR')
返回空列表的原因。
我无法重现第二个问题,即大写标签打印为\r\n\t\t\t\t'
。你能修改下面的代码来证明这个问题吗?
import lxml.etree as ET
content = '''\
<TR>
<TR vAlign="top" align="left">
<!--<TD><B onmouseover="tips.Display('Metadata_WEB', event)" onmouseout="tips.Hide('Metadata_WEB')">Meta Data:</B></TD>-->
<TD></TD>
</TR>
</TR>'''
root = ET.HTML(content)
print(root.xpath('//TR'))
# []
print(root.xpath('//tr/node()'))
# [<!--<TD><B onmouseover="tips.Display('Metadata_WEB', event)" onmouseout="tips.Hide('Metadata_WEB')">Meta Data:</B></TD>-->, <Element td at 0xb77463ec>, '\n ']
print(root.xpath('//tr'))
# [<Element tr at 0xb77462fc>, <Element tr at 0xb77463ec>]