当我打开太多页面并忽略最后一个URL时,PhantomJS崩溃了

PhantomJS crashes when I open too many pages and ignores the last URL

本文关键字:URL 最后一个 PhantomJS 崩溃 太多      更新时间:2023-09-26

系统:Windows 8.1 64位,带有二进制文件,版本2.0

我有一个.txt文件,每行有一个URL,我阅读每一行并打开页面,搜索特定的URL。match(代码中由于隐私原因更改了域名)-如果找到,打印找到的JSON,中止请求,卸载页面。我的.txt文件包含12500个链接,出于测试目的,我将其分成前10/100/500个url。

问题1:如果我尝试10个url,它打印9,然后使用40-50%的cpu

问题2:如果我尝试100个url,它打印98,由于任何原因使用40-50%的cpu,然后在2-3分钟后崩溃。

问题3:同样适用于98个链接(打印96个,使用40-50%的cpu,然后也崩溃)和500个链接

txt文件:https://www.dropbox.com/s/eeiy12ku5k15226/sitemaps.7z?dl=1

98,100和500链接的崩溃转储:https://www.dropbox.com/s/ilvbg8lv1bizjti/Crash%20dumps.7z?dl=1

console.log('Hello, world!');
var fs = require('fs');
var stream = fs.open('100sitemap.txt', 'r');
var line = stream.readLine();
var webPage = require('webpage');
var i = 1;
while(!stream.atEnd() || line != "") {
     //console.log(line);
    var page = webPage.create();
    page.settings.loadImages = false;
    page.open(line, function() {});
    //console.log("opened " + line);
    page.onResourceRequested = function(requestData, request) {
        //console.log("BEFORE: " +requestData.url);
        var match = requestData.url.match(/example.com'/ac/g)
        //console.log("Match: " + match);
        //console.log("Line: " + line);
        //console.log("Match: " + match);
        if (match != null) {
            var targetString = decodeURI(JSON.stringify(requestData.url));
            var klammerauf = targetString.indexOf("{");
            var jsonobjekt = targetString.substr(klammerauf,   (targetString.indexOf("}") - klammerauf) + 1);
            targetJSON = (decodeURIComponent(jsonobjekt));
            console.log(i);
            i++;
            console.log(targetJSON);
            console.log("");
            request.abort();
            page.close();
        }
    };
    var line = stream.readLine();
}
//console.log("File closed");
//stream.close();

并发请求

你真的不应该在循环中加载页面,因为循环是同步结构,而page.open()是异步结构。这样做,您将遇到内存消耗飙升的问题,因为所有url都是同时打开的。如果列表中有20个或更多的url,这将是一个问题。

函数层次范围

另一个问题是JavaScript具有函数级作用域。这意味着即使在while块内部定义page变量,它也是全局可用的。由于它是全局定义的,因此您会遇到PhantomJS的异步特性的问题。page.onResourceRequested函数定义中的page很可能与用于打开触发回调的URL的page不同。点击这里了解更多。一个常见的解决方案是使用IIFE将page变量绑定到一个迭代,但是您需要重新考虑整个方法。

征战

您还会有内存泄漏,因为当page.onResourceRequested事件中的URL不匹配时,您不会放弃请求,也不会清理页面实例。您可能希望对所有url都这样做,而不仅仅是匹配您的特定正则表达式的url。

容易解决

一个快速的解决方案是定义一个函数进行一次迭代,并在当前迭代结束时调用下一次迭代。您还可以为所有请求重用一个page实例。

var page = webPage.create();
function runOnce(){
    if (stream.atEnd()) {
        phantom.exit();
        return;
    }
    var url = stream.readLine();
    if (url === "") {
        phantom.exit();
        return;
    }
    page.open(url, function() {});
    page.onResourceRequested = function(requestData, request) {
        /**...**/
        request.abort();
        runOnce();
    };
}
runOnce();