当前位置: 首页 > java >正文

(3)从零开发 Chrome 插件:网页图片的批量下载

(1)从零开发 Chrome 插件:构建你的第一个插件
(3)从零开发 Chrome 插件:实现 API 登录与本地存储功能
(3)从零开发 Chrome 插件:网页图片的批量下载
(4)从零开发 Chrome 插件:Chrome插件调试全攻略

我们常常会遇到需要保存页面图片的情况。一张两张手动保存还好,但要是遇到图片数量较多的页面,那就比较痛苦。基于这样的痛点,我开发了一款 Chrome 图片下载插件,能实现网页图片的批量下载。下面就来详细分享这款插件的开发过程。

一 插件核心功能

在这里插入图片描述

当用户点击浏览器工具栏中的插件图标时,会弹出一个操作界面。在这个界面里,用户可以进行一系列设置,比如给要下载的图片设置文件名前缀,用正则表达式来过滤不需要的图片 URL,还能选择是否只下载当前页面中可见的图片。

完成设置后,用户点击 “开始下载图片” 按钮,插件就会启动内容脚本。内容脚本会注入到当前正在浏览的网页中,收集页面里所有 img 标签对应的图片资源。在收集过程中,它会对图片的 URL 格式进行处理,比如把相对路径转换成绝对路径,然后根据用户设置的过滤规则,筛选出符合条件的图片,再把这些图片的信息发送到后台脚本。。

二 程序流程深度解析

用户点击插件图标,弹出操作界面加载完成。用户在界面中输入文件名前缀、设置过滤规则等信息,接着点击确认下载按钮。此时,内容脚本启动,开始提取图片的 src 或者 data-src 属性值,将其中的相对路径转换为绝对路径。然后,根据用户设置的规则对图片进行筛选,筛选出符合条件的图片后,把图片列表发送到后台脚本。后台脚本接收图片列表后,调用 Chrome 下载 API,循环下载图片并保存到本地指定路径。最后,判断所有图片是否都下载完成,如果完成,就显示下载完成的通知,整个流程到此结束。

三 功能详细说明

1. 用户交互层

这一层是用户与插件进行交互的主要部分。当用户点击浏览器工具栏中的插件图标时,会触发弹出界面(由 popup.html 实现)的加载。用户在这个界面中设置下载参数,比如文件名前缀、过滤规则等,然后确认下载操作,这一系列动作都属于用户交互层的范畴。

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>图片下载器</title><script src="popup.js"></script><style>body {width: 350px;padding: 10px;font-family: Arial, sans-serif;margin: 0;}.container {padding: 10px;}h3 {margin-top: 0;color: #333;}.section {margin-bottom: 15px;}.section label {display: block;margin-bottom: 5px;font-weight: bold;}.section input, .section textarea {width: 100%;padding: 8px;box-sizing: border-box;border: 1px solid #ddd;border-radius: 4px;}.checkbox-group {margin-bottom: 10px;}.checkbox-group label {font-weight: normal;margin-left: 5px;}button {background-color: #4CAF50;color: white;padding: 10px 15px;border: none;border-radius: 4px;cursor: pointer;width: 100%;font-size: 16px;}button:hover {background-color: #45a049;}.status {margin-top: 10px;padding: 8px;border-radius: 4px;display: none;}.status.success {background-color: #d4edda;color: #155724;}.status.error {background-color: #f8d7da;color: #721c24;}.image-count {margin-top: 5px;font-size: 12px;color: #666;}</style>
</head>
<body><div class="container"><h3>图片下载器</h3><div class="section"><label for="prefix">文件名前缀 (可选):</label><input type="text" id="prefix" placeholder="例如: mysite_"></div><div class="section"><label for="filter">图片URL过滤 (正则表达式, 可选):</label><input type="text" id="filter" placeholder="例如: \.(jpg|png|gif)$"></div><div class="checkbox-group"><input type="checkbox" id="onlyVisible" checked><label for="onlyVisible">仅下载可见图片</label></div><button id="downloadBtn">开始下载图片</button><div id="status" class="status"></div><div class="image-count">找到 <span id="imageCount">0</span> 张图片</div></div>
</body>
</html>    
2. 用户交互层脚 popup.js
document.addEventListener('DOMContentLoaded', () => {const downloadBtn = document.getElementById('downloadBtn');const status = document.getElementById('status');const imageCount = document.getElementById('imageCount');const prefixInput = document.getElementById('prefix');const filterInput = document.getElementById('filter');const onlyVisibleCheckbox = document.getElementById('onlyVisible');// 新增目录输入元素const directoryInput = document.getElementById('directory');// 初始获取图片数量updateImageCount();// 监听下载按钮点击事件downloadBtn.addEventListener('click', () => {// 显示加载状态showStatus('正在收集图片...', 'success');// 获取当前活动标签页chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {const activeTab = tabs[0];// 向content script发送消息获取图片chrome.tabs.sendMessage(activeTab.id, {action: 'getImages',filter: filterInput.value,onlyVisible: onlyVisibleCheckbox.checked}, (response) => {if (chrome.runtime.lastError) {showStatus('无法获取图片: ' + chrome.runtime.lastError.message, 'error');return;}if (!response || !response.images || response.images.length === 0) {showStatus('没有找到符合条件的图片', 'error');return;}const images = response.images;const prefix = prefixInput.value;// 显示下载信息showStatus(`找到 ${images.length} 张图片,开始下载...`, 'success');// 发送消息到background.js进行下载chrome.runtime.sendMessage({action: 'downloadImages',images: images,prefix: prefix});// 关闭弹出窗口window.close();});});});// 监听过滤条件变化,更新图片数量filterInput.addEventListener('input', updateImageCount);onlyVisibleCheckbox.addEventListener('change', updateImageCount);// 更新图片数量function updateImageCount() {// 获取当前活动标签页chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {const activeTab = tabs[0];// 向content script发送消息获取图片chrome.tabs.sendMessage(activeTab.id, {action: 'getImages',filter: filterInput.value,onlyVisible: onlyVisibleCheckbox.checked}, (response) => {if (!chrome.runtime.lastError && response && response.images) {imageCount.textContent = response.images.length;} else {imageCount.textContent = '?';}});});}// 显示状态信息function showStatus(message, type) {status.textContent = message;status.className = `status ${type}`;status.style.display = 'block';}
});
3.配置文件
{"manifest_version": 3,"name": "图片下载器","version": "1.0","description": "一键下载当前页面上的所有图片","permissions": ["activeTab","downloads","storage","tabs","scripting"],"background": {"service_worker": "background.js"},"action": {"default_popup": "popup.html","default_icon": {"16": "icon16.png"}},"content_scripts": [{"matches": ["<all_urls>"],"js": ["content.js"]}],"icons": {"16": "icon16.png"}
}

这个一定要配置
**downloads ** 下载权限
**storage ** 存储权限

4.连接层context
是连接网页和后台脚本的桥梁。它会被注入到当前正在浏览的网页中,负责提取页面中图片的 src 或者 data-src 属性值。在提取过程中,它会处理 URL 路径,把相对路径转换为绝对路径,以确保图片能够被正确访问。之后,它会根据用户设置的过滤规则,筛选出符合条件的图片,并把这些图片的列表发送给后台脚本。
// 监听来自popup的消息
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {if (message.action === 'getImages') {const { filter, onlyVisible } = message;// 收集页面上的所有图片let images = Array.from(document.querySelectorAll('img')).map(img => {let src = img.src;debugger;// 处理data-src等替代属性if (!src && img.dataset.src) src = img.dataset.src;if (!src && img.dataset.origSrc) src = img.dataset.origSrc;if (!src && img.dataset.lazySrc) src = img.dataset.lazySrc;// 跳过没有有效src的图片if (!src) return null;// 处理相对URLif (!src.startsWith('http') && !src.startsWith('data:')) {try {src = new URL(src, window.location.href).href;} catch (e) {return null;}}// 跳过data:URL的图片(通常是小图标或临时图片)if (src.startsWith('data:')) return null;return {src: src,width: img.naturalWidth || img.offsetWidth,height: img.naturalHeight || img.offsetHeight,alt: img.alt || '',isVisible: isElementInViewport(img)};}).filter(img => img !== null);// 过滤可见图片if (onlyVisible) {images = images.filter(img => img.isVisible);}// 应用正则表达式过滤if (filter && filter.trim() !== '') {try {const regex = new RegExp(filter, 'i');images = images.filter(img => regex.test(img.src) || regex.test(img.alt));} catch (e) {console.error('无效的正则表达式:', filter);}}// 返回图片列表sendResponse({ images });}return true; // 保持消息通道打开,直到sendResponse被调用
});// 检查元素是否在视口中
function isElementInViewport(el) {const rect = el.getBoundingClientRect();return (rect.top >= 0 &&rect.left >= 0 &&rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&rect.right <= (window.innerWidth || document.documentElement.clientWidth));
}
5. 后台处理层

后台脚本(background.js)是插件的核心处理部分。它接收内容脚本发送过来的图片列表后,会调用 Chrome 浏览器的 downloads API,循环对列表中的图片进行下载操作,并将图片保存到本地用户指定的路径中。在下载过程中,它还会监控下载进度,判断所有图片是否都下载完成。

// background.js
// 监听来自content script的消息
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {if (message.action === 'downloadImages') {const { images, prefix } = message;let downloaded = 0;let failed = 0;// 逐个下载图片images.forEach((image, index) => {// 生成唯一的文件名const filename = generateFilename(image.src, prefix, index);debugger;// 创建下载任务chrome.downloads.download({url: image.src,filename: filename,saveAs: false}, (downloadId) => {if (!downloadId) {console.error('下载失败:', chrome.runtime.lastError, image.src);} else {downloaded++;}// 当所有下载任务都完成后,发送通知if (index === images.length - 1) {sendNotification(downloaded, failed);}});});}
});// 生成文件名
function generateFilename(url, prefix, index) {try {// 尝试从URL中提取文件名const urlObj = new URL(url);let filename = urlObj.pathname.split('/').pop();// 如果没有扩展名,添加.jpgif (!filename.includes('.')) {filename += '.jpg';}// 移除不合法的文件名字符filename = filename.replace(/[\\/:*?"<>|]/g, '_');// 添加前缀if (prefix && prefix.trim() !== '') {return `${prefix.trim()}_${filename}`;}return filename;} catch (e) {// 如果URL解析失败,生成一个通用文件名return `${prefix || 'image'}_${index}.jpg`;}
}// 发送下载完成通知
function sendNotification(downloaded, failed) {chrome.notifications.create({type: 'basic',iconUrl: 'icon128.png',title: '图片下载完成',message: `成功下载 ${downloaded} 张图片,${failed} 张失败。`});
}    
6.反馈层

当后台脚本判断所有图片都下载完成后,会通过 Chrome 浏览器的 notifications API 向用户发送下载完成的通知,让用户及时了解下载状态,这就是反馈层的功能。

http://www.xdnf.cn/news/15419.html

相关文章:

  • 辨析git reset三种模式以及和git revert的区别:回退到指定版本和撤销指定版本的操作
  • 【Ubuntu22.04】repo安装方法
  • 基于STM32的智能火灾报警系统设计
  • AI|大模型入门(六):GPT→盘古,国内外大模型矩阵速览
  • kotlin布局交互
  • 响应式编程入门教程第三节:ReactiveCommand 与 UI 交互
  • 【PTA数据结构 | C语言版】创建哈夫曼树
  • 医疗数据分析中标准化的作用
  • Java项目:基于SSM框架实现的学生档案管理系统【ssm+B/S架构+源码+数据库+毕业论文+开题报告】
  • 剑指offer62_骰子的点数
  • Vue3入门-指令
  • brupsuite使用中遇到的一些问题(bp启动后浏览器无法连接)/如何导入证书
  • 智能体技术深度解析:从概念到企业级搭建指南
  • 安全参綉25暑假第一次作业
  • Student后台管理系统查询接口
  • CentOS服务器安装Supervisor使队列可以在后台运行
  • GAMES101 lec2-数学基础1(线性代数)
  • 为何说分布式 AI 推理已成为下一代计算方式
  • 特殊的整数-水仙花数
  • 【c++】c++11新特性(右值引用和移动语义)
  • Java报表导出框架
  • 详解BIO,NIO,AIO
  • 【git fetch submodule报错】Errors during submodule fetch 如何解决?
  • 【Java EE】多线程-初阶 认识线程(Thread)
  • urlencode、html实体编码、unicode
  • 进程---基础知识+命令+函数(fork+getpid+exit+wait+exec)
  • ACL流量控制实验
  • 12.如何判断字符串是否为空?
  • 记字节前端面试一道简单的算法题
  • 游戏玩法的专利博弈