You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js同步XMLHttpRequest设置responseType为arraybuffer及图片解密问询

漫画网站图片爬取问题及解决方案

问题说明

  • 爬取某漫画网站图片时,网站采用加密算法获取图片并解析为Blob链接,需在解密步骤后终止流程,返回Uint8Array,再通过Python代码写入文件。
  • 咨询:Node.js v18.3.0环境下,使用async:false的XMLHttpRequest时,能否设置responseType为arraybuffer?

同步XHR设置responseType的说明

通过jsdom模拟的XMLHttpRequest在同步模式下理论上支持设置responseType: 'arraybuffer',但存在版本兼容性问题,且同步XHR本身不被现代环境推荐。更可靠的方式是改用Node.js原生http/https模块发起同步请求,直接获取二进制数据。

修正后的实现代码

1. getAndDecrypt.js(核心解密逻辑)

const CryptoJS = require("crypto-js");
const https = require("https");
const { URL } = require("url");

// 与网站一致的解密密钥
const secretKey = "my2ecret782ecret";

// 同步获取远程图片的ArrayBuffer
function getSyncArrayBuffer(url) {
    const urlObj = new URL(url);
    let chunks = [];
    const buffer = Buffer.from(new Promise((resolve, reject) => {
        const req = https.request({
            hostname: urlObj.hostname,
            path: urlObj.pathname + urlObj.search,
            method: 'GET'
        }, (res) => {
            res.on('data', chunk => chunks.push(chunk));
            res.on('end', () => resolve(Buffer.concat(chunks)));
        });
        req.on('error', reject);
        req.end();
    }));
    return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
}

// 将CryptoJS WordArray转为Uint8Array
function wordArrayToUint8Array(wordArray) {
    const uint8Array = new Uint8Array(wordArray.sigBytes);
    let byteIndex = 0;
    for (const word of wordArray.words) {
        uint8Array[byteIndex++] = (word >> 24) & 0xff;
        if (byteIndex === uint8Array.length) break;
        uint8Array[byteIndex++] = (word >> 16) & 0xff;
        if (byteIndex === uint8Array.length) break;
        uint8Array[byteIndex++] = (word >> 8) & 0xff;
        if (byteIndex === uint8Array.length) break;
        uint8Array[byteIndex++] = word & 0xff;
        if (byteIndex === uint8Array.length) break;
    }
    return uint8Array;
}

// AES解密函数
function decryptData(arrayBuffer, key) {
    const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer);
    const decrypted = CryptoJS.AES.decrypt({
        ciphertext: wordArray
    }, CryptoJS.enc.Utf8.parse(key), {
        iv: CryptoJS.enc.Utf8.parse(key),
        padding: CryptoJS.pad.Pkcs7
    });
    return wordArrayToUint8Array(decrypted);
}

// 对外暴露的入口函数
function getDecryptedImage(url) {
    const arrayBuffer = getSyncArrayBuffer(url);
    return decryptData(arrayBuffer, secretKey);
}

module.exports = { getDecryptedImage };

2. Python调用代码

import execjs

def read_js_file(filename):
    with open(filename, 'r', encoding='utf-8') as f:
        return f.read()

def get_decrypted_image(url):
    js_code = read_js_file('getAndDecrypt.js')
    ctx = execjs.compile(js_code)
    uint8array = ctx.call('getDecryptedImage', url)
    # 转换为Python可写入的bytes类型
    return bytes(uint8array.values())

if __name__ == '__main__':
    target_url = 'https://img.mwimser2.cc/static/upload/book/id/18928/547567/4c8ca89af48c44d45893f959b16447b2.webp?v=20220724'
    image_bytes = get_decrypted_image(target_url)
    with open('a.webp', 'wb') as f:
        f.write(image_bytes)

关键修改点

  • 替换jsdom模拟XHR为Node.js原生https模块,彻底避免同步XHR的responseType兼容性问题。
  • 补全原代码中缺失的二进制转换逻辑,确保数据流转正确。
  • 优化解密后Uint8Array到Pythonbytes的转换逻辑,保证写入文件的图片可正常打开。

内容的提问来源于stack exchange,提问作者openwld

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 22:48:51