如何管理PhantomJS实例的"池"

Tri*_*daz 66 node.js web-scraping jsdom phantomjs

我正在计划内部使用的webservice,它接受一个参数,一个URL,并返回表示该URL中已解析 DOM的html .通过解决,我的意思是webservice将首先获取该URL的页面,然后使用PhantomJS"渲染"页面,然后在执行所有DHTML,AJAX调用等之后返回结果源.但是发动对每个请求的基础(这是我现在做)幽灵的方式过于缓慢.我宁愿拥有一个PhantomJS实例池,其中一个实例可用于为我的webservice提供最新的调用.

以前有没有做过这方面的工作?我宁愿将这个web服务基于其他人的工作,而不是从头开始为我自己编写一个池管理器/ http代理服务器.

更多上下文:我列出了迄今为止我见过的两个类似的项目,以及为什么我避免了每个项目,这导致了关于管理PhantomJS实例池的问题.

jsdom - 从我所看到它在页面上执行脚本具有很强的功能,但它不会尝试复制浏览器行为,因此如果我将它用作通用的"DOM解析器",那么它最终会成为很多额外的编码来处理各种边缘情况,事件调用等.我看到的第一个例子是必须为我使用node设置的测试应用程序手动调用body标签的onload()函数.这似乎是一个深深的兔子洞的开始.

Selenium - 它只有很多移动部件,因此设置一个池来管理长期存在的浏览器实例将比使用PhantomJS更复杂.我不需要它的任何宏录制/脚本功能.我只想要一个能够获得网页并解析它的DOM的web服务,就好像我用浏览器浏览到那个URL一样(如果我可以让它忽略图像等,甚至更快)

Jas*_*onS 62

我设置了一个PhantomJs Cloud Service,它几乎可以满足您的要求.我花了大约5个星期的工作时间.

您将遇到的最大问题是PhantomJs中已知的内存泄漏问题.我解决这个问题的方法是每50次调用循环我的实例.

您将遇到的第二大问题是每页处理非常CPU和内存密集,因此您每个CPU只能运行4个左右的实例.

你遇到的第三大问题是PhantomJs在页面完成事件和重定向方面非常古怪.您将被告知您的页面在实际呈现之前已完成呈现. 有很多方法可以解决这个问题,但遗憾的是没有任何"标准".

你要处理的第四大问题是nodejs和phantomjs之间的互操作,幸好有很多npm软件包可以解决这个问题.

所以我知道我有偏见(因为我写了我要建议的解决方案),但我建议你查看PhantomJsCloud.com,它可以免费使用.

2015年1月更新:我遇到的另一个(第五个?)大问题是如何从经理/负载均衡器发送请求/响应.最初我使用的是PhantomJS的内置HTTP服务器,但仍然遇到了它的局限性,特别是在最大响应大小方面.我最终将请求/响应写入本地文件系统作为通信线路. *实施服务所花费的总时间可能代表20个人周问题,也许是1000个小时的工作.*和FYI我正在为下一个版本进行完全重写....(正在进行中)


Mic*_*ley 17

JavaScript库的异步工作在节点和具有queue功能是这种东西非常方便:

queue(worker, concurrency)

使用指定的并发创建队列对象.添加到队列中的任务将并行处理(最高为并发限制).如果所有工作人员都在进行中,则该任务将排队等候,直到有一个工作可用.一旦工作人员完成任务,就会调用任务的回调.

一些伪代码:

function getSourceViaPhantomJs(url, callback) {
  var resultingHtml = someMagicPhantomJsStuff(url);
  callback(null, resultingHtml);
}

var q = async.queue(function (task, callback) {
  // delegate to a function that should call callback when it's done
  // with (err, resultingHtml) as parameters
  getSourceViaPhantomJs(task.url, callback);
}, 5); // up to 5 PhantomJS calls at a time

app.get('/some/url', function(req, res) {
  q.push({url: params['url_to_scrape']}, function (err, results) {
    res.end(results);
  });
});
Run Code Online (Sandbox Code Playgroud)

查看项目自述文件queue完整文档.

  • 你的朋友,差不多4年后,让我很头疼. (2认同)

Tho*_*orf 14

对于我的硕士论文,我开发了图书馆phantomjs-pool,正是这样做的.它允许提供作业,然后映射到PhantomJS工作人员.该库处理作业分发,通信,错误处理,日志记录,重新启动等等.该库已成功用于抓取超过一百万页.

例:

以下代码执行Google搜索数字0到9,并将页面屏幕截图保存为googleX.png.四个网站并行爬行(由于创建了四个工作人员).脚本通过启动node master.js.

master.js(在Node.js环境中运行)

var Pool = require('phantomjs-pool').Pool;

var pool = new Pool({ // create a pool
    numWorkers : 4,   // with 4 workers
    jobCallback : jobCallback,
    workerFile : __dirname + '/worker.js', // location of the worker file
    phantomjsBinary : __dirname + '/path/to/phantomjs_binary' // either provide the location of the binary or install phantomjs or phantomjs2 (via npm)
});
pool.start();

function jobCallback(job, worker, index) { // called to create a single job
    if (index < 10) { // index is count up for each job automatically
        job(index, function(err) { // create the job with index as data
            console.log('DONE: ' + index); // log that the job was done
        });
    } else {
        job(null); // no more jobs
    }
}
Run Code Online (Sandbox Code Playgroud)

worker.js(在PhantomJS环境中运行)

var webpage = require('webpage');

module.exports = function(data, done, worker) { // data provided by the master
    var page = webpage.create();

    // search for the given data (which contains the index number) and save a screenshot
    page.open('https://www.google.com/search?q=' + data, function() {
        page.render('google' + data + '.png');
        done(); // signal that the job was executed
    });

};
Run Code Online (Sandbox Code Playgroud)


TTT*_*TTT 5

作为@JasonS的替代品,您可以尝试我建造的PhearJS.PhearJS是一个用NodeJS编写的用于PhantomJS实例的管理程序,它通过HTTP提供API.它可以从Github开源.