javascript casperJS 如何使用 querySelector 或 querySelectorAll 通过特定的起始文本选择元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25281217/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
casperJS How select element(s) by specific starting text with querySelector or querySelectorAll
提问by Marco
I have to use casperJS to upload one file to a customer server, now before uploading I need to emulate a click on two specific links, these links (simple HTML anchors) don't have a name/id/class... (really ugly HTML code) so I have the only option to select it by it's text content.
我必须使用 casperJS 将一个文件上传到客户服务器,现在在上传之前我需要模拟对两个特定链接的点击,这些链接(简单的 HTML 锚点)没有名称/id/类...(真的丑陋的 HTML 代码)所以我唯一的选择是通过它的文本内容来选择它。
How can I find it using the querySelector
or querySelectorAll
methods?
如何使用querySelector
或querySelectorAll
方法找到它?
So far, I could come up with the following (unsuccessful attempts) :(
到目前为止,我可以想出以下(不成功的尝试):(
querySelector("a[text()='texttofind']");
querySelector("a[text='texttofind']");
querySelector("a[text=texttofind]");
EDIT AFTER ALL SUGGESTION
在所有建议后编辑
TITLE UPDATEDto be more specific about my problem that seem related only to casperjs
标题已更新,以更具体地说明我似乎仅与 casperjs 相关的问题
PLATFORM- Windows 7 - CasperJS version 1.1.0-beta3 - phantomjs version 1.9.7 - Python 2.7
平台- Windows 7 - CasperJS 版本 1.1.0-beta3 - phantomjs 版本 1.9.7 - Python 2.7
so, probably i'm too dumb :( now i post a complete example that sadly don't work for me :(
所以,可能我太笨了:(现在我发布了一个完整的例子,可惜对我不起作用:(
HTML main index
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 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 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 script
CasperJS 脚本
start equal for all tests:
对于所有测试开始相等:
var casper = require('casper').create();
casper.start(serverName, function(){});
first test - clicklabel as suggested by @Ka0s
第一个测试 - @Ka0s 建议的 clicklabel
casper.then(function(){
this.withFrame('menu_b', function(){
this.clickLabel('clickhere', 'a');
});
});
result:
结果:
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
this not work even if i cleanup the string removing blank spaces at the end of the clickhere string on my test code.
即使我清除了测试代码上 clickhere 字符串末尾的空格,这也不起作用。
second test - xPath as sugggested by @ArtjomB
第二个测试-@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);
});
});
});
result:
结果:
remote message caught: undefined
so i suppose that the xPath fail finding the element.
所以我想 xPath 找不到元素。
Third test - querySelectorAll with for loop as suggested by @Brunis
第三个测试 - querySelectorAll 和 @Brunis 建议的 for 循环
This is a strange beaviour, casperJS return the content of href instead the object this not seem an error on below code but a problem on my implementation or something else.
这是一个奇怪的行为,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]);
});
});
});
Result: remote message caught: javascript:alert('test')
结果:捕获到远程消息:javascript:alert('test')
i obtain the href code not the object! if i try this example in a fiddle, i receive the object and i can call onclick() on it.
我获得的是href代码而不是对象!如果我在小提琴中尝试这个例子,我会收到这个对象,我可以在它上面调用 onclick() 。
回答by Brunis
Here's a simple loop that matches the text of the link you want and adds them to an array:
这是一个简单的循环,它匹配您想要的链接的文本并将它们添加到数组中:
the html:
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>
and the script:
和脚本:
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]);
}
}
now you have the matched elements in the elems array.
现在您在 elems 数组中有匹配的元素。
fiddle here: http://jsfiddle.net/0pLd8s9r/
在这里小提琴:http: //jsfiddle.net/0pLd8s9r/
回答by Ka0s
回答by Artjom B.
You seem to be confused with page context. Everything that is executed inside an evaluate
callback is sandboxed. It will cannot see variables on the outside or the outside cannot see variables on the inside. They have to be specifically passed and can only be composed of basic primitives. From the docs:
您似乎对页面上下文感到困惑。在evaluate
回调中执行的所有内容都被沙盒化。它将看不到外部的变量或外部看不到内部的变量。它们必须特别传递并且只能由基本原语组成。从文档:
Note:The arguments and the return value to the evaluate function must be a simple primitive object. The rule of thumb: if it can be serialized via JSON, then it is fine.
注意:evaluate 函数的参数和返回值必须是一个简单的原始对象。经验法则:如果它可以通过 JSON 序列化,那就没问题了。
Regarding your actual question, you can use XPath as suggested by BoltClock. As you have seen, CasperJS provides the XPath utility which is usable outside of the page context.
关于您的实际问题,您可以按照 BoltClock 的建议使用 XPath。如您所见,CasperJS 提供了可在页面上下文之外使用的 XPath 实用程序。
var x = require('casper').selectXPath;
casper.click(x("//a[starts-with(.,'clickhere')]"));
starts-with(string, string)
is an XPath 1.0 function to check if some string starts with another string.
starts-with(string, string)
是一个 XPath 1.0 函数,用于检查某个字符串是否以另一个字符串开头。
If you want to use this only to retrieve the element based on the starting text and then do something else with it, you can use the client utils of CasperJS for that inside the page context. It provides for example the function getElementByXPath
:
如果你只想使用它来检索基于起始文本的元素,然后用它做其他事情,你可以在页面上下文中使用 CasperJS 的客户端工具。它提供了例如功能getElementByXPath
:
casper.evaluate(function(){
var element = __utils__.getElementByXPath("//a[starts-with(.,'clickhere')]");
// do something with element
});
The __utils__
property is injected by CasperJS into the page context for every page.
该__utils__
属性由 CasperJS 注入到每个页面的页面上下文中。
The .
in the XPath is the complete text that is inside this element whereas text()
would only select text nodes that are directly inside the a
element. Since the text that you use to select the a
element is inside of the b
element, you need to either use .
like shown above or select the b
element and then go to the parent:
将.
在XPath是该元素中,而完整的文本text()
将仅选择直接在内部文本节点a
元素。由于用于选择a
元素的文本位于元素内部,因此b
您需要使用.
如上所示或选择b
元素然后转到父元素:
"//a/b[starts-with(text(),'clickhere')]/.."
回答by icke
querySelector(All)
will not let you specify the content of the element you're looking for. You would have to look into each anchor individually.
querySelector(All)
不会让您指定要查找的元素的内容。您必须单独查看每个锚点。
You could try something like this:
你可以尝试这样的事情:
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)
( JSFiddle)