ktty1220 / cheerio-httpcli

iconvによる文字コード変換とcheerioによるHTMLパースを組み込んだNode.js用HTTPクライアントモジュール
MIT License
262 stars 28 forks source link

Base64埋め込み画像のsrcが取得できない #20

Closed yuta0801 closed 7 years ago

yuta0801 commented 7 years ago

画像をダウンロードするサンプルをGoogleの画像検索の結果の画像を ダウンロードさせるようにしたら以下のようなエラーがでました。

試しにdownload.js:312の$elem.attr('src')の値を見てみるとundefinedでした。

var fs = require('fs');
var client = require('cheerio-httpcli');

client.download.on('ready', function (stream) {
    stream.pipe(fs.createWriteStream('/path/to/image.png'));
    console.log(stream.url.href + 'をダウンロードしました');
}).on('error', function (err) {
    console.error(err.url + 'をダウンロードできませんでした: ' + err.message);
}).on('end', function () {
    console.log('ダウンロードが完了しました');
});

client.download.parallel = 4;

client.fetch('http://www.google.com/search', { q: 'node.js', tbm:'isch' }, function (err, $, res, body) {
    $('img').download();
    console.log('OK!');
});
node_modules\cheerio-httpcli\lib\cheerio\download.js:312
      var b64chk = $elem.attr('src').match(/^data:(image\/\w+);base64,([\s\S]+)$/i);
                                    ^

TypeError: Cannot read property 'match' of undefined
    at Object.<anonymous> (node_modules\cheerio-httpcli\lib\cheerio\download.js:312:37)
    at initialize.exports.each (node_modules\cheerio\lib\api\traversing.js:300:24)
    at initialize.cheerio.download (node_modules\cheerio-httpcli\lib\cheerio\download.js:300:10)
    at Object.callback (img\app.js:16:14)
    at Object.<anonymous> (node_modules\cheerio-httpcli\lib\client.js:261:17)
    at Object.<anonymous> (node_modules\cheerio-httpcli\lib\client.js:221:9)
    at Request.self.callback (node_modules\request\request.js:188:22)
    at emitTwo (events.js:106:13)
    at Request.emit (events.js:191:7)
    at Request.<anonymous> (node_modules\request\request.js:1171:10)
ktty1220 commented 7 years ago

調べてみましたが、Google画像検索結果のHTMLソース上では画像タグが以下の様になっていました。

<img class="rg_ic rg_i" data-sz="f" name="ZcvDYlgt8bMONM:" alt="「node.js」の画像検索結果" jsaction="load:str.tbn" onload="google.aft&&google.aft(this)">

HTMLソースの時点ではimgタグにsrc属性が指定されていません。

おそらくonloadのタイミングでsrcにbase64化された画像が差し込まれるのではないかと思います。 cheerio-httpcliではonloadといった動的なコンテンツ変更には対応していないので、srcが指定されていないimgタグのsrcを見に行ってエラーになっているといった状態です。

次バージョンで修正する予定ですが、現在masterブランチで大きめの対応を行っており、それと合わせてリリースする関係上、すぐにバージョンアップというわけにはいかない状態なので、急ぎの場合は、エラーの出た箇所を以下のように書き換えるととりあえず動くようにはなります。

var b64chk = ($elem.attr('src') || '').match(/^data:(image\/\w+);base64,([\s\S]+)$/i);

ただ、Googleの画像検索結果が上記のように動的にimgsrcをセットしていることから考えると、この修正を適用しても検索結果の画像を正常に全部取得できるかどうかは分かりません。

静的コンテンツの解析がcheerio-httpcliの機能なので、その点についてはご了承ください。

ktty1220 commented 7 years ago

こちらは0.7.0で修正されました。