Greasy Fork is available in English.

网站图片(背景图,svg,canvas)抓取预览下载

将站点所有的图片(背景图,svg,canvas)抓取提供预览,直接点击下载。

La data de 17-05-2019. Vezi ultima versiune.

  1. // ==UserScript==
  2. // @name 网站图片(背景图,svg,canvas)抓取预览下载
  3. // @namespace https://github.com/yujinpan/tampermonkey-extension
  4. // @version 2.1
  5. // @license MIT
  6. // @description 将站点所有的图片(背景图,svg,canvas)抓取提供预览,直接点击下载。
  7. // @author yujinpan
  8. // @include http*://**
  9. // ==/UserScript==
  10.  
  11. /**
  12. * 已有功能列表:
  13. * - 抓取页面上的图片链接,包括 **img,背景图,svg,canvas**
  14. * - 提供展示抓取的图片的列表快速预览
  15. * - 提供按钮快速切换抓取的图片展示区
  16. * - 提供快速下载,点击预览即可下载源图片文件
  17. * - 提供动态抓取后来加载的图片
  18. *
  19. * 2019-5-17 更新内容:
  20. * - 修复 svg,canvas 展示与下载问题
  21. * - 增加暗黑透明样式,黑色,白色图片区分明显
  22. * - 重构核心代码,分模块执行,提高可读性与维护性
  23. * - 兼容 iframe 的 btoa 方法报错
  24. */
  25.  
  26. (() => {
  27. // 存放抓取与生成的图片
  28. const urls = new Set();
  29.  
  30. // 初始化
  31. init();
  32.  
  33. /**
  34. * 初始化
  35. */
  36. function init() {
  37. // 创建样式
  38. createStyle();
  39.  
  40. // 创建容器
  41. const section = document.createElement('section');
  42. section.id = 'SIR';
  43. section.innerHTML = `
  44. <button class="SIR-toggle-button">自动获取图片</button>
  45. <div class="SIR-cover"></div>
  46. <ul class="SIR-main">
  47. </ul>
  48. `;
  49. document.body.append(section);
  50.  
  51. // 获取按钮与列表 DOM
  52. const button = section.querySelector('.SIR-toggle-button');
  53. const main = section.querySelector('.SIR-main');
  54.  
  55. // 切换时进行抓取
  56. let showMain = false;
  57. button.onclick = () => {
  58. showMain = !showMain;
  59. if (showMain) {
  60. imagesReptile();
  61. // content
  62. let imageList = '';
  63. urls.forEach((url) => {
  64. imageList += `
  65. <li>
  66. <a download="image" title="点击下载" href="${url}">
  67. <img src='${url}' />
  68. </a>
  69. </li>`;
  70. });
  71. main.innerHTML = imageList;
  72. } else {
  73. main.innerHTML = '';
  74. }
  75. section.classList.toggle('active', showMain);
  76. };
  77. }
  78.  
  79. /**
  80. * 获取资源列表
  81. */
  82. function imagesReptile() {
  83. const elements = Array.from(document.querySelectorAll('*'));
  84.  
  85. // 遍历取出 img,backgroundImage,svg,canvas
  86. for (const element of elements) {
  87. const tagName = element.tagName.toLowerCase();
  88.  
  89. // img 标签
  90. if (tagName === 'img') {
  91. urls.add(getImgUrl(element));
  92. continue;
  93. }
  94.  
  95. // svg
  96. if (tagName === 'svg') {
  97. urls.add(getSvgImage(element));
  98. continue;
  99. }
  100.  
  101. // canvas
  102. if (tagName === 'canvas') {
  103. urls.add(getCanvasImage(element));
  104. continue;
  105. }
  106.  
  107. // background-image
  108. const backgroundImage = getComputedStyle(element).backgroundImage;
  109. if (backgroundImage !== 'none' && backgroundImage.startsWith('url')) {
  110. urls.add(backgroundImage.slice(5, -2));
  111. }
  112. }
  113. }
  114.  
  115. /**
  116. * 创建样式
  117. */
  118. function createStyle() {
  119. const style = document.createElement('style');
  120. style.innerHTML = `
  121. #SIR.active .SIR-cover {
  122. display: block;
  123. }
  124. #SIR.active .SIR-main {
  125. display: flex;
  126. }
  127. .SIR-toggle-button {
  128. position: fixed;
  129. right: 0;
  130. bottom: 0;
  131. z-index: 99999;
  132. opacity: 0.5;
  133. background: white;
  134. }
  135. .SIR-toggle-button:hover {
  136. opacity: 1;
  137. }
  138. .SIR-cover,
  139. .SIR-main {
  140. display: none;
  141. position: fixed;
  142. width: 100%;
  143. height: 100%;
  144. top: 0;
  145. left: 0;
  146. }
  147. .SIR-cover {
  148. z-index: 99997;
  149. background: rgba(255, 255, 255, 0.7);
  150. }
  151. .SIR-main {
  152. z-index: 99998;
  153. overflow-y: auto;
  154. margin: 0;
  155. padding: 0;
  156. list-style-type: none;
  157. flex-wrap: wrap;
  158. text-align: center;
  159. background: rgba(0, 0, 0, 0.7);
  160. }
  161. .SIR-main > li {
  162. box-sizing: border-box;
  163. width: 10%;
  164. min-width: 168px;
  165. min-height: 100px;
  166. max-height: 200px;
  167. padding: 1px;
  168. box-shadow: 0 0 1px darkgrey;
  169. background: rgba(0, 0, 0, 0.5);
  170. overflow: hidden;
  171. }
  172. .SIR-main > li > a {
  173. display: flex;
  174. justify-content: center;
  175. align-items: center;
  176. width: 100%;
  177. height: 100%;
  178. }
  179. .SIR-main > li:hover img {
  180. transform: scale(1.5);
  181. }
  182. .SIR-main > li img {
  183. transition: transform .3s;
  184. max-width: 100%;
  185. }
  186. `;
  187. document.head.append(style);
  188. }
  189.  
  190. /**
  191. * 获取 svg 图片链接
  192. * @param {Elment} svg svg 元素
  193. */
  194. function getSvgImage(svg) {
  195. svg.setAttribute('version', 1.1);
  196. svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
  197.  
  198. try {
  199. return 'data:image/svg+xml;base64,' + btoa(svg.outerHTML);
  200. } catch (e) {
  201. console.log('svg创建失败');
  202. return '';
  203. }
  204. }
  205.  
  206. /**
  207. * 获取 canvas 图片链接
  208. * @param {Element} canvas canvas 元素
  209. */
  210. function getCanvasImage(canvas) {
  211. return canvas.toDataURL();
  212. }
  213.  
  214. /**
  215. * 获取 img 的链接
  216. * @description
  217. * 兼容 srcset 属性
  218. * @param {Element} element 图片元素
  219. */
  220. function getImgUrl(element) {
  221. let url;
  222.  
  223. // 兼容 srcset 属性
  224. if (element.srcset) {
  225. const srcs = element.srcset.split(',');
  226. url = srcs.reduce((pre, curr) => {
  227. curr = curr.trim();
  228. return curr.includes(' ') ? curr.split(' ')[0] : curr;
  229. }, '');
  230. } else {
  231. url = element.src;
  232. }
  233.  
  234. return url;
  235. }
  236. })();