2017-06-16 5 views
6

私はnightmare.jsスクリプトを実行しています。ここでは、ページ上の複数の要素のスクリーンショットを取得しようとしています。Nightmare.js screenshotバッファの長さ0

最初の要素はきれいにキャプチャされますが、フォールドの下にある他のすべての要素はゼロ長でキャプチャされます。私はこの問題をデバッグするのに苦労しています。どんな助けでも信じられないほど高く評価されます。

基本的に、このスクリプトはページ内を移動し、すべてセレクタに一致する要素を選択します。次に、asyncを使用して応答を収集し、オブジェクトのバッファを返します。問題は、折りたたみの下の要素がスクリーンショットを取得しないことです(バッファの長さはゼロになります)。私はwait()を試して要素にスクロールしましたが、まだ成功していません。

import * as Nightmare from 'nightmare' 
import * as vo from 'vo' 
import * as async from 'async' 
import * as fs from 'fs' 

const urls:String[] = [ 
    'https://yahoo.com/' 
] 


Nightmare.action('snap', function(selector:String, done:Function) { 
    const self = this; 

    this.evaluate_now(function (selector) { 
    return Array.from(document.querySelectorAll(selector)) 
    .map((ele:Element) => { 
     if (ele) { 
     const rect = ele.getBoundingClientRect() 
     const r:Function = Math.round 
     return { 
      x: r(rect.left), 
      y: r(rect.top), 
      width: r(rect.width), 
      height: r(rect.height) 
     } 
     } 
    }) 
    }, function(err, clips) { 
    if (err) return done(err) 
    if (!clips) return done(new Error(`Selector not found`)) 
    let snaps = [] 
    const snap = (clip, cb) => { 
     self 
     .scrollTo(clip.y - clip.height, clip.x) 
     .screenshot(clip, cb) 
     .run() 
    } 
    async.mapSeries(clips.reverse(), snap, (err, res) => { 
     done(err, res) 
    }) 
    }, selector) 
}) 

const scrape = (url) => { 
    const nightmare = Nightmare({ 
    show: true 
    }); 
    nightmare 
    .goto(url) 
    .snap('.navbar') 
    .end() 
    .then((buffers:Buffer[]) => { 
     buffers.forEach((data, index) => { 
     fs.writeFileSync(`images/navbar-${index}.png`, data) 
     }) 
    }) 
} 

urls.forEach(scrape) 
+0

この問題を再現しようとしていますが、yahoo.comページに「.navbar」という要素がないことがわかりました。あなたはそれを明確にしていただけますか? –

+0

Evgeny、確かに。ブートストラップが付いたページ(https://getbootstrap.com/ – auser

+0

)で試してみてください。あなたはそれを複製できましたか、@EvgenySorokin? – auser

答えて

1

、より良い結果を与えた: アプローチの違いは次のとおりです。要素に第1スクロールとその後、その範囲を取ってからスクリーンショットを進めてください。

const Nightmare = require('nightmare'); 
const fs = require('fs'); 
const nightmare = Nightmare({ 
    show: true, 
    openDevTools: false, 
    gotoTimeout: 45000 
}); 

nightmare.goto('https://www.google.co.in/?#safe=off&q=nightmare') 
    .wait(1000) 
    .evaluate(getElements, 'div.g') 
    .then(() => { 
    console.log("Calling screenshots: "); 
    getAllScreenshots(0); 
    }) 
    .catch(function(err) { 
    console.log(err); 
    }); 

function getAllScreenshots(index) { 
    console.log("Called with index: ", index) 
    nightmare.evaluate(function(index) { 
     const r = Math.round; 
     if(index >= window.__nightmare.output.length) { 
     return false; 
     } 
     var element = window.__nightmare.output[index]; 
     console.log(index, element.innerHTML); 
     element.scrollIntoView(false); 
     var bound = element.getBoundingClientRect(); 
     return { 
     x: r(bound.left)-10, 
     y: r(bound.top)-10, 
     width: r(element.clientWidth)+40, 
     height: r(element.clientHeight)+10 
     } 
    }, index) 
    .then(function(bound) { 
     if(!bound) { 
     return; 
     } 
     console.log("Taking screenshot: ", bound); 
     nightmare.wait(500).screenshot(__dirname + '/images/navbar' + index + '.png', bound) 
     .then(function() { 
      console.log("Calling Next of: ", index); 
      getAllScreenshots(index + 1); 
     }).catch(function(err) { 
      console.log(err); 
     }) 
    }) 
    .catch(function(err) { 
     console.log(err); 
    }); 
} 

function getElements(selector) { 
    var elements = document.querySelectorAll(selector); 
    window.__nightmare.output = elements; 
    console.log(elements.length); 
} 
+0

これは素晴らしいことです。ありがとうございました! – auser

4

実際には、screenshot()関数は、表示される画面から座標を取得します。
例:任意の要素の(x、y)が(10、1000)でウィンドウサイズが(800,600)の場合、スクロール(900:element.y、0)してからscreenshotを(element.y- scroll.y = 100、element.x)

私は最終的に、コードの作業を得た:

異なる流れからそれをしよう
const Nightmare = require('nightmare'); 
const fs = require('fs'); 
const nightmare = Nightmare({ 
    show: true, 
    openDevTools: true, 
}); 

nightmare.goto('https://in.news.yahoo.com/') 
    .wait(1000) 
    .evaluate(getBounds, '.Cf') 
    .then(function(rects) { 
    console.log(rects); 

    function getScreenshot(rects, index) { 
     if (index == rects.length) return; 
     nightmare.scrollTo(rects[index].y, 0) 
     .screenshot(__dirname + '/images/navbar' + index + '.png', { 
      //60 is height of the top element which remains 
      x: rects[index].x-10, 
      y: 60, 
      width: rects[index].width+30, 
      height: rects[index].height +60 
     }) 
     .then(function() { 
      console.log("Calling next. " + index); 
      getScreenshot(rects, index + 1); 
     }).catch(function(err) { 
      console.log(err); 
     }) 
    }; 

    getScreenshot(rects, 0); 
    }) 
    .catch(function(err) { 
    console.log(err); 
    }); 

function getBounds(selector) { 
    var elements = document.querySelectorAll(selector); 
    if (elements && elements.length > 0) { 
    var arr = []; 
    const r = Math.round; 
    for (var ii = 0; ii < elements.length; ii++) { 
     var rect = elements[ii].getBoundingClientRect(); 
     arr.push({ 
     x: r(rect.left), 
     y: r(rect.top), 
     width: r(rect.width), 
     height: r(rect.height) 
     }) 
    } 
    console.log("Elements found: ", arr.length); 
    return arr; 
    } 
    return null; 
} 
関連する問題