js2xml中的xpath是否允许我在选择时执行类似包含的操作?

时间:2016-06-06 10:07:56

标签: javascript xpath web-scraping scrapy js2xml

使用以下javascript代码抓取页面时,我想知道分配给myProp2的值。

myProp1={col1: 'firstName', col2: 'lastName'};
myProp2='data';

js2xml给出了一个xpath(),但它不允许我做像contains()这样的东西,我可以在Scrapy的xpath()中做。

我希望这样做:

xpath('//assign[contains(., "myProp2")]/right/*')

获取分配给myProp2的值,但看起来我在Scrapy中使用的contains()不可用。

我的解决方法是执行两次xpath()选择,然后并行迭代它们,并在获得标识符匹配后获取目标值:

import js2xml
from StringIO import StringIO
from lxml import etree

f = StringIO(
"""
<html>
<head>
<script type='text/javascript'>
  myProp1={col1: 'firstName', col2: 'lastName'};
  myProp2='data';
</script>
</head>
<body>
  This has test javascript.
</body>
</html>
""")
tree = etree.parse(f)
for script in tree.xpath('//script/text()'):
    jstree = js2xml.parse(script)
    idtree = jstree.xpath('//assign/left/*')
    valtree = jstree.xpath('//assign/right/*')
    for ids, vals in zip(idtree, valtree):
        id = js2xml.jsonlike.make_dict(ids)
        val = js2xml.jsonlike.make_dict(vals)
        if id == 'myProp2':
            print(val)

我会在很多地方这样做,所以提供像contains()这样的功能会有用。

可能在某种程度上,我只是不知道它。有没有办法在js2xml的xpath()中执行此操作?

更新:这最终成为一个基本的xpath表达式问题,而不是专门针对js2xml的问题。

对于其他读过这个有xpath初学者问题的人来说,我已经了解到有xpath测试站点在学习如何编写xpath表达式时有很大的帮助。

2 个答案:

答案 0 :(得分:1)

js2xml.parse返回表示JavaScript指令的lxml XML树。 但是分配的标识符在输出XML中不显示为文本节点,因此您通常不能直接在contains(., ...)节点上assign,但您可以在其某些子属性上执行。{/ p>

让我们先来看看js2xml给你的XML:

>>> s = '''
... myProp1={col1: 'firstName', col2: 'lastName'};
... myProp2='data';'''
>>> import js2xml
>>> jstree = js2xml.parse(s)
>>> print(js2xml.pretty_print(jstree))
<program>
  <assign operator="=">
    <left>
      <identifier name="myProp1"/>
    </left>
    <right>
      <object>
        <property name="col1">
          <string>firstName</string>
        </property>
        <property name="col2">
          <string>lastName</string>
        </property>
      </object>
    </right>
  </assign>
  <assign operator="=">
    <left>
      <identifier name="myProp2"/>
    </left>
    <right>
      <string>data</string>
    </right>
  </assign>
</program>

你可以看到“myProp2”:

  • name属性属性
  • 的值
  • identifier元素,
  • left元素的孩子
  • assign声明中。

您可以在contains()属性上使用@name,并在make_dict元素的子项(您想要的实际数据)上调用right

>>> js2xml.jsonlike.make_dict(
...     jstree.xpath(
...         '//assign[contains(left//@name, "myProp2")]/right/*')[0]
... )
'data'

答案 1 :(得分:1)

Paul对于如何使用contains()这个问题得到了最好的答案。

这里的另一个表达虽然提供了相同的结果,但没有使用contains(),而是使用一个谓词,可以更容易地看到匹配应该发生的位置。

//assign[left/identifier[@name="myProp1"]]/right/*