先看下采集效果,录屏有些模糊,凑合看吧。
给出关键代码片段,完整代码请联系站长
主要引入的依赖
const puppeteer = require('puppeteer');
const fs = require('fs-extra');
const path = require('path');
let fetch;
const saveDir = 'C:/Users/40650/Desktop/qrcode';
const infoTxt = 'qrcode_info.txt';
下载函数实现
async function downloadImage(url) {
// 在 isWeixin
await fs.ensureDir(saveDir);
let ext = '.jpg';
if (url.includes('.png')) ext = '.png';
else if (url.includes('.webp')) ext = '.webp';
const filename = `img_${Date.now()}_${Math.floor(Math.random() * 9000 + 1000)}${ext}`;
const filePath = path.join(saveDir, filename);
const headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'image/avif,image/webp,image/apng,image/*,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Referer': 'https://www.douyin.com/'
};
try {
const res = await fetch(url, { headers });
if (res.status === 200) {
const arrayBuffer = await res.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
console.log('准备识别图片:', url, 'buffer长度:', buffer.length);
// 识别二维码
const isQR = await isWeixinQRCode(buffer);
if (!isQR) {
console.log('❌ 非微信二维码图片,跳过保存');
return null;
}
await fs.writeFile(filePath, buffer);
console.log('✅ 图片已保存:', filePath);
return filePath;
} else {
console.log('❌ 下载失败,状态码:', res.status);
}
} catch (e) {
console.log('❌ 下载出错:', e);
}
return null;
}
二维码图片识别(色值转换,增强,提高采集准确率)
// 判断图片 buffer 是否为微信二维码(动态 import 兼容 ESM)
// 使用 sharp + @zxing/library 实现 buffer 二维码识别
async function isWeixinQRCode(buffer) {
console.log('开始识别二维码...');
const sharp = (await import('sharp')).default || (await import('sharp'));
const ZXingModule = await import('@zxing/library');
const { MultiFormatReader, BarcodeFormat, RGBLuminanceSource, BinaryBitmap, HybridBinarizer, DecodeHintType } = ZXingModule;
// 多种预处理:原图、灰度、反色、灰度反色
const preprocessList = [
async img => img,
async img => img.clone().greyscale(),
async img => img.clone().negate(),
async img => img.clone().greyscale().negate(),
];
try {
for (const preprocess of preprocessList) {
let image = sharp(buffer);
image = await preprocess(image);
const { width, height } = await image.metadata();
const raw = await image.ensureAlpha().raw().toBuffer();
const luminances = new Uint8ClampedArray(width * height);
for (let i = 0; i < width * height; i++) {
// 灰度 = R*0.299 + G*0.587 + B*0.114
const r = raw[i * 4];
const g = raw[i * 4 + 1];
const b = raw[i * 4 + 2];
luminances[i] = 0.299 * r + 0.587 * g + 0.114 * b;
}
const source = new RGBLuminanceSource(luminances, width, height);
const bitmap = new BinaryBitmap(new HybridBinarizer(source));
const reader = new MultiFormatReader();
const hints = new Map();
hints.set(DecodeHintType.POSSIBLE_FORMATS, [BarcodeFormat.QR_CODE]);
reader.setHints(hints);
try {
const result = reader.decode(bitmap);
const qrText = result.getText().toLowerCase();
console.log('✅ 检测图片内容:', qrText);
if (qrText.includes('weixin') || qrText.includes('wx') || qrText.includes('wechat')) {
console.log('✅ 检测到微信二维码:', qrText);
return true;
} else {
console.log('❌ 检测到二维码,但不是微信二维码:', qrText);
return false;
}
} catch (err) {
// 本次预处理未识别,继续尝试下一个
}
}
console.log('❌ ZXing 所有预处理均未识别二维码');
return false;
} catch (e) {
console.log('❌ isWeixinQRCode 整体异常:', e);
return false;
}
}