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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 04:17:17  来源:igfitidea点击:

casperJS How select element(s) by specific starting text with querySelector or querySelectorAll

javascriptcss-selectorscasperjsselectors-api

提问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 querySelectoror querySelectorAllmethods?

如何使用querySelectorquerySelectorAll方法找到它?

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

If you anyway know the text within the anchor, try clickLabel. This is what I use

如果您知道锚中的文本,请尝试 clickLabel。这是我使用的

this.clickLabel('Anchor_Text','a')

Where Anchor_Text is the complete text in the anchor

其中 Anchor_Text 是锚中的完整文本

Found here

这里找到

回答by Artjom B.

You seem to be confused with page context. Everything that is executed inside an evaluatecallback 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 aelement. Since the text that you use to select the aelement is inside of the belement, you need to either use .like shown above or select the belement 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)