【问题标题】:casperJS How select element(s) by specific starting text with querySelector or querySelectorAllcasperJS 如何使用 querySelector 或 querySelectorAll 通过特定的起始文本选择元素
【发布时间】:2014-10-06 12:30:15
【问题描述】:

我必须使用 casperJS 将一个文件上传到客户服务器,现在在上传之前我需要模拟点击两个特定链接,这些链接(简单的 HTML 锚点)没有名称/id/类.. . (真的很丑的 HTML 代码)所以我只能通过它的文本内容来选择它。

如何使用querySelectorquerySelectorAll 方法找到它?

到目前为止,我可以想出以下(不成功的尝试):(

querySelector("a[text()='texttofind']");
querySelector("a[text='texttofind']");
querySelector("a[text=texttofind]");

所有建议后编辑

标题已更新 更具体地说明我似乎只与 casperjs 相关的问题

平台 - 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 建议的 clicklabel

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 找不到元素。

第三次测试 - querySelectorAll 与@Brunis 建议的 for 循环

这是一个奇怪的行为,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('test')

我获得的是 href 代码而不是对象!如果我在小提琴中尝试这个例子,我会收到对象,我可以在它上面调用 onclick()。

【问题讨论】:

  • 文本内容不是其父节点的属性;它本身就是一个节点类型。您将无法使用querySelector 执行此操作。您必须使用 JS 来检查每个 a 元素的文本内容,然后在找到匹配项后对其进行操作。
  • Palpatim 是对的,先找到所有的 a 元素,然后在一个简单的 for 循环中过滤掉不需要的元素。
  • 为什么不用 XPath 来代替?
  • 谢谢大家! @BoltClock 我如何在 casperJS 评估中使用 xPath?我无法使用它.. 我试试这个: var xPath = require('casper').selectXPath; this.evaluate(function(){element = xPath('//a[[text()="SampleText"]'); });但似乎不起作用:(我将 xPath 作为空引用
  • 你从“我的代码”得到的错误不是我的代码,是你的 onchange 事件触发了警报。

标签: javascript css-selectors casperjs selectors-api


【解决方案1】:

这是一个简单的循环,它匹配您想要的链接文本并将它们添加到数组中:

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 数组中找到了匹配的元素。

在这里提琴:http://jsfiddle.net/0pLd8s9r/

【讨论】:

  • 谢谢,这似乎在浏览器上工作,但 casperJs 在你的代码上有一个奇怪的行为。如果我在浏览器(firefox)上执行 console.log(elems[0]) 它会返回 [a] 对象,因此我可以执行 elems[0].onclick() 来触发点击事件。但如果我在 casperJs 上做同样的事情,我会收到 href 而不是对象上的内容!
  • 从您在 html 中的选择中删除 onchange="javascript:alert('test')"
【解决方案2】:

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

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

其中 Anchor_Text 是锚点中的完整文本

找到here

【讨论】:

    【解决方案3】:

    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)

    【讨论】:

      【解决方案4】:

      您似乎对页面上下文感到困惑。在evaluate 回调中执行的所有内容都是沙盒。它将看不到外部的变量或外部无法看到内部的变量。它们必须经过专门传递,并且只能由基本原语组成。来自docs

      注意:评估函数的参数和返回值必须是简单的原始对象。经验法则:如果可以通过 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
      });
      

      __utils__ 属性由 CasperJS 注入到每个页面的页面上下文中。

      XPath 中的. 是该元素内的完整文本,而text() 只会选择直接在a 元素内的文本节点。由于用于选择 a 元素的文本位于 b 元素内,因此您需要使用 .(如上所示)或选择 b 元素然后转到父元素:

      "//a/b[starts-with(text(),'clickhere')]/.."
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-01-13
        • 2022-11-26
        • 2019-04-27
        • 1970-01-01
        • 2014-01-07
        • 2018-05-13
        • 1970-01-01
        • 2010-11-27
        相关资源
        最近更新 更多