【问题标题】:Best practices to execute faster a CasperJS script that scrapes thousands of pages更快执行抓取数千页的 CasperJS 脚本的最佳实践
【发布时间】:2018-03-04 10:25:14
【问题描述】:

我编写了一个运行良好的 CasperJS 脚本,只是它需要(非常非常)很长的时间来抓取页面。

简而言之,这是伪代码:

  1. 我的功能来抓取元素
  2. 我的casper.start() 开始导航并登录
  3. casper.then() 我循环遍历一个数组并存储我的链接
  4. casper.thenOpen() 打开每个链接并调用我的函数来报废。

它可以完美地(并且足够快)抓取一堆链接。但是当涉及到数千个时(现在我正在运行包含 100K 链接数组的脚本),执行时间是无穷无尽的:前 10K 链接在 3h54m10s 中被废弃,接下来的 10K 在 2h18m27s 中被废弃。

我可以稍微解释一下这两个 10K 批次之间的区别:第一个包括带有 100K 链接的数组的循环和存储。从这一点开始,脚本只打开页面来废弃它们。但是,我注意到阵列在大约 30 分钟后准备就绪,因此无法准确解释时间间隔。

我已将我的casper.thenOpen() 放在 for 循环中,希望在每个新链接构建并存储在数组中之后,会发生报废。现在,我确定我失败了,但它会在性能方面改变什么吗?

这是我现在想到的唯一线索,如果有人愿意分享他/她的最佳实践以显着减少脚本执行的运行时间(应该不难!),我将非常感激。

编辑#1

下面是我的代码:

var casper = require('casper').create();
var fs = require('fs');

// This array maintains a list of links to each HOL profile

// Example of a valid URL: https://myurl.com/list/74832
var root = 'https://myurl.com/list/';
var end = 0;
var limit = 100000;
var scrapedRows = [];

// Returns the selector element property if the selector exists but otherwise returns defaultValue

function querySelectorGet(selector, property, defaultValue) {
  var item = document.querySelector(selector);
  item =  item ? item[property] : defaultValue;
  return item;
}

// Scraping function
function scrapDetails(querySelectorGet) {

  var info1 = querySelectorGet("div.classA h1", 'innerHTML', 'N/A').trim()
  var info2 = querySelectorGet("a.classB span", 'innerHTML', 'N/A').trim()
  var info3 = querySelectorGet("a.classC span", 'innerHTML', 'N/A').trim()

  //For scraping different texts of the same kind (i.e: comments from users)
  var commentsTags = document.querySelectorAll('div.classComments');
  var comments =  Array.prototype.map.call(commentsTags, function(e) {
    return e.innerText;
  })

// Return all the rest of the information as a JSON string
  return {
    info1: info1,
    info2: info2,
    info3: info3,

    // There is no fixed number of comments & answers so we join them with a semicolon
    comments : comments.join(' ; ')
  };
}

casper.start('http://myurl.com/login', function() {
this.sendKeys('#username', 'username', {keepFocus: true});
this.sendKeys('#password', 'password', {keepFocus: true});
this.sendKeys('#password', casper.page.event.key.Enter, {keepFocus: true});

  // Logged In
  this.wait(3000,function(){

    //Verify connection by printing welcome page's title
    this.echo( 'Opened main site titled: ' + this.getTitle());
  });
});

casper.then( function() {

  //Quick summary
  this.echo('# of links : ' + limit);
  this.echo('scraping links ...')

  for (var i = 0; i < limit; i++) {

    // Building the urls to visit
    var link = root + end;

        // Visiting pages...
        casper.thenOpen(link).then(function() {
            // We pass the querySelectorGet method to use it within the webpage context
            var row = this.evaluate(scrapDetails, querySelectorGet);
            scrapedRows.push(row);

            // Stats display
            this.echo('Scraped row ' + scrapedRows.length + ' of ' + limit);
        });

    end++;
  }

});

casper.then(function() {
  fs.write('infos.json', JSON.stringify(scrapedRows), 'w')
});

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

【问题讨论】:

    标签: arrays performance time casperjs execution


    【解决方案1】:

    在这一点上,我的问题可能比答案多,但让我们试试吧。

    您使用 CasperJS 而不是 Curl 有什么特别的原因吗?例如,如果您要抓取使用 Javascript 的网站,我可以理解对 CasperJS 的需求。或者你想截屏。否则,我可能会将 Curl 与 PHP 或 Python 等脚本语言一起使用,并利用内置的 DOM 解析函数。 你当然可以使用像 Scrapy 这样的专用抓取工具。有很多可用的工具。

    然后是“显而易见”的问题:您真的需要那么大的数组吗?您要实现的目标尚不清楚,我假设您希望将提取的链接存储到数据库或其他东西。不能小批量拆分流程吗?

    应该有帮助的一件事是通过声明一个固定大小的数组分配足够的内存,即: var theArray = new Array(1000);

    不断调整数组大小必然会导致性能问题。每次向数组中添加新项目时,都必须在后台进行昂贵的内存分配操作,并在循环运行时重复执行。

    由于您没有显示任何代码,因此我们无法提出有意义的改进建议,只是概括性的建议。

    【讨论】:

    • 感谢您的回答@Anonymous!我没有考虑过 Curl,因为我只知道 PhantomJS、CasperJS 和 SlimmerJS 是最流行的网页抓取语言。根据您的回答,我认为 Curl 可能会成功,所以我一定会试一试。我使用 import.io 进行抓取,但我负担不起他们的计划,所以我决定自学 CasperJS。我需要抓取成千上万的网页,所以在某些时候,我需要大型数组来存储 URL。我没有分配内存,所以再次在这里,我也会尝试并比较结果。我已经用我的代码更新了我的问题;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-10
    • 1970-01-01
    • 2021-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多