一键下载网页所有图片(含dataurl格式图片)

无意间接触到一款浏览器插件,可以一键下载抓取网页中的所有图片,包括dataurl、bolb、普通链接图等;工作中得空,于是研究了一下并简单实现了一下;
在此过程中主要有以下几个难点:

  1. dataurl格式图片的抓取
  2. bolb格式图片的抓取
  3. a标签的download属性在图片跨域时失效的问题(点击标签时不会打开下载界面,而是会把当前窗口地址替换为该图片地址)
  4. 通过XHR请求图片也会存在的跨域问题
  5. 文件的批量下载

现在讲解一下实现思路:

  • 首先获取页面中的所有image元素 doucment.images
  • 循环遍历该类数组对象,获取image元素的src属性
    • 如果该src为正常的格式,如:https://xxx.com/image.png,那么可以通过直接将该图片地址赋值给一个新建的a标签的的href属性,并设置a标签的download属性
    • 如果该图片地址是dataurl格式,那么就通过atob函数将该dataurl先解码成blob数据,再通过a标签下载
// 正常图片下载
async function downloadFile(url, fileName) {
	return new Promise((resolve, reject) => {
		var x = new XMLHttpRequest()
		x.responseType = 'blob'
		x.onload = function (e) {
			var url = window.URL.createObjectURL(x.response)
			var a = document.createElement('a')
			a.href = url
			a.download = fileName
			a.click()
			a.remove()
			resolve()
		}
		x.onerror = reject
		x.open('GET', url)
		x.send()
	})
		.catch(console.log)
}
// dataurl转换成blob数据
function dataURLtoBlob(dataurl) {
    let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
    while(n--){
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], {type:mime});
}
// dataurl图片下载
function downloadFile2(fileName, content){
    var blob = new Blob([content]);
    var link = document.createElement("a");
    link.download = fileName;
    link.href = URL.createObjectURL(blob); 
    link.click()
    link.remove()
}
// 过滤函数 宽高必须大于等于指定值
function filter(width, height, image){
    return image.naturalHeight >= width && image.naturalWidth >= height
}
// 循环开启下载任务
async function justDoIt() {
	for (let i = 0, len = document.images.length; i < len; i++) {
		try {
			let img = document.images[i]
			// 筛选尺寸 默认宽度高度大于50
			if (!filter(50, 50, img)) {
				continue
			}
			let src = img.src
			let name_ext = src.split('?')[0].split('/')
			name_ext = name_ext[name_ext.length - 1].split('.')
			let name = img.title || img.alt || name_ext[0]
			let ext = name_ext[1] || 'jpg'
			if (src.split(':')[0] == 'data') {
				let arr = src.split(','),
					mime = arr[0].match(/:(.*?);/)
				let imgBolb = dataURLtoBlob(src)
				downloadFile2(new Date().valueOf() + '.' + mime[1].split('/')[1], imgBolb)
			} else {
				await downloadFile(src, name + '.' + ext)
			}
		} catch (e) {
			console.error(e)
		}
	}
}
justDoIt()

踩过的坑:

  • 通过src解析文件后缀名的时候出现undefined,后来排查发现并不是所有的图片文件地址都包含了后缀在这里插入图片描述
  • 通过XHR去请求图片文件的时候,部分会出现跨域问题(这个问题在浏览器插件里面不会出现,因为插件发送请求并没有跨域限制)
  • 最开始下载文件的时候,没有使用异步函数,这回导致同时发起的请求数量过多,超过浏览器限制,导致之后的那些任务没有下发成功(现在是通过async函数解决,但出现一个问题就是前一个任务完成后才开始第二个下载,这样无法发挥出并发请求的优势。优化思路:控制并发数量,只有请求数量小于一定值的时候才开始下一个任务)

实战:(csdn首页)
1、负责代码到如图的地方。
在这里插入图片描述
2、注意事项
在这里插入图片描述
首次使用时请点确认
在这里插入图片描述

3、结果
在这里插入图片描述
待优化:

  • 背景图片没有提取到
  • 下载图片时的并发请求控制
  • icon图片的提取
运行环境 .NET Framework2.0 开发工具 Microsoft Visual Studio 2005 二. 部分代码说明(主要讲解异步分析和下载): 异步分析下载采取的策略是同时分析同时下载,即未等待数据全部分析完毕就开始把已经分析出来的图片链接开始下载下载成功的均在List框链接前面划上了√ ,未能下载图片有可能是分析错误或者是下载异常。 1. 异步分析部分代码 /// /// 异步分析下载 /// private void AsyncAnalyzeAndDownload(string url, string savePath) { this.uriString = url; this.savePath = savePath; #region 分析计时开始 count = 0; count1 = 0; freq = 0; result = 0; QueryPerformanceFrequency(ref freq); QueryPerformanceCounter(ref count); #endregion using (WebClient wClient = new WebClient()) { AutoResetEvent waiter = new AutoResetEvent(false); wClient.Credentials = CredentialCache.DefaultCredentials; wClient.DownloadDataCompleted += new DownloadDataCompletedEventHandler(AsyncURIAnalyze); wClient.DownloadDataAsync(new Uri(uriString), waiter); //waiter.WaitOne(); //阻止当前线程,直到收到信号 } } /// /// 异步分析 /// protected void AsyncURIAnalyze(Object sender, DownloadDataCompletedEventArgs e) { AutoResetEvent waiter = (AutoResetEvent)e.UserState; try { if (!e.Cancelled && e.Error == null) { string dnDir = string.Empty; string domainName = string.Empty; string uri = uriString; //获得域名 http://www.sina.com/ Match match = Regex.Match(uri, @"((http(s)?://)?)+[\w-.]+[^/]");//, RegexOptions.IgnoreCase domainName = match.Value; //获得域名最深层目录 http://www.sina.com/mail/ if (domainName.Equals(uri
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值