浏览器插件:图片抓取与下载工具
下面是一个完整的浏览器插件代码,可以抓取当前页面的所有图片,提供预览功能,并允许用户选择下载。
文件结构
image-downloader/
├── manifest.json
├── popup.html
├── popup.js
├── popup.css
└── icons/
├── icon48.png
└── icon128.png
1. manifest.json
{
"manifest_version": 3,
"name": "图片抓取与下载工具",
"version": "1.0",
"description": "抓取当前页面的所有图片并提供下载功能",
"permissions": ["activeTab", "downloads"],
"action": {
"default_popup": "popup.html",
"default_icon": {
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"icons": {
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
}
2. popup.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>图片抓取工具</title>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<div class="container">
<h1>页面图片抓取</h1>
<div class="controls">
<button id="fetchImages">抓取图片</button>
<button id="downloadSelected">下载选中图片</button>
<button id="selectAll">全选</button>
<button id="deselectAll">取消全选</button>
</div>
<div class="filter">
<label for="minWidth">最小宽度:</label>
<input type="number" id="minWidth" placeholder="最小宽度" min="0">
<label for="minHeight">最小高度:</label>
<input type="number" id="minHeight" placeholder="最小高度" min="0">
</div>
<div id="status"></div>
<div id="imageGallery"></div>
</div>
<script src="popup.js"></script>
</body>
</html>
3. popup.css
body {
width: 600px;
padding: 10px;
font-family: Arial, sans-serif;
}
.container {
display: flex;
flex-direction: column;
gap: 10px;
}
h1 {
font-size: 18px;
margin: 0 0 10px 0;
text-align: center;
}
.controls {
display: flex;
gap: 5px;
flex-wrap: wrap;
}
button {
padding: 5px 10px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #45a049;
}
.filter {
display: flex;
gap: 10px;
align-items: center;
flex-wrap: wrap;
}
.filter input {
width: 60px;
padding: 3px;
}
#status {
color: #666;
font-style: italic;
min-height: 20px;
}
#imageGallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 10px;
max-height: 500px;
overflow-y: auto;
margin-top: 10px;
}
.image-container {
border: 1px solid #ddd;
padding: 5px;
border-radius: 4px;
display: flex;
flex-direction: column;
align-items: center;
}
.image-container img {
max-width: 100%;
max-height: 100px;
object-fit: contain;
margin-bottom: 5px;
}
.image-info {
font-size: 12px;
text-align: center;
word-break: break-all;
}
.checkbox-container {
margin-top: 5px;
}
4. popup.js
document.addEventListener('DOMContentLoaded', function() {
const fetchImagesBtn = document.getElementById('fetchImages');
const downloadSelectedBtn = document.getElementById('downloadSelected');
const selectAllBtn = document.getElementById('selectAll');
const deselectAllBtn = document.getElementById('deselectAll');
const minWidthInput = document.getElementById('minWidth');
const minHeightInput = document.getElementById('minHeight');
const imageGallery = document.getElementById('imageGallery');
const statusDiv = document.getElementById('status');
let currentImages = [];
// 抓取页面图片
fetchImagesBtn.addEventListener('click', async function() {
statusDiv.textContent = '正在抓取图片...';
try {
const [tab] = await chrome.tabs.query({active: true, currentWindow: true});
// 注入内容脚本获取图片
const results = await chrome.scripting.executeScript({
target: {tabId: tab.id},
func: getPageImages,
});
if (results && results[0] && results[0].result) {
currentImages = results[0].result;
filterAndDisplayImages();
statusDiv.textContent = `找到 ${currentImages.length} 张图片`;
} else {
statusDiv.textContent = '未找到图片或发生错误';
}
} catch (error) {
console.error('抓取图片时出错:', error);
statusDiv.textContent = '抓取图片时出错: ' + error.message;
}
});
// 下载选中的图片
downloadSelectedBtn.addEventListener('click', function() {
const selectedImages = currentImages.filter(img => img.selected);
if (selectedImages.length === 0) {
statusDiv.textContent = '请先选择要下载的图片';
return;
}
statusDiv.textContent = `正在下载 ${selectedImages.length} 张图片...`;
selectedImages.forEach(img => {
chrome.downloads.download({
url: img.src,
filename: getFilenameFromUrl(img.src),
conflictAction: 'uniquify'
});
});
statusDiv.textContent = `已开始下载 ${selectedImages.length} 张图片`;
});
// 全选
selectAllBtn.addEventListener('click', function() {
currentImages.forEach(img => img.selected = true);
renderImages();
});
// 取消全选
deselectAllBtn.addEventListener('click', function() {
currentImages.forEach(img => img.selected = false);
renderImages();
});
// 过滤条件变化时重新显示图片
minWidthInput.addEventListener('change', filterAndDisplayImages);
minHeightInput.addEventListener('change', filterAndDisplayImages);
// 根据过滤条件筛选并显示图片
function filterAndDisplayImages() {
const minWidth = parseInt(minWidthInput.value) || 0;
const minHeight = parseInt(minHeightInput.value) || 0;
const filteredImages = currentImages.filter(img => {
return img.naturalWidth >= minWidth && img.naturalHeight >= minHeight;
});
renderImages(filteredImages);
}
// 渲染图片到画廊
function renderImages(imagesToRender = currentImages) {
imageGallery.innerHTML = '';
imagesToRender.forEach(img => {
const imgContainer = document.createElement('div');
imgContainer.className = 'image-container';
const imgElement = document.createElement('img');
imgElement.src = img.src;
imgElement.alt = '缩略图';
const imgInfo = document.createElement('div');
imgInfo.className = 'image-info';
imgInfo.textContent = `${img.naturalWidth}×${img.naturalHeight}`;
const checkboxContainer = document.createElement('div');
checkboxContainer.className = 'checkbox-container';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.checked = img.selected || false;
checkbox.addEventListener('change', function() {
img.selected = this.checked;
});
const checkboxLabel = document.createElement('label');
checkboxLabel.textContent = '选择';
checkboxContainer.appendChild(checkbox);
checkboxContainer.appendChild(checkboxLabel);
imgContainer.appendChild(imgElement);
imgContainer.appendChild(imgInfo);
imgContainer.appendChild(checkboxContainer);
imageGallery.appendChild(imgContainer);
});
}
// 从URL中提取文件名
function getFilenameFromUrl(url) {
try {
const urlObj = new URL(url);
const pathname = urlObj.pathname;
const filename = pathname.split('/').pop() || 'image';
// 如果文件名没有扩展名,添加一个
if (!filename.includes('.')) {
const extension = getImageExtensionFromUrl(url);
return `${filename}.${extension}`;
}
return filename;
} catch {
return 'image.jpg';
}
}
// 从URL中猜测图片扩展名
function getImageExtensionFromUrl(url) {
if (url.includes('.jpg') || url.includes('.jpeg')) return 'jpg';
if (url.includes('.png')) return 'png';
if (url.includes('.gif')) return 'gif';
if (url.includes('.webp')) return 'webp';
if (url.includes('.svg')) return 'svg';
if (url.includes('.bmp')) return 'bmp';
return 'jpg'; // 默认
}
});
// 在页面上下文中执行的函数,用于获取所有图片
function getPageImages() {
const images = Array.from(document.querySelectorAll('img, [style*="background-image"]'));
const result = [];
images.forEach(element => {
let src, naturalWidth, naturalHeight;
if (element.tagName === 'IMG') {
src = element.src;
naturalWidth = element.naturalWidth;
naturalHeight = element.naturalHeight;
} else {
// 处理背景图片
const style = window.getComputedStyle(element);
const bgImage = style.backgroundImage;
if (bgImage && bgImage !== 'none') {
src = bgImage.replace(/^url\(["']?/, '').replace(/["']?\)$/, '');
naturalWidth = element.offsetWidth;
naturalHeight = element.offsetHeight;
}
}
if (src && !src.startsWith('data:') && naturalWidth > 0 && naturalHeight > 0) {
result.push({
src,
naturalWidth,
naturalHeight,
selected: false
});
}
});
// 去重
const uniqueUrls = new Set();
return result.filter(img => {
if (uniqueUrls.has(img.src)) return false;
uniqueUrls.add(img.src);
return true;
});
}
5. 图标文件
你需要准备两个图标文件:
icons/icon48.png
(48×48像素)icons/icon128.png
(128×128像素)
可以使用简单的图片作为图标,或者从免费图标网站下载。
安装和使用说明
- 将上述文件按照结构保存到文件夹中
- 在Chrome浏览器中打开
chrome://extensions/
- 开启"开发者模式"
- 点击"加载已解压的扩展程序",选择你的文件夹
- 插件安装完成后,点击工具栏中的插件图标即可使用
功能特点
- 抓取当前页面的所有图片(包括IMG标签和背景图片)
- 显示每张图片的尺寸信息
- 可按最小宽度/高度过滤图片
- 支持单选、全选和取消全选
- 批量下载选中的图片
- 自动为下载的图片生成合适的文件名
这个插件可以帮助用户轻松抓取网页上的所有图片资源,并通过预览选择需要的图片进行下载。