首页 文章

PhantomJS点击图片并等待加载

提问于
浏览
2

我正在尝试用PhantomJS进行页面自动化 . 我的目标是能够访问网站,单击图像,并在点击加载页面后继续使用其他代码 . 为了测试这个,我正在尝试编写一个脚本,该脚本将转到PhantomJS网站上的快速入门指南的URL,然后单击PhantomJS徽标将页面带到PhantomJS主页 . 还要在点击之前和之后呈现网站的图片以确保点击有效 . 这是我目前的代码:

var page = require('webpage').create();

page.open('http://phantomjs.org/quick-start.html', function(status) {
console.log(status);
page.render('websiteBeforeClick.png');
console.log(page.frameUrl); //check url before click

var element = page.evaluate(function() {
  return document.querySelector('img[alt="PhantomJS"]');
});

page.sendEvent('click', element.offsetLeft, element.offsetTop, 'left');

window.setTimeout(function () {
console.log(page.frameUrl); //check url after click
}, 3000);

console.log('element is ' + element); //check that querySelector() is returning an element
page.render('websiteAfterClick.png');
phantom.exit();
});

问题是我之前和之后的图片是一样的 . 这是我运行时的输出 .

success
 element is [object Object]

我从这里使用他们的sendEvent方法“http://phantomjs.org/api/webpage/method/send-event.html”,但我不确定它是否正常工作 .

另外为什么我的window.setTimeout()中的console.log(page.frameUrl)没有被执行?

我在PhantomJS网站上查看了他们的页面自动化示例 . 特别是这一个“https://github.com/ariya/phantomjs/blob/master/examples/imagebin.js” . 我注意到他们使用的例子

document.querySelector('input[name=disclaimer_agree]').click()

但当我用我的代码尝试它时,我收到了一个错误 .

document.querySelector('img[alt="PhantomJS"]').click();
TypeError: 'undefined' is not a function

编辑#1:

我将代码的结尾部分更改为:

page.sendEvent('click', element.offsetLeft, element.offsetTop, 'left');


window.setTimeout(function () {
  console.log(page.frameUrl);
  page.render('websiteAfterClick.png');
  phantom.exit();
}, 3000);

console.log('element is ' + element);
});

现在我的后图像是正确的 . 但现在我的问题是,如果我想继续我的代码,即点击网站上的另一个元素,我的新代码是否必须全部嵌套在超时函数内?

2 回答

  • 5

    有一个示例函数 phantom.waitFor(callback) ,我在following post上解释,它如下:

    phantom.waitFor = function(callback) {
      do {
        // Clear the event queue while waiting.
        // This can be accomplished using page.sendEvent()
        this.page.sendEvent('mousemove');
      } while (!callback());
    }
    

    这可以帮助简化代码并避免对window.setTimeout()的嵌套调用,因为等待预设的时间而不是等待元素变得可见,这些调用不是很可靠 . 一个例子如下:

    // Step 1: Open and wait to finish loading
    page.open('http://localhost/');
    phantom.waitFor(function() {return !page.loading;});
    
    // Step 2: Click on first panel and wait for it to show
    page.evaluate(function() { $("#activate-panel1").click(); });
    phantom.waitFor(function() {
       return page.evaluate(function() {return $("#panel1").is(":visible");})
    });
    
    // Step 3: Click on second panel and wait for it to show
    page.evaluate(function() { $("#activate-panel2").click(); });
    phantom.waitFor(function() {
       return page.evaluate(function() {return $("#panel2").is(":visible");})
    });
    console.log('READY!');
    phantom.exit();
    

    这将连续(即同步)加载每个面板,同时保持代码简单并避免嵌套回调 .

    希望它有意义 . 你也可以使用CasperJS作为替代品,它旨在使这个东西更简单 .

  • 0

    是的,您的新代码将从 setTimeout 回调内部调用 . 您可以直接嵌套代码或编写一个为您填充代码的函数,并在 setTimeout 中调用该函数 .

    function anotherClick(){
        // something
    }
    
    page.sendEvent('click', element.offsetLeft, element.offsetTop, 'left');
    
    window.setTimeout(function () {
      console.log(page.frameUrl);
      page.render('websiteAfterClick.png');
      anotherClick();
      phantom.exit();
    }, 3000);
    

    还有另一种方式 . 您也可以使用多个 setTimeout 完全编写它,但之后您无法对之前调用中的突发情况做出反应 .

    page.sendEvent('click', element.offsetLeft, element.offsetTop, 'left');
    
    window.setTimeout(function () {
      console.log(page.frameUrl);
      page.render('websiteAfterClick.png');
    }, 3000);
    
    window.setTimeout(function () {
      // some more actions
    }, 6000); // you cannot know if this delay is sufficient
    
    window.setTimeout(function () {
      phantom.exit();
    }, 9000); // you cannot know if this delay is sufficient
    

    如果你想做很多动作/导航步骤,我建议使用CasperJS .

相关问题