0

使用以下 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 表达式时很有帮助。

4

2 回答 2

1

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

我们先来看看 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'
于 2016-06-06T11:13:54.290 回答
1

对于如何为此使用 contains() 的问题,Paul 给出了最佳答案。

这是另一个表达式,尽管它提供了相同的结果,但不使用 contains() 而是使用谓词,以便更容易地查看匹配应该发生的位置。

//assign[left/identifier[@name="myProp1"]]/right/*
于 2016-06-06T19:43:16.153 回答