我必须使用casperJS将一个文件上传到客户服务器,现在在上传之前我需要模仿两个特定链接上的点击,这些链接(简单HTML锚点)没有名称/ id /类...(非常丑陋的HTML代码)所以我有唯一的选择来选择它的文本内容。
如何使用querySelector
或querySelectorAll
方法找到它?
到目前为止,我可以提出以下(不成功的尝试):(
querySelector("a[text()='texttofind']");
querySelector("a[text='texttofind']");
querySelector("a[text=texttofind]");
在所有建议之后编辑
TITLE UPDATED 更具体地说我的问题似乎只与casperjs相关
PLATFORM - Windows 7的 - CasperJS版本1.1.0-beta3 - phantomjs版本1.9.7 - Python 2.7
所以,可能我太愚蠢了:(现在我发布了一个完整的例子,可悲的是不适合我:(
HTML主要索引
<html>
<head>
<title>TEST Main Page</title>
</head>
<frameset cols="100,100" >
<frame name="menu_a" src="menu_1.html">
<frame name="menu_b" src="menu_2.html">
</frameset>
</html>
HTML menu_1.html
<html>
<head>
<title>TEST Menu 1</title>
</head>
<body style="background-color:red;">
<h3>Menu 1</h3>
<select onchange="javscript:alert('test')" id="test" size="1" name="systemID">
<option value="0">---</option>
<option selected="selected" value="1">TestMenu1 </option>
<option value="17">TestMenu2 </option>
</select>
</body>
</html>
HTML menu_2.html
<html>
<head>
<title>TEST Menu 1</title>
</head>
<body style="background-color:orange;">
<h3>Menu 2</h3>
<a href="javascript:alert('test')"><b>clickhere </b></a>
<a href="javascript:alert('noclickhere')"><b>NoClickHere </b></a>
</body>
</html>
CasperJS脚本
对所有测试开始均等:
var casper = require('casper').create();
casper.start(serverName, function(){});
首次测试 - 按@ Ka0s
的建议点击标签casper.then(function(){
this.withFrame('menu_b', function(){
this.clickLabel('clickhere', 'a');
});
});
结果:
CasperError: Cannot dispatch mousedown event on nonexistent selector: xpath selector: //a[text()="test"]
/bin/casperjs/modules/casper.js:1355 in mouseEvent
/bin/casperjs/modules/casper.js:462 in click
/bin/casperjs/modules/casper.js:487 in clickLabel
/test.js:90
/bin/casperjs/modules/casper.js:1553 in runStep
/bin/casperjs/modules/casper.js:399 in checkStep
即使我清理字符串,删除测试代码上clickhere字符串末尾的空格,这也行不通。
第二次测试 - 由@ArtjomB建议的xPath
casper.then(function(){
this.withFrame('menu_b', function(){
this.evaluate(function(){
var element = __utils__.getElementByXPath("//a[starts-with(text(),'clickhere')]");
console.log(element);
});
});
});
结果:
remote message caught: undefined
所以我认为xPath找不到元素。
第三次测试 - 使用for循环的querySelectorAll,如@Brunis所建议
这是一个奇怪的beaviour,casperJS返回href的内容而不是对象 这似乎不是下面的代码错误,但我的实现或其他问题。
casper.then(function(){
this.withFrame('menu_b', function(){
this.evaluate(function(){
var as = document.querySelectorAll("a");
var match = "clickhere";
var elems = [];
for (var i=0; i<as.length; i++){
if (as[i].textContent === match) {
elems.push(as[i]);
}
}
console.log(elems[0]);
});
});
});
结果: 捕获的远程消息:javascript:alert(&#39; test&#39;)
我获得的href代码不是对象!如果我在小提琴中尝试这个例子,我会收到该对象,我可以在其上调用onclick()。
答案 0 :(得分:5)
这是一个简单的循环,与您想要的链接文本相匹配,并将它们添加到数组中:
html:
<div>
<a name="test">not this one</a>
<a name="test">not this one</a>
<a name="test">not this one</a>
<a name="test">not this one</a>
<a name="test">this one</a>
</div>
和脚本:
var as = document.querySelectorAll("a");
var match = "this one";
var elems = [];
for (var i=0; i<as.length; i++){
if (as[i].textContent === match) {
elems.push(as[i]);
}
}
现在你在elems数组中有匹配的元素。
答案 1 :(得分:3)
答案 2 :(得分:1)
querySelector(All)
不允许您指定您正在寻找的元素的内容。您必须单独查看每个锚点。
您可以尝试这样的事情:
var hrefs = document.getElementById('all_anchors').querySelectorAll('a');
for (var x=0;x<hrefs.length;x++) {
if (hrefs[x].innerHTML==text) {
alert(hrefs[x].href);
}
}
(JSFiddle)
答案 3 :(得分:1)
您似乎对页面上下文感到困惑。在evaluate
回调中执行的所有内容都是沙箱。它将无法看到外部或外部的变量在内部看不到变量。它们必须被专门传递,并且只能由基本原语组成。来自docs:
注意: evaluate函数的参数和返回值必须是一个简单的原始对象。经验法则:如果它可以通过JSON序列化,那就没关系了。
关于您的实际问题,您可以按照BoltClock的建议使用XPath。如您所见,CasperJS提供了可在页面上下文之外使用的XPath实用程序。
var x = require('casper').selectXPath;
casper.click(x("//a[starts-with(.,'clickhere')]"));
starts-with(string, string)
是一个XPath 1.0函数,用于检查某些字符串是否以另一个字符串开头。
如果您只想使用它来根据起始文本检索元素,然后对其执行其他操作,则可以在页面上下文中使用CasperJS的客户端实用程序。它提供了例如函数getElementByXPath
:
casper.evaluate(function(){
var element = __utils__.getElementByXPath("//a[starts-with(.,'clickhere')]");
// do something with element
});
CasperJS将__utils__
属性注入到每个页面的页面上下文中。
XPath中的.
是此元素内的完整文本,而text()
只会选择直接位于a
元素内的文本节点。由于您用于选择a
元素的文本位于b
元素内,因此您需要使用上面显示的.
或选择b
元素,然后去父母:
"//a/b[starts-with(text(),'clickhere')]/.."