【问题标题】:Changing a link dynamically in PhantomJS and clicking it to scrape the page在 PhantomJS 中动态更改链接并单击它以抓取页面
【发布时间】:2015-11-07 12:16:35
【问题描述】:

这几天我一直在尝试解决这个问题,但一直未能实现。

有这个网页,如果我需要删除所有可用的记录,我注意到如果我用 firebug 或浏览器的检查器修改分页链接,我可以获得我需要的所有记录,例如,这是原文链接:

<a href="javascript:gReport.navigate.paginate('paginator_min_row=16max_rows=15rows_fetched=15')">

如果我像这样修改那个链接

<a href="javascript:gReport.navigate.paginate('paginator_min_row=1max_rows=5000rows_fetched=5000')">

然后单击浏览器上的分页按钮(包含我刚刚更改的链接的相同按钮)我能够从该站点获取我需要的所有记录(大多数时候“行”没有不能大于 4000,我用 5000 以防万一)

由于我必须每天手动处理该文件,我想也许我可以使用 PhantomJS 自动化该过程并在一次运行中获取整个页面,而无需查找该链接然后更改它,因此为了修改分页链接并获取我正在使用以下代码的所有记录:

var page = require('webpage').create();
var fs = require('fs');
page.open('http://testingsite1.local', function () {
    page.evaluate(function(){
        $('a[href="javascript:gReport.navigate.paginate(\'paginator_min_row=16max_rows=15rows_fetched=15\')"]').first().attr('href', 'javascript:gReport.navigate.paginate(\'paginator_min_row=1max_rows=5000rows_fetched=5000\')').attr('id','clickit');
    $('#clickit')[0].click();
    });

    page.render('test.png');
    fs.write('test.html', page.content, 'w');
    phantom.exit();
});

请注意,该网站上有两个分页链接,因为我使用 jquery 的“.first()”只选择第一个。

此外,由于所需的链接没有任何标识符,我使用它自己的链接选择它,然后将其更改为我需要的,最后我将“clickit”ID 添加到它以供以后调用。

现在,这是我的问题:

我不确定为什么它不起作用,如果我运行代码它只获取第一页,在检查了请求的页面源代码后,我确实看到 href 链接已更改为我想要的,但是它只是没有被调用,我对可能出现的问题有两种不同的理论

  1. 修改后的 href 没有得到“点击”,因此页面没有得到更新

  2. href 确实被点击了,但由于页面需要几秒钟来动态加载所有结果,我只能转储 Phantomjs 看到的第一页

你们怎么看?


[2015 年 11 月 6 日更新] 好的,所以@Artjomb 和@pguardiario 提供的答案为我指明了一个新方向:

  1. 我需要更多关于发生了什么的调试信息
  2. 我需要直接调用 gReport.navigate.paginate 函数

遗憾的是我只是缺乏正确使用 PhantomJS 的经验,其他几个示例表明我可以使用 CasperJS 实现我想要的,所以我尝试了一下,这是我在几个小时后制作的

var utils = require('utils');
var fs = require('fs');
var url = 'http://testingsite1.local';

var casper = require('casper').create({
  verbose: true,
  logLevel: 'debug'
});

casper.on('error', function(msg, backtrace) {
  this.echo("=========================");
  this.echo("ERROR:");
  this.echo(msg);
  this.echo(backtrace);
  this.echo("=========================");
});

casper.on("page.error", function(msg, backtrace) {
  this.echo("=========================");
  this.echo("PAGE.ERROR:");
  this.echo(msg);
  this.echo(backtrace);
  this.echo("=========================");
});

casper.start(url, function() {
  var url = this.evaluate(function() {
    $('a[href="javascript:gReport.navigate.paginate(\'paginator_min_row=16max_rows=15rows_fetched=15\')"]').attr('href', 'javascript:gReport.navigate.paginate(\'paginator_min_row=1max_rows=5000rows_fetched=5000\')').attr('id', 'clicklink');
    return gReport.navigate.paginate('paginator_min_row=1max_rows=5000rows_fetched=5000');
  });
});

casper.then(function() {
  this.waitForSelector('.nonexistant', function() {
    // Nothing here
  }, function() {
    //page load failed after 5 seconds
    this.capture('screen.png');
    var html = this.getPageContent();
    var f = fs.open('test.html', 'w');
    f.write(html);
    f.close();
  }, 50000);
});

casper.run(function() {
  this.exit();
});

请温柔一点,因为我知道这段代码很烂,我不是 Javascript 专家,实际上我对它知之甚少,我知道我应该等待一个元素出现,但它在我的测试中根本不起作用我仍然在没有从 AJAX 请求更新的情况下获取页面。

最后我等了很长时间(50 秒)让 AJAX 请求显示在页面上,然后转储 HTML

哦!并且直接调用该函数效果很好!

【问题讨论】:

  • 直接做gReport.navigate.paginate('paginator_min_row=1max_rows=5000rows_fetched=5000')不是更有意义吗?
  • @pguardiario 好主意!事实上,您已经为我指明了一个新方向:目前我在顶部添加了 CasperJS,我正在体验一定程度的成功,我会用它来更新主要问题

标签: javascript jquery click phantomjs


【解决方案1】:
  1. href 确实被点击了,但由于页面需要几秒钟来动态加载所有结果,我只能转储 Phantomjs 看到的第一页

通过将渲染、写入和退出调用包装在setTimeout 中并尝试不同的超时,很容易检查是否是这样:

page.open('http://testingsite1.local', function () {
    page.evaluate(function(){
        $('a[href="javascript:gReport.navigate.paginate(\'paginator_min_row=16max_rows=15rows_fetched=15\')"]').first().attr('href', 'javascript:gReport.navigate.paginate(\'paginator_min_row=1max_rows=5000rows_fetched=5000\')').attr('id','clickit');
        $('#clickit')[0].click();
    });

    setTimeout(function(){
        page.render('test.png');
        fs.write('test.html', page.content, 'w');
        phantom.exit();
    }, 5000);
});

如果真的只是超时问题,那么您应该使用waitFor() function 等待特定条件,例如“加载所有元素”或“加载该类型的 x 个元素”。

  1. 修改后的 href 没有得到“点击”,因此页面没有得到更新

这有点棘手。您可以收听onConsoleMessageonErroronResourceErroronResourceTimeout 事件(Example),看看页面是否有错误。其中一些错误可以通过您可以在 PhantomJS 中执行的操作来修复:Function.prototype.bind not availableHTTPS site/resources cannot be loaded

还有其他方法可以点击更可靠的内容,例如this one

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 2021-06-18
    • 1970-01-01
    相关资源
    最近更新 更多