code

PhantomJS 인스턴스의 '풀'을 관리하는 방법

codestyles 2020. 11. 15. 11:20
반응형

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

  1. run some phantomjs instance as webdriver phantomjs --webdriver=port_number
  2. 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]

  3. 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

반응형