PhantomJS 인스턴스의 '풀'을 관리하는 방법
하나의 인수, URL을 사용하고 해당 URL에서 해결 된 DOM을 나타내는 html을 반환하는 내부적으로 사용하기위한 웹 서비스를 계획하고 있습니다. 해결하면 웹 서비스가 먼저 해당 URL에서 페이지를 가져온 다음 PhantomJS를 사용하여 페이지를 '렌더링'한 다음 모든 DHTML, AJAX 호출 등이 실행 된 후 결과 소스를 반환합니다. 그러나 (내가 지금하고 있어요) 당 요청으로 팬텀을 시작하는 것은 방법 이 너무 부진. 내 웹 서비스에 대한 최신 호출을 제공하기 위해 항상 사용할 수있는 PhantomJS 인스턴스 풀을 갖고 싶습니다.
이전에 이런 종류의 작업을 한 적이 있습니까? 이 웹 서비스는 처음부터 풀 관리자 / http 프록시 서버를 작성하는 것보다 다른 사람의 작업을 기반으로합니다.
더 많은 컨텍스트 : 지금까지 본 2 개의 유사한 프로젝트와 각 프로젝트를 피한 이유를 나열하여 대신 PhantomJS 인스턴스 풀을 관리하는 것에 대한 질문이 생겼습니다.
jsdom-페이지에서 스크립트를 실행하기위한 훌륭한 기능이 있지만 브라우저 동작을 복제하려고 시도하지 않기 때문에 범용 "DOM 확인자"로 사용하면 결국 모든 종류의 엣지 케이스, 이벤트 호출 등을 처리하기위한 많은 추가 코딩. 제가 본 첫 번째 예제는 노드를 사용하여 설정 한 테스트 앱에 대해 body 태그의 onload () 함수를 수동으로 호출해야하는 것입니다. 깊은 토끼 굴의 시작 인 것 같았다.
Selenium-움직이는 부분이 너무 많기 때문에 수명이 긴 브라우저 인스턴스를 관리하기 위해 풀을 설정하는 것은 PhantomJS를 사용하는 것보다 더 복잡합니다. 매크로 기록 / 스크립팅 혜택이 필요하지 않습니다. 나는 브라우저로 해당 URL을 탐색하는 것처럼 웹 페이지를 가져오고 DOM을 해결하는 성능이 뛰어난 웹 서비스를 원합니다 (또는 이미지를 무시할 수있는 경우 더 빠름).
나는 PhantomJs 클라우드 서비스를 설정했고 그것은 당신이 요구하는 것을 거의 수행합니다. 작업하는 데 약 5 주가 걸렸습니다.
직면하게 될 가장 큰 문제 는 PhantomJs 의 알려진 메모리 누수 문제입니다 . 이 문제를 해결하는 방법은 호출 50 회마다 인스턴스를 순환하는 것입니다.
두 번째로 큰 문제는 페이지 당 처리가 CPU와 메모리 집약적이기 때문에 CPU 당 4 개 정도의 인스턴스 만 실행할 수 있다는 것입니다.
세 번째로 직면하게 될 가장 큰 문제는 PhantomJ가 페이지 완료 이벤트 및 리디렉션으로 인해 매우 이상하다는 것입니다. 페이지가 실제로 렌더링되기 전에 렌더링이 완료되었다는 알림을 받게됩니다. 이를 처리하는 방법에는 여러 가지가 있지만 안타깝게도 '표준'은 없습니다.
네 번째로 처리해야 할 가장 큰 문제는 nodejs와 phantomjs 간의 상호 운용성입니다. 고맙게도 선택할 수 있는이 문제 를 처리하는 npm 패키지가 많이 있습니다.
그래서 나는 편향되어 있다는 것을 알고 있지만 (내가 제안 할 솔루션을 작성한 것처럼) 가벼운 사용을 위해 무료 인 PhantomJsCloud.com 을 확인하는 것이 좋습니다 .
2015 년 1 월 업데이트 : 또 다른 (5 번째?) 큰 문제는 관리자 /로드 밸런서에서 요청 / 응답을 보내는 방법입니다. 원래 나는 PhantomJS의 내장 HTTP 서버를 사용하고 있었지만, 특히 최대 응답 크기와 관련하여 한계에 부딪 혔습니다. 요청 / 응답을 로컬 파일 시스템에 통신 회선으로 작성했습니다. * 서비스 구현에 소요 된 총 시간은 약 20 명의 인건비 문제를 나타냅니다. 작업 시간은 약 1000 시간입니다. * 그리고 참고로 다음 버전에 대한 완전한 재 작성을하고 있습니다 .... (진행 중)
비동기 자바 스크립트 라이브러리는 노드에서 작동하고있다 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);
});
});
프로젝트의 readme에서 전체 문서를queue
확인하십시오 .
내 석사 논문을 위해 정확히 이것을 수행 하는 라이브러리 phantomjs-pool 을 개발 했습니다. 그러면 PhantomJS 작업자에 매핑되는 작업을 제공 할 수 있습니다. 라이브러리는 작업 배포, 통신, 오류 처리, 로깅, 다시 시작 등을 처리합니다. 이 라이브러리는 백만 개 이상의 페이지를 크롤링하는 데 성공적으로 사용되었습니다.
예:
다음 코드는 0에서 9까지의 숫자에 대한 Google 검색을 실행하고 페이지의 스크린 샷을 googleX.png 로 저장 합니다. 4 개의 웹 사이트가 병렬로 크롤링됩니다 (4 명의 작업자 생성으로 인해). 스크립트는를 통해 시작됩니다 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
}
}
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
});
};
As an alternative to @JasonS great answer you can try PhearJS, which I built. PhearJS is a supervisor written in NodeJS for PhantomJS instances and provides an API via HTTP. It is available open-source from Github.
if you are using nodejs why not use selenium-webdriver
- run some phantomjs instance as webdriver
phantomjs --webdriver=port_number
for each phantomjs instance create PhantomInstance
function PhantomInstance(port) { this.port = port; } PhantomInstance.prototype.getDriver = function() { var self = this; var driver = new webdriver.Builder() .forBrowser('phantomjs') .usingServer('http://localhost:'+self.port) .build(); return driver; }
and put all of them to one array [phantomInstance1,phantomInstance2]
create dispather.js that get free phantomInstance from array and
var driver = phantomInstance.getDriver();
If you are using nodejs, you can use https://github.com/sgentle/phantomjs-node, which will allow you to connect an arbitrary number of phantomjs process to your main NodeJS process, hence, the ability to use async.js and lots of node goodies.
참고URL : https://stackoverflow.com/questions/9961254/how-to-manage-a-pool-of-phantomjs-instances
'code' 카테고리의 다른 글
Zend_Db_Select로 WHERE IN 절을 만드는 방법 (0) | 2020.11.16 |
---|---|
pdfminer를 라이브러리로 사용하는 방법 (0) | 2020.11.16 |
Meteor의 반응성은 배후에서 어떻게 작동합니까? (0) | 2020.11.15 |
Oracle의 기존 테이블에 자동 증가 기본 키 추가 (0) | 2020.11.15 |
Node.js 스크립트에 대한 적절한 해시 뱅 (0) | 2020.11.15 |