2012-04-01 12 views
65

मैं आंतरिक रूप से अपने स्वयं के उपयोग के लिए एक webservice की योजना बना रहा हूं जो एक तर्क, एक यूआरएल लेता है, और का प्रतिनिधित्व करने वाले एचटीएमएल को उस URL से हल किया गया है। हल करके मेरा मतलब है कि webservice पहले उस यूआरएल पर पेज प्राप्त करेगा, फिर पृष्ठ को 'रेंडर' करने के लिए फ़ैंटॉमजेएस का उपयोग करें, और उसके बाद परिणामी स्रोत को सभी डीएचटीएम के बाद वापस करें, AJAX कॉल इत्यादि निष्पादित किए जाते हैं। हालांकि प्रति अनुरोध आधार पर प्रेत लॉन्च करना (जो अब मैं कर रहा हूं) रास्ता बहुत सुस्त है। मेरे पास फ़ैंटॉमजेएस उदाहरणों का एक पूल होगा जो हमेशा मेरे webservice को नवीनतम कॉल करने के लिए उपलब्ध है।फ़ैंटॉमजेएस उदाहरणों के 'पूल' का प्रबंधन कैसे करें

क्या इस तरह की कोई चीज़ पहले से की गई है? मैं स्क्रैच से अपने लिए पूल मैनेजर/http प्रॉक्सी सर्वर लिखने के बजाय दूसरों के काम पर इस webservice का आधार बनाना चाहता हूं।

अधिक संदर्भ: मैंने 2 समान परियोजनाएं सूचीबद्ध की हैं जिन्हें मैंने अभी तक देखा है और मैंने प्रत्येक से क्यों बचा है, जिसके परिणामस्वरूप फ़ैंटॉमजेएस उदाहरणों के पूल के प्रबंधन के बारे में यह प्रश्न है।

jsdom - मैंने जो देखा है उससे पृष्ठ पर स्क्रिप्ट निष्पादित करने के लिए बहुत अच्छी कार्यक्षमता है, लेकिन यह ब्राउज़र व्यवहार को दोहराने का प्रयास नहीं करता है, इसलिए यदि मैं इसे सामान्य उद्देश्य "डीओएम रिज़ॉल्वर" के रूप में उपयोग करता हूं, डी सभी प्रकार के किनारों के मामलों, घटना कॉलिंग इत्यादि को संभालने के लिए बहुत अधिक कोडिंग होने का अंत होता है। मैंने देखा कि पहला उदाहरण मैन्युअल रूप से नोड का उपयोग करके स्थापित एक परीक्षण ऐप के लिए बॉडी टैग के ऑनलोड() फ़ंक्शन को कॉल करना था । यह एक गहरे खरगोश छेद की शुरुआत की तरह लग रहा था।

सेलेनियम - इसमें अभी बहुत अधिक चलने वाले हिस्सों हैं, इसलिए लंबे समय तक रहने वाले ब्राउज़र उदाहरणों को प्रबंधित करने के लिए पूल स्थापित करना फ़ैंटॉमजेएस का उपयोग करने से अधिक जटिल होगा। मुझे इसकी किसी भी मैक्रो रिकॉर्डिंग/स्क्रिप्टिंग लाभ की आवश्यकता नहीं है। मैं बस में

उत्तर

17

async JavaScript library काम करता है (अगर मैं इसे छवियों आदि की उपेक्षा कर सकते हैं भी तेजी से या) एक वेब सेवा है कि एक वेबपेज हो रही है और यह डोम के रूप में अगर मैं एक ब्राउज़र के साथ है जो URL से ब्राउज़ कर रहे थे हल करने में के रूप में performant है चाहता हूँ

queue(worker, concurrency)

Creates a queue object with the specified concurrency. Tasks added to the queue will be processed in parallel (up to the concurrency limit). If all workers are in progress, the task is queued until one is available. Once a worker has completed a task, the task's callback is called.

कुछ स्यूडोकोड:

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); 
    }); 
}); 

चेक बाहर entire documentation for queue at the project's readme नोड और एक queue समारोह है कि बात यह है कि इस तरह का के लिए काफी आसान है।

+0

आप कैसे कतार काम करता है जानते हैं विस्तार से? मुझे लगता है कि यह कतार में कई एक्सएचआर अनुरोधों को बुला रहा है?मैं एक ऐसे समाधान की तलाश में हूं जो वास्तव में फ़ैंटोमोज़ प्रक्रियाओं को एक डिमन के रूप में चलने के बजाए एक डिमन के रूप में चल रहा है। – CMCDragonkai

+0

@CMCDragonkai प्रश्न में उल्लेख किया गया है कि "फैंटॉमजेएस उदाहरणों का एक पूल हमेशा सेवा के लिए उपलब्ध है मेरे webservice के लिए नवीनतम कॉल, "जो लगातार PhantomJS daemons चल रहा है, लेकिन यह जवाब किसी भी मामले के साथ काम करेगा। सभी 'async.queue' फ़ंक्शन यह सुनिश्चित करता है कि किसी भी समय फ़ंक्शन में कॉल की निश्चित संख्या से अधिक बकाया नहीं है; आप उस समारोह के अंदर क्या करते हैं आप पर निर्भर है। –

+2

आप मेरे दोस्त, लगभग 4 साल बाद, मुझे काफी सिरदर्द बचा लिया है। – mgmcdermott

0

आप NodeJS का उपयोग कर रहे हैं, तो आप https://github.com/sgentle/phantomjs-node, जो आप अपने मुख्य NodeJS प्रक्रिया को phantomjs प्रक्रिया का एक मनमाना संख्या कनेक्ट करने के लिए अनुमति देगा का उपयोग कर सकते, इसलिए, async.js और नोड उपहार के बहुत सारे उपयोग करने की क्षमता।

+0

यह सच नहीं है। यदि आप प्रेत जेएस के एक से अधिक उदाहरण बनाते हैं और उन्हें एक ही समय में चलाते हैं तो आपको 'त्रुटि: EADDRINUSE सुनें' मिलती है। मैं वर्तमान में विभिन्न बंदरगाहों पर प्रेत उदाहरण डालने का तरीका ढूंढ रहा हूं या जो भी EADDRINUSE उत्पन्न कर रहा है। – RachelC

+1

यह निश्चित रूप से प्रेत उदाहरण शुरू करने की आपकी ज़िम्मेदारी है ताकि वे एक अलग बंदरगाह पर सुन सकें। –

61

मैं एक फ़ैंटॉमजे क्लाउड सेवा सेट करता हूं, और यह आपके द्वारा पूछे जाने वाले कार्यों में काफी कुछ करता है। मुझे लगभग 5 सप्ताह के काम को लागू करने में लगा।

आपके द्वारा चलाए जाने वाली सबसे बड़ी समस्या memory leaks in PhantomJs का ज्ञात-मुद्दा है। जिस तरह से मैंने इस तरह काम किया है, वह हर 50 कॉलों के अपने उदाहरणों को चक्रबद्ध करना है।

दूसरी सबसे बड़ी समस्या जो आप दौड़ेंगे, वह प्रति पृष्ठ प्रसंस्करण बहुत सीपीयू और स्मृति गहन है, इसलिए आप प्रति सीपीयू 4 या तो उदाहरण चलाने में सक्षम होंगे।

तीसरी सबसे बड़ी समस्या जो आप दौड़ेंगे वह यह है कि फ़ैंटॉमजे पेज-फिनिश ईवेंट और रीडायरेक्ट के साथ बहुत निराशाजनक है। आपको सूचित किया जाएगा कि आपका पृष्ठ वास्तव में प्रस्तुत होने से पहले प्रस्तुत करना समाप्त हो गया है। There are a number of ways to deal with this, लेकिन दुर्भाग्य से कुछ भी 'मानक' नहीं है।

चौथी सबसे बड़ी समस्या जिसे आप सौदा करना चाहते हैं, नोडज और फैंटोमज के बीच इंटरऑप है, धन्यवाद, a lot of npm packages that deal with this issue से चुनने के लिए धन्यवाद।

तो मुझे पता है कि मैं पक्षपातपूर्ण हूं (जैसा कि मैंने समाधान लिखा है, जिसे मैं सुझाव देने जा रहा हूं) लेकिन मेरा सुझाव है कि आप PhantomJsCloud.com देखें जो प्रकाश उपयोग के लिए स्वतंत्र है।

जनवरी 2015 अद्यतन: एक और (? 5) बड़ी समस्या मैं में भाग कैसे प्रबंधक/लोड संतुलन से अनुरोध/प्रतिक्रिया भेजने के लिए है। मूल रूप से मैं फ़ैंटॉमजेएस के अंतर्निहित HTTP सर्वर का उपयोग कर रहा था, लेकिन इसकी प्रतिक्रियाओं में विशेष रूप से अधिकतम प्रतिक्रिया-आकार के संबंध में चल रहा था। मैंने स्थानीय फाइल सिस्टम को संचार की लाइनों के रूप में अनुरोध/प्रतिक्रिया लिखना समाप्त कर दिया। * सेवा के कार्यान्वयन पर खर्च किए गए कुल समय शायद 20 मैन-हफ्ते के मुद्दों का प्रतिनिधित्व करता है, शायद 1000 घंटे का काम है। * और एफवाईआई मैं अगले संस्करण के लिए एक पूर्ण पुनर्लेखन कर रहा हूं .... (प्रगतिशील)

+0

ग्रेट उत्तर जेसन। यदि आप आगे बढ़ सकते हैं तो कार्यान्वयन के विवरण के बारे में हमें और बताएं। उदाहरण के लिए आप सभी उदाहरणों का प्रबंधन कैसे करते हैं? इसके अलावा, आप नोड से खुद को प्रेत उदाहरण कैसे लॉन्च करते हैं? ऐसा करने के लिए कोई मॉड्यूल सिफारिश? या आप प्रक्रियाओं को जन्म देते हैं? – Nobita

+1

मैं सर्वर पर एक नोडज 'राउटर' ऐप से सभी प्रबंधन करता हूं। यह सामान्य nodejs spawn प्रक्रिया कमांड के माध्यम से एकाधिक phantomjs.exe उदाहरण लॉन्च करता है। वास्तव में उस संबंध में कुछ विशेष नहीं है। मैंने एनपीएम पर पाए गए सभी विभिन्न फैंटोम्प्स रैपरों की कोशिश की, लेकिन स्पष्ट रूप से वे ज्यादातर चूसते हैं। नोडजेस राउटर ऐप से/से संवाद करने के लिए केवल phantomjs के अंतर्निहित http सर्वर का उपयोग करके समाप्त हो गया। – JasonS

+0

एक phantomJS उदाहरण के भीतर कई वेबपृष्ठ ऑब्जेक्ट बनाने के बारे में क्या? उस के साथ कुछ गलत है ? – Xsmael

5

@ जेसनएस के महान जवाब के विकल्प के रूप में आप PhearJS को आजमा सकते हैं। फेहरजेएस एक पर्यवेक्षक है जो फोंटॉमजेएस उदाहरणों के लिए नोडजेएस में लिखा गया है और HTTP के माध्यम से एक एपीआई प्रदान करता है। यह Github से ओपन-सोर्स उपलब्ध है।

1

अगर आप NodeJS उपयोग कर रहे हैं यही कारण है कि सेलेनियम-webdriver का उपयोग नहीं

  1. रन कुछ phantomjs उदाहरण के रूप में webdriver phantomjs --webdriver=port_number
  2. प्रत्येक के लिए

    phantomjs उदाहरण 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; 
    } 
    

    बना सकते हैं और के सभी डाल उन्हें एक सरणी [phantomInstance1, phantomInstance2]

  3. dispather.js कि सरणी से मुक्त phantomInstance हो और

    var driver = phantomInstance.getDriver(); 
    
+0

यह एक अच्छा तरीका नहीं है। मेरा विश्वास करो ... मेरे कार्यक्रम में मैंने सेलेनियम-वेबड्राइवर का उपयोग किया लेकिन अंततः मैंने इसे दिया! –

14

मेरे मालिक थीसिस के लिए बनाने के लिए, मैं पुस्तकालय phantomjs-pool जो वास्तव में यह करता है विकसित की है। यह उन नौकरियों को प्रदान करने की अनुमति देता है जिन्हें फ़ैंटॉमजेएस श्रमिकों के लिए मैप किया जाता है। पुस्तकालय नौकरी वितरण, संचार, त्रुटि प्रबंधन, लॉगिंग, पुनरारंभ करने और कुछ और सामान को संभालता है। लाइब्रेरी का सफलतापूर्वक दस लाख से अधिक पृष्ठों को क्रॉल करने के लिए उपयोग किया गया था।

उदाहरण:

निम्नलिखित कोड संख्या 9 करने के लिए 0 के लिए एक Google खोज निष्पादित करता है और के रूप में googleX.png पृष्ठ का एक स्क्रीनशॉट बचाता है। चार वेबसाइटें समानांतर में क्रॉल की जाती हैं (चार श्रमिकों के निर्माण के कारण)। लिपि node master.js के माध्यम से शुरू की गई है।

master.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 
    } 
} 
(Node.js वातावरण में चलता है)

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 
    }); 

}; 
+1

यह एक महान पुस्तकालय है। मैं सोच रहा हूं, क्या ऐसा कोई तरीका है जब पता लगाने के लिए कोई और प्रक्रिया नहीं है? जैसा कि प्रक्रियाओं की एक श्रृंखला पूरी हो जाने के बाद 'pool.start() 'कुछ करने के बाद, async या वादे के माध्यम से प्रतीक्षा कर रहा है? – afithings

+0

धन्यवाद। वर्तमान में एसिंक के साथ सरल करने का कोई तरीका नहीं है। हालांकि, आप प्रत्येक व्यक्तिगत नौकरी के लिए कॉलबैक का उपयोग कर सकते हैं (जो एक काम पूरा होने पर आग लगती है) और इस तरह एक काउंटर बढ़ाएं। तो आप अभी भी यह पता लगाने में सक्षम हैं कि सभी नौकरियां कब समाप्त हो जाती हैं। –

संबंधित मुद्दे