XPath查询(例如“// th / a”)返回的结果不在当前元素下

时间:2015-08-11 20:31:32

标签: python xpath lxml

我有以下脚本:

from lxml import etree

sample_html = '''
<body><div><table><tbody>
<tr>
  <th><a href="xxx">AAA</a></th>
  <td data-xxx="AAA-1234"></td>
  <td data-xxx="AAA-5678"></td>
</tr>
<tr>
  <th><a href="xxx">BBB</a></th>
  <td data-xxx="BBB-1234"></td>
  <td data-xxx="BBB-5678"></td>
</tr>
</tbody></table></div></body>
'''

def parse_tree(tree):
    print '============================> Parsing tree'
    rows = tree.xpath('//body/div/table/tbody/tr')
    for row in rows:
        As = row.xpath('//th/a')
        for a in As:
            print a.text
        tds = row.xpath('//td')
        for td in tds:
            print td.attrib['data-xxx']
    print


body = sample_html
tree = etree.HTML(body)
parse_tree(tree)

这给了我输出:

============================> Parsing tree
AAA
BBB
AAA-1234
AAA-5678
BBB-1234
BBB-5678
AAA
BBB
AAA-1234
AAA-5678
BBB-1234
BBB-5678

但我在期待:

============================> Parsing tree
AAA
AAA-1234
AAA-5678
BBB
BBB-1234
BBB-5678

也就是说,我希望在for row in rows循环中我只能 访问一行。相反,xpath似乎以某种方式处理整个表格。我显然不明白发生了什么。

有人可以澄清xpath如何处理行,以及为什么它在循环中访问整个表?我该如何更正我的剧本?

2 个答案:

答案 0 :(得分:3)

你的锚定是错误的。而不是:

for row in rows:
    As = row.xpath('//th/a')

...使用前导.来引用树中当前元素的位置:

for row in rows:
    As = row.xpath('.//th/a')

.//告诉查询它相对于树中的当前位置,而前导//显式地从根运行递归搜索。

顺便说一下 - 为什么你的搜索会递归?您可以将//更改为/,并获得显着的效率。

答案 1 :(得分:3)

查看Abbreviated Syntax section of the XPath spec,特别是

  • <?php $file_data = file_get_contents('/home/MYFILE.csv'); //$utf8_file_data = utf8_encode($file_data); $utf8_file_data = mb_convert_encoding($file_data, "UTF-8", "UTF-16LE"); //$utf8_file_data = iconv("UTF-16LE","UTF-8",$file_data); $new_file_name = '/home/MYFILE_NEW.csv'; file_put_contents($new_file_name , $utf8_file_data ); ?> 选择文档根的所有//para后代,从而选择与上下文节点相同的文档中的所有para个元素
  • para选择上下文节点的.//para元素后代

此外,

  

para//的缩写。例如,/descendant-or-self::node()///para的缩写,因此将选择文档中的任何para元素

/descendant-or-self::node()/child::para开头的任何XPath表达式都从文档 root 节点开始,因此不能将其限制为上下文节点的后代。事实上,上下文节点被忽略,除了确定选择根节点的文档。

如果您想要选择上下文节点的后代(&#34;当前元素&#34;),如您所述,请从/开始。