Node.js如何从网页获取图片并使用base64编码?

105

我正在尝试从网络上获取图像,并使用base64对其进行编码。

目前为止,我已经做了这个:

var request = require('request');
var BufferList = require('bufferlist').BufferList;

bl = new BufferList(),

request({uri:'http://tinypng.org/images/example-shrunk-8cadd4c7.png',responseBodyStream: bl}, function (error, response, body) 
{
    if (!error && response.statusCode == 200) 
    {
        var type = response.headers["content-type"];
        var prefix = "data:" + type + ";base64,";
        var base64 = new Buffer(bl.toString(), 'binary').toString('base64');
        var data = prefix + base64;
        console.log(data);
    }
});

这似乎非常接近解决方案,但我还不能使它正常工作。它识别了数据类型并输出了这个结果:

data:image/png;base64

然而,缓冲区列表 'bl' 似乎为空。


只是一个完全的猜测,但我认为可能有可能请求()正在使用一个标头,指示可能被某些网站阻止的代理,以最小化爬取。 - Brett Zamir
@BrettZamir 你这么认为吗?用200响应阻止请求似乎非常不好... - Sebastian vom Meer
1
我可以问一下:require('request')是什么?在文档中找不到它。我只知道它与http/https有关。 - Sebastian vom Meer
@Sebastian,是的,这只是一个猜测...但这是我经常遇到的问题之一,所以只是随口提供一下... - Brett Zamir
@SebastianG,如果你在文档中找不到所需的内容,那么这意味着它来自于...? :D - gustavohenke
@gustavohenke 抱歉,我不明白... - Sebastian vom Meer
11个回答

186

BufferList已过时,因为它的功能现在已经集成到了Node核心中。这里唯一棘手的部分是将请求设置为不使用任何编码:

var request = require('request').defaults({ encoding: null });

request.get('http://tinypng.org/images/example-shrunk-8cadd4c7.png', function (error, response, body) {
    if (!error && response.statusCode == 200) {
        data = "data:" + response.headers["content-type"] + ";base64," + Buffer.from(body).toString('base64');
        console.log(data);
    }
});

太好了,它起作用了,谢谢!不过我有一个问题,为什么请求没有设置任何编码?如果我跳过 .defaults({ encoding: null }) 部分,我仍然会得到某种结果。 - Aleksr9
27
encoding: null 表示请求返回的是一个 buffer 而不是一个字符串。字符串会得到无法使用的乱码数据,因为 base64 的整个目的就是编码二进制数据。我在自己的 StackOverflow 问题 https://dev59.com/6nLYa4cB1Zd3GeqPVUG3 中得到了关于编码的答案,现在我很高兴回报社区。 - Dan Kohn
1
解决方案:从本地主机运行生产环境 - SouvikMaji
2
愿众神保佑你...我知道这是一个编码问题,但我一直在努力寻找如何在请求库中禁用它。 - Dimas Crocco
1
@DanKohn new Buffer现在已经被弃用。https://nodejs.org/api/buffer.html - Nagendra Rao
显示剩余2条评论

58

如果有人在使用axios作为HTTP客户端时遇到相同的问题,解决方法是在请求选项中添加responseType属性,并将其值设置为'arraybuffer':

let image = await axios.get('http://aaa.bbb/image.png', {responseType: 'arraybuffer'});
let returnedB64 = Buffer.from(image.data).toString('base64');

希望这可以帮助到你


1
非常感谢!帮我节省了大量的时间和烦恼! - Dhananjai Pai
我在使用axios时遇到了很多问题,结果发现响应类型是关键。非常感谢! - ShaneTheKing

43

截至2017年底的最新情况:

读完上面的答案并进行了一些研究后,我发现了一种新的方法,不需要安装任何软件包,只用内置的http模块就可以了!

注意:我使用的是node版本6.x,所以我想它也适用于以上版本。

var http = require('http');

http.get('http://tinypng.org/images/example-shrunk-8cadd4c7.png', (resp) => {
    resp.setEncoding('base64');
    body = "data:" + resp.headers["content-type"] + ";base64,";
    resp.on('data', (data) => { body += data});
    resp.on('end', () => {
        console.log(body);
        //return res.json({result: body, status: 'success'});
    });
}).on('error', (e) => {
    console.log(`Got error: ${e.message}`);
});

希望对你有所帮助!

另外,可以在这里了解更多关于http.get(...)的信息!


5
这个有效。在我的解决方案中,我不得不同时使用http和https模块,因为大多数资源现在都是https。不幸的是,你需要手动检查要使用哪个模块。请参阅https://dev59.com/GVsX5IYBdhLWcg3wLM7K#45215071。 - l p
1
对我来说最好的答案! - Valfar Developer

23

使用 Node Fetch 的另一种方式,将步骤分解为每个变量:

const fetch = require('node-fetch');

const imageUrl = "Your URL here";
const imageUrlData = await fetch(imageUrl);
const buffer = await imageUrlData.arrayBuffer();
const stringifiedBuffer = Buffer.from(buffer).toString('base64');
const contentType = imageUrlData.headers.get('content-type');
const imageBase64 = 
`data:${contentType};base64,${stringifiedBuffer}`;

这就是适合我的一个。谢谢! - ElasticThoughts

16

如果你知道图片类型,可以使用node-fetch包的一行代码解决。可能并不适合所有人,但我已经将node-fetch作为一个依赖,所以如果其他人也有类似的情况:

await fetch(url).then(r => r.buffer()).then(buf => `data:image/${type};base64,`+buf.toString('base64'));

好的,简洁明了! - Janosh
2
很好!.buffer已被弃用。这是新的方法: const blob = await response.arrayBuffer(); return \data:${response.headers.get("content-type")};base64,${Buffer.from(blob).toString("base64")}`;` - Gus

12

如果您正在使用axios,则可以按照以下步骤进行操作

var axios = require('axios');
const url ="put your url here";
const image = await axios.get(url, {responseType: 'arraybuffer'});
const raw = Buffer.from(image.data).toString('base64');
const base64Image = "data:" + image.headers["content-type"] + ";base64,"+raw;

你可以使用base64解码进行检查。


9
您可以使用base64-stream Node.js模块,这是一个流式Base64编码器/解码器。此方法的好处是您无需将整个图像缓冲到内存中,也不需要使用request模块即可转换图像。
var http = require('http');
var base64encode = require('base64-stream').Encode;

http.get('http://tinypng.org/images/example-shrunk-8cadd4c7.png', function(res) {
    if (res.statusCode === 200)
        res.pipe(base64encode()).pipe(process.stdout);
});

3

我使用node-base64-image npm模块来加载并将图像编码为base64字符串。

下载并编码图片:

var base64 = require('node-base64-image');

var options = {string: true};
base64.base64encoder('www.someurl.com/image.jpg', options, function (err, image) {
    if (err) {
        console.log(err);
    }
    console.log(image);
});

对本地图像进行编码:

var base64 = require('node-base64-image');

var path = __dirname + '/../test.jpg',
options = {localFile: true, string: true};
base64.base64encoder(path, options, function (err, image) {  
    if (err) { console.log(err); }  
    console.log(image);  
}); 

3
base64.encode(<URL>, <OPTIONS>, <CALLBACK>) API参考:https://github.com/riyadhalnur/node-base64-image/blob/HEAD/docs/docs.md将<URL>转换为base64编码的字符串,并在回调函数中返回结果。可选的<OPTIONS>参数允许您指定编码选项,如图像类型和质量。 - Semur Nabiev
尝试使用此npm包时出现ECONNREFUSED错误。可以在GitHub上看到相同的问题,但没有给出解决方案。 - Alok Rajasukumaran

2

一句话概括:

Buffer.from(
    (
      await axios.get(image, {
      responseType: "arraybuffer",
    })
  ).data,
  "utf-8"
).toString("base64")

2

这篇旧文章可能对某些人有所帮助。 基于Dmytro的回答,帮助了我。

const base64FromUrl = async (url: string) => {
  try {
    return Buffer.from((await axios.get(url, { responseType: "arraybuffer", })).data, "utf-8").toString("base64")
  } catch (error) {
    return ""
  }
}

我刚刚添加了错误处理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接