使用以下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表达式时有很大的帮助。
答案 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/*