2013-05-23 7 views
7

サイトからいくつかの画像を保存します。現時点で私は画像への道を得ることができますが、私はファントムを使って画像を取得して保存する方法を知りません。phantomjsでサイトから画像をダウンロードするには

findRotationTeaserImages = -> 
    paths = page.evaluate -> 
    jQuery('.rotate img').map(-> return this.src).get() 

    for path, i in paths 
    console.log(path); 
    //save the image 
+0

はい、私の悪い英語のために申し訳ありません。 –

+0

あなたの ' - >'は 'function(){...}'の略語ですか? – LarsH

+2

はい、関数のcoffeescript表記です。 –

答えて

17

を知っているこれは古い質問ですが、オブジェクト内の各画像の寸法と位置を保存してから、phantomjs page.clipRectを変更して、page.render()メソッドが画像を描画する領域だけをレンダリングするようにしますです。

var page = require('webpage').create(); 

page.open('http://dribbble.com/', function() { 

    page.includeJs('//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js',function() { 

     var images = page.evaluate(function() { 
      var images = []; 
      function getImgDimensions($i) { 
       return { 
        top : $i.offset().top, 
        left : $i.offset().left, 
        width : $i.width(), 
        height : $i.height() 
       } 
      } 
      $('.dribbble-img img').each(function() { 
       var img = getImgDimensions($(this)); 
       images.push(img); 
      }); 

      return images; 
     }); 

     images.forEach(function(imageObj, index, array){ 
      page.clipRect = imageObj; 
      page.render('images/'+index+'.png') 
     }); 

     phantom.exit(); 
    }); 
}); 
5

画像をダウンロードするノードのスクリプトを実行している子プロセスを起動することによってこの問題を解決:

phantomJsスクリプト:

findRotationTeaserImages = -> 
    paths = page.evaluate -> 
    jQuery('.rotate img').map(-> return this.src).get() 

    args = ('loadRotationTeaser.js ' + paths.join(' ')).split(' ') 

    child_process.execFile("node", args, null, (err, stdout, stderr) -> 
    phantom.exit() 
) 

nodeJsスクリプト

http = require('http-get'); 

args = process.argv.splice(2) 

for path, i in args 
    http.get path, 'public/images/rotationTeaser/img' + i + '.jpeg', (error, result) -> 
9

これを行うための別の方法が用意されました:ここにhttp://dribbble.com/から複数の画像をこする、一例です。

var fs = require("fs"); 
var imageBase64 = page.evaluate(function(){ 
    var canvas = document.createElement("canvas"); 
    canvas.width =img.width; 
    canvas.height =img.height; 
    var ctx = canvas.getContext("2d"); 
    ctx.drawImage(img, 0, 0);  
    return canvas.toDataURL ("image/png").split(",")[1]; 
}) 
fs.write("file.png",atob(imageBase64),'wb'); 
+0

非常に良い解決策私はそれを試して、それは素晴らしい仕事です。私はしかし、いくつかの質問があります。 .split( "、")[1]はなぜ必要なのですか? 評価なしで動作させてもらえますか? ありがとう! – B2F

+0

なしで試したことはありません。 toDataUrlは、実際のバイトコードの前にあるデータの種類を定義する接頭辞を返します。 私はatobがプレフィックスなしでバイトコードそのものと共に使われているのを見たことがあります。 –

0

場合は、画像のサイズが知られている:renderメソッドを使用している場合

 


    var webPage = require('webpage'); 

    /** 
    * Download image with known dimension. 
    * @param src Image source 
    * @param dest Destination full path 
    * @param width Image width 
    * @param height Image height 
    * @param timeout Operation timeout 
    * @param cbk Callback (optional) 
    * @param cbkParam Parameter to pass back to the callback (optional) 
    */ 
    function downloadImg(src, dest, width, height, timeout, cbk, cbkParam) { 
     var page = webPage.create(); 

     page.settings.resourceTimeout = timeout; //resources loading timeout(ms) 
     page.settings.webSecurityEnabled = false; //Disable web security 
     page.settings.XSSAuditingEnabled = false; //Disable web security 

     page.open(src, function(status) { 

      // missing images sometime receive text from server 
      var success = status == 'success' && !page.plainText; 

      if (success) { 
       page.clipRect = { 
        top: 0, 
        left: 0, 
        width: width, 
        height: height 
       }; 
       page.render(dest); 

      } 

      cbk && cbk(success, cbkParam); 
      page.close(); 
     }); 
    }; 

 
0

私は本当に多くのトラブルを経験しました。幸運にも私は最終的に2つのより良い解決策を考え出します。私のプロジェクトで使用したコードは次のとおりです。最初の解決策は、クッキーを更新するためにいくつかの問題を抱えているため、キャプチャ画像を取得するときにうまく動作しません。どちらの方法でも、新しいhttp要求が発生します。しかし、いくつかの変更を加えれば、第二のものはそのような要求を排除することができます。

最初のものはphantomJsからクッキーを取り出し、requestを使用して新しいhttp要求を行います。 2番目はbase64を使用して画像を渡します。

async download(download_url, stream) { 
    logger.profile(`download(download_url='${download_url}')`); 
    let orig_url = await this.page.property('url'); 
    download_url = url.resolve(orig_url, download_url); 
    let cookies = await this.page.property('cookies'); 
    let jar = request.jar(); 
    for (let cookie of cookies) { 
     if (cookie.name !== undefined) { 
      cookie.key = cookie.name; 
      delete cookie.name; 
     } 
     if (cookie.httponly !== undefined) { 
      cookie.httpOnly = cookie.httponly; 
      delete cookie.httponly; 
     } 
     if (cookie.expires !== undefined) 
      cookie.expires = new Date(cookie.expires); 
     jar.setCookie(new Cookie(cookie), download_url, {ignoreError: true}); 
    } 
    let req = request({ 
     url: download_url, 
     jar: jar, 
     headers: { 
      'User-Agent': this.user_agent, 
      'Referer': orig_url 
     } 
    }); 
    await new Promise((resolve, reject) => { 
     req.pipe(stream) 
      .on('close', resolve) 
      .on('error', reject); 
    }); 
    // Due to this issue https://github.com/ariya/phantomjs/issues/13409, we cannot set cookies back 
    // to browser. It is said to be redesigned, but till now (Mar 31 2017), no change has been made. 
    /*await Promise.all([ 
     new Promise((resolve, reject) => { 
      req.on('response',() => { 
       jar._jar.store.getAllCookies((err, cookies) => { 
        if (err) { 
         reject(err); 
         return; 
        } 
        cookies = cookies.map(x => x.toJSON()); 
        for (let cookie of cookies) { 
         if (cookie.key !== undefined) { 
          cookie.name = cookie.key; 
          delete cookie.key; 
         } 
         if (cookie.httpOnly !== undefined) { 
          cookie.httponly = cookie.httpOnly; 
          delete cookie.httpOnly; 
         } 
         if (cookie.expires instanceof Date) { 
          cookie.expires = cookie.expires.toGMTString(); 
          cookie.expiry = cookie.expires.toTime(); 
         } 
         else if (cookie.expires == Infinity) 
          delete cookie.expires; 
         delete cookie.lastAccessed; 
         delete cookie.creation; 
         delete cookie.hostOnly; 
        } 
        this.page.property('cookies', cookies).then(resolve).catch(reject); 
       }); 
      }).on('error', reject); 
     }), 
     new Promise((resolve, reject) => { 
      req.pipe(fs.createWriteStream(save_path)) 
       .on('close', resolve) 
       .on('error', reject); 
     }) 
    ]);*/ 
    logger.profile(`download(download_url='${download_url}')`); 
} 
async download_image(download_url, stream) { 
    logger.profile(`download_image(download_url='${download_url}')`); 
    await Promise.all([ 
     new Promise((resolve, reject) => { 
      this.client.once('donwload image', data => { 
       if (data.err) 
        reject(err); 
       else 
        stream.write(Buffer.from(data.data, 'base64'), resolve); 

      }); 
     }), 
     this.page.evaluate(function (url) { 
      var img = new Image(), callback = function (err, data) { 
       callPhantom({ 
        event: 'donwload image', 
        data: { 
         err: err && err.message, 
         data: data 
        } 
       }); 
      }; 
      img.onload = function() { 
       var canvas = document.createElement("canvas"); 
       canvas.width = img.width; 
       canvas.height = img.height; 
       canvas.getContext("2d").drawImage(img, 0, 0); 
       callback(null, canvas.toDataURL("image/png").replace(/^data:image\/(png|jpg);base64,/, "")); 
      }; 
      img.onerror = function() { 
       callback(new Error('Failed to fetch image.')); 
      }; 
      img.src = url; 
     }, download_url) 
    ]); 
    logger.profile(`download_image(download_url='${download_url}')`); 
} 
関連する問題