在 Casper 重复函数之外无法访问数组

Array is not accessible outside of Casper repeat function

我的目标是获取招聘网站的每份工作 link,按照工作 link 转到每个工作详细信息页面,通过 CASPERJS 下载并保存详细信息 html . 由于每次我们在作业 link 和作业详细信息页面之间来回移动时,每个作业 link 的 ID 都会发生变化,因此我每次都需要在 casper.repeat 下获取所有作业 ID。但是 NoOfLink 数组在 repeat 函数之外变空了[我在代码中评论了那部分]。问题是什么?

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

var noOfRecordsToLoop = 0;
var TotalNoofNullElement = 0;
var NoOfLink = [];

var x = require('casper').selectXPath;

casper.echo('\nStart loding site......');

//---------------------------------------------Load and Scroll the site---------------------------------------//

casper.start('https://........../...../.......Careers/');

casper.wait(10000, function () {
    //---------Total no of Job posting------//

    var noOfRecords = this.fetchText(x('//*[@id="...........................jobProfile......"]'));
    noOfRecordsToLoop = noOfRecords.replace(/[^0-9]/g, "");
    var totalNoOfPage = Math.ceil(parseInt(noOfRecords) / 50);

    casper.echo('\nStart scrolling site......');

    casper.repeat(totalNoOfPage, function () {
        this.scrollToBottom(); //-----------------------Scroll down
        casper.wait(10000, function () {})
    })

})

//------------------------------------------------Load and Scroll the site---------------------------------------//


casper.then(function () {
    //-----------------------------------------Get all the link elements  --------------------------//

    var countForLink = 0;
    var numTimesForRpt = noOfRecordsToLoop;
    var numTimes = noOfRecordsToLoop;

    casper.repeat(numTimesForRpt, function () {

        RetElement = this.evaluate(function () {
            var startingRow = '//*[contains(@id, "...-uid-")]'
                var element = __utils__.getElementByXPath(startingRow).getAttribute('id');
            return element;
        });

        var count = RetElement.replace(/[^0-9]/g, "");

        casper.repeat(numTimes, function () {
            var MatchElements = this.evaluate(function (count) {
                    var xp = '//*[contains(@id, "...-uid-' + count + '")]'
                        var element = __utils__.getElementByXPath(xp).getAttribute('id');
                    return element;
                }, count++);

            if (!MatchElements) {
                TotalNoofNullElement = TotalNoofNullElement + 1
            } else {
                NoOfLink.push(MatchElements);
            }

            //**Here array elements are accessible**
            for (var k = 0; k < NoOfLink.length; k++) {
                this.echo(NoOfLink[k]);
            }

        });

        //**But here array elements are not accessible outside of repeat** function
        this.echo("Size of array is" + NoOfLink.length);

        for (var q = 0; q < NoOfLink.length; q++) {
            this.echo(NoOfLink[q]);
        }

        //-----------------------------------------Get all the link elements----------------------------//

        //------------------------------------Go to the Job Detail Page Extract HTML and Save---------------------------//

        this.echo("\n Inside repeat to Generate HTML");
        var num = NoOfLink[countForLink];
        this.echo("\nLink id is " + NoOfLink[countForLink]);
        num = parseInt(num.replace(/[^0-9]/g, ""));
        this.echo("\nNum is " + num);

        //-----------------Click to go to the Job Detail Page------------------//

        casper.thenClick(x('//*[@id="..-uid-' + num + '"]/div/div'));

        casper.wait(5000, function getJobDetail() {

            var content = this.getElementInfo(x(".//*[contains(@id,'......t-uid-')]")).html;
            var divStart = '<div id="extrdHtml">'
                var divEnd = '</div>'
                var body = divStart + content + divEnd

                this.echo("\nContent of Job detail :" + body);

            var fs = require('fs');

            fs.write('extractedJob' + NoOfLink[countForLink] + '.html', body, 'w');

            this.echo("\nFile saved");

            //------------------------------------Go to the Job Detail Page Extract HTML and Save---------------------------//

        }); //casper.wait

        casper.back();

        casper.wait(5000);

        countForLink++

    }); //casper.repeat

}); //casper.then

//-------------------------------------------Get all the link elements------------------------------//

casper.run();

有两个重复循环。

  1. casper.repeat(numTimesForRpt, function () { - 这是主外循环,第二个循环所在的地方。
  2. casper.repeat(numTimes, function () – 我在哪里获取 link 并填充 NoOfLink 数组。我试图在第二个循环之外(在主外循环内)获取数组元素值,但它不起作用。

所有then*wait*函数都是异步步函数。如果您调用它们,您将安排一个在当前步骤结束时执行的步骤。 casper.repeat()uses casper.then() 的函数,因此也是异步的。 casper.repeat() 之后的每个同步代码都将在 repeat 回调的内容之前执行。

您有两个选择:

  1. casper.repeat() 之后的所有内容包装在 casper.then() 中以使其异步或
  2. 如果 repeat 的回调不需要像您的案例 那样异步评估 ,则使用普通的同步循环而不是 repeat

顺便说一句,您通常可以通过使用 CasperJS 提供的辅助函数来减少代码量。例如,您不需要仅使用 evaluate() 来通过 XPath 获取某些元素的 id 属性。您可以使用 casper.getElementsAttribute().

示例:

var count = RetElement.replace(/[^0-9]/g, "");

for(var i = count; i < (numTimes + count); i++) {
    var MatchElements = this.getElementsAttribute(x('//*[contains(@id, "...-uid-' + i + '")]'), 'id');

    if (!MatchElements) {
        TotalNoofNullElement = TotalNoofNullElement + 1
    } else {
        NoOfLink.push(MatchElements);
    }

    //**Here array elements are accessible**
    for (var k = 0; k < NoOfLink.length; k++) {
        this.echo(NoOfLink[k]);
    }
}