最近在看华为昇腾在线课程,想下载到本地,发现没有下载按钮,就想到用豆包帮我怎么下载

谷歌浏览器打开课程页面,右键检查元素,发现每一页都是blob格式图片

遂用豆包帮我生成了一段脚本(大致功能是:将blob图片转换成png格式,去除重复,做成一个压缩包,并让用户选择保存位置)

// 第一步:仅加载JSZip(打包必需,简化加载逻辑+超时处理)
function loadJSZip() {
  return new Promise((resolve, reject) => {
    // 超时保护:10秒加载失败则提示
    const timeout = setTimeout(() => reject('JSZip加载超时(网络/CDN问题)'), 10000);
    
    if (window.JSZip) {
      clearTimeout(timeout);
      resolve(window.JSZip);
      return;
    }

    const script = document.createElement('script');
    // 备用CDN(主CDN失效时自动切换)
    script.src = 'https://lib.baomitu.com/jszip/3.10.1/jszip.min.js';
    script.onload = () => {
      clearTimeout(timeout);
      resolve(window.JSZip);
    };
    script.onerror = (err) => {
      clearTimeout(timeout);
      reject('JSZip加载失败:请检查网络,或手动复制JSZip源码到控制台运行');
    };
    document.head.appendChild(script);
  });
}

// 第二步:原生API计算Blob哈希(替代MD5,无外部依赖)
async function getBlobHash(blob) {
  try {
    // 1. 将Blob转为ArrayBuffer
    const arrayBuffer = await blob.arrayBuffer();
    // 2. 用浏览器原生API计算SHA-256哈希
    const hashBuffer = await window.crypto.subtle.digest('SHA-256', arrayBuffer);
    // 3. 将哈希转为十六进制字符串(便于存储和对比)
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
    return hashHex;
  } catch (err) {
    throw new Error(`哈希计算失败:${err.message}(可能是浏览器不支持原生Crypto API)`);
  }
}

// 第三步:将Blob图片转为PNG格式(逻辑不变)
async function convertToPngBlob(blobUrl) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.crossOrigin = 'anonymous';
    img.onerror = (err) => reject(`图片加载失败:${err.message}`);

    img.onload = () => {
      try {
        const canvas = document.createElement('canvas');
        canvas.width = img.width;
        canvas.height = img.height;
        const ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0);
        canvas.toBlob((pngBlob) => {
          pngBlob ? resolve(pngBlob) : reject('Canvas导出PNG失败');
        }, 'image/png');
      } catch (err) {
        reject(`转换PNG失败:${err.message}`);
      }
    };

    fetch(blobUrl)
      .then(res => res.blob())
      .then(blob => {
        img.src = URL.createObjectURL(blob);
        setTimeout(() => URL.revokeObjectURL(img.src), 1000);
      })
      .catch(err => reject(`获取Blob数据失败:${err.message}`));
  });
}

// 第四步:弹出保存对话框(逻辑不变)
async function saveFileWithPicker(blob, defaultFileName) {
  try {
    if (!window.showSaveFilePicker) {
      throw new Error('浏览器不支持自定义保存位置,将使用默认下载方式');
    }
    const fileHandle = await window.showSaveFilePicker({
      suggestedName: defaultFileName,
      types: [{ description: 'ZIP压缩包', accept: { 'application/zip': ['.zip'] } }],
    });
    const writable = await fileHandle.createWritable();
    await writable.write(blob);
    await writable.close();
    console.log(`文件已保存到你选择的位置:${fileHandle.name}`);
    return fileHandle.name;
  } catch (err) {
    if (err.name === 'AbortError') {
      alert('❌ 你取消了文件保存操作');
      return null;
    } else {
      console.warn('自定义保存失败,降级为默认下载:', err);
      const zipUrl = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = zipUrl;
      a.download = defaultFileName;
      a.click();
      URL.revokeObjectURL(zipUrl);
      return defaultFileName;
    }
  }
}

// 第五步:核心逻辑(去重+转PNG+打包,无外部哈希库)
async function saveUniqueBlobImagesAsPng() {
  try {
    // 1. 加载JSZip(仅这一个外部依赖)
    const JSZip = await loadJSZip();
    const zip = new JSZip();
    const hashSet = new Set(); // 存储已处理的图片哈希(去重核心)
    let totalCount = 0, duplicateCount = 0, successCount = 0;

    // 2. 获取所有Blob图片
    const blobImgs = document.querySelectorAll('img[src^="blob:"]');
    totalCount = blobImgs.length;
    if (totalCount === 0) {
      alert('未找到任何blob格式的图片!');
      return;
    }
    console.log(`找到 ${totalCount} 张blob图片,开始去重+转换PNG...`);

    // 3. 遍历处理(去重+转PNG)
    for (const img of blobImgs) {
      try {
        // 3.1 先转为PNG Blob
        const pngBlob = await convertToPngBlob(img.src);
        // 3.2 用原生API计算哈希(替代MD5)
        const imgHash = await getBlobHash(pngBlob);

        // 3.3 去重判断
        if (hashSet.has(imgHash)) {
          duplicateCount++;
          console.log(`跳过重复图片(哈希:${imgHash.substring(0, 8)}...)`);
          continue;
        }

        // 3.4 保留唯一图片
        hashSet.add(imgHash);
        successCount++;
        const imgName = `blob_image_${successCount}.png`;
        zip.file(imgName, pngBlob);
        console.log(`已添加唯一PNG图片:${imgName}(哈希:${imgHash.substring(0, 8)}...)`);
      } catch (err) {
        console.error(`处理图片失败:`, err);
        continue;
      }
    }

    // 4. 校验结果
    if (successCount === 0) {
      alert('没有成功保留任何唯一图片!');
      return;
    }

    // 5. 生成ZIP包并保存
    const zipBlob = await zip.generateAsync({ type: 'blob' });
    const defaultFileName = `unique_blob_images_png_${new Date().getTime()}.zip`;
    const savedFileName = await saveFileWithPicker(zipBlob, defaultFileName);

    // 6. 最终反馈
    if (savedFileName) {
      alert(`✅ 处理完成!
总图片数:${totalCount} 张
重复图片数:${duplicateCount} 张
保留唯一PNG图片数:${successCount} 张
压缩包已保存(文件名:${savedFileName})`);
    }

  } catch (err) {
    console.error('整体执行失败:', err);
    alert('抓取失败:' + err.message);
  }
}

// 执行脚本(直接调用即可)
saveUniqueBlobImagesAsPng();

粘贴到console页面

回车执行(注意执行前最后把ppt里面每一页都加载完成浏览一下,不然导出的图片不全)

保存到电脑本地就行

解压后发现文件都在

打开WPS,新建PDF,选择从图片新建

点击添加图片,选择解压后的所有图片

点击模板拼接,导出即可

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐