python lxml在windows和linux上有不同的结果

Niu*_*uya 5 python xpath lxml elementtree

Linux的

>>> from lxml import etree
>>> html='''<td><a href=''>a1</a></td>
... <td><a href=''>a2</a></td>
... '''
>>> p=etree.HTML(html)
>>> a=p.xpath("//a[1]")
>>> for i in a:
...    print i.text
... 
a1
a2
Run Code Online (Sandbox Code Playgroud)

视窗.

>>> html='''<td><a href=''>a1</a></td>
... <td><a href=''>a2</a></td>
... '''
>>> from lxml import etree
>>> p=etree.HTML(html)
>>> a=p.xpath("//a[1]")
>>> for i in a:
...    print i.text
...
a1
>>> b=p.xpath("//a[2]")
>>> for i in b:
...    print i.text
...
a2
Run Code Online (Sandbox Code Playgroud)

在Windows中,我可以轻松地使用a[1]a[2]获得这两个值.但是在Linux中,xpath //a[1]将这两个链接文本放在一起.

这使得程序在这些操作系统中不那么兼容.我必须修改不同操作系统上的代码.它是一个lxml模块错误吗?对此有何解决方案?

Jan*_*sky 6

我可以在您报告的Linux上确认相同的结果.它返回两个元素的列表,而不是1个单个元素.

什么是xpath //a[1]要求

它要求任何a首先在其上下文中的元素.

因为你有a嵌入元素td,td是计算位置的上下文,这种情况有两次出现.

更改xpath以"(//a)[1]"解决问题.

操作员和特殊字符的MSDN引用

过滤器模式运算符([])的优先级高于路径运算符(/和//).例如,表达式// comment()[3]选择索引等于3的所有注释,相对于文档中任何位置的注释父项.这与表达式(// comment())[3]不同,后者从相对于父项的所有注释的集合中选择第三个注释.第一个表达式可以返回多个注释,而后者只能返回一个注释.

降级Windows lxml版本3.3.5

xpath //a[1]只返回提供文档的一个元素是完全错误的,应报告给lxml作者.

lxml在不同平台和操作系统上的状态:

  • 赢:lxml 2.3.0 - 好的
  • 赢:lxml 3.3.5 - BUG
  • 林:lxml 3.3.5 - 好的
  • 林:lxml 2.3.0 - 好的

为了使您的解决方案可移植,您应该要求,lxml==2.3.0因为此版本在Windows上以及在Linux上正常运行(可能有另一个版本在两个平台上运行良好,我没有测试更多).

奖金 - 测试套件

假设你已安装 nose

$ pip install nose
Run Code Online (Sandbox Code Playgroud)

您可以使用以下内容test_xpath.py:

from lxml import etree
import nose

print "=================================="
print "lxml version: ", etree.__version__
print "=================================="

def test_html():
    html_str = """
    <td><a href=''>a1</a></td>
    <td><a href=''>a2</a></td>
    """
    doc = etree.HTML(html_str.strip())
    elms = doc.xpath("//a[1]")
    assert len(elms) == 2, """xpath `//a[1]` shall return 2 elements"""
    assert all(elm.tag == "a" for elm in elms), "all returned elements shall be `a`"
    assert elms[0].text == "a1"
    assert elms[1].text == "a2"

def test_xml():
    xml_str = """
    <root>
        <td><a href=''>a1</a></td>
        <td><a href=''>a2</a></td>
    </root>
    """
    doc = etree.fromstring(xml_str.strip())
    elms = doc.xpath("//a[1]")
    assert len(elms) == 2, """xpath `//a[1]` shall return 2 elements"""
    assert all(elm.tag == "a" for elm in elms), "all returned elements shall be `a`"
    assert elms[0].text == "a1"
    assert elms[1].text == "a2"

nose.main()
Run Code Online (Sandbox Code Playgroud)

并快速执行测试:

$ python test_xpath.py  -v
==================================
lxml version:  2.3.0
==================================
test_xpath.test_html ... ok
test_xpath.test_xml ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.002s

OK
Run Code Online (Sandbox Code Playgroud)