您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Collect pictures of paginated structure picture website
- // ==UserScript==
- // @name picture_collector
- // @namespace http://tampermonkey.net/
- // @version 1.0.5
- // @description Collect pictures of paginated structure picture website
- // @author petitepluie
- // @match http://pic.netbian.com/*
- // @match http://www.gaoimg.com/*
- // @match *://desk.zol.com.cn/*
- // @match https://588ku.com/*
- // @match https://www.pixivacg.com/*
- // @match https://www.10wallpaper.com/*
- // @match http://www.netbian.com/*
- // @grant none
- // @license MIT
- // ==/UserScript==
- (function(){
- //获取本页地址
- var selfUrl=window.location.href;
- //添加界面css
- var mystyle=document.createElement("style");
- mystyle.innerHTML=`#popUpBox {
- position:fixed;
- top:0;
- right:-618px;
- z-index:10000;
- width:650px;
- height:20px;
- overflow-y:scroll;
- border:1px solid blue;
- background:#fff;
- }
- #boxCont {
- display:none;
- }
- #showAllConfig {
- width:100%;
- }
- #boxTitle {
- width:100%;
- height:22px;
- color:#fff;
- background:#0451ad;
- }
- #show_hid {
- width:32px;
- height:18px;
- line-height:15px;
- color:#0451ad;
- font-size:15px;
- font-weight:bold;
- }
- #baseOptionPlace {
- width:100%;
- height:50px;
- }
- #baseOptionCont {
- float:left;
- width:90%;
- height:100%;
- }
- #baseOptionCont span {
- font-size:12px;
- }
- #baseOptionCont input {
- height:10px;
- }
- .baseOption {
- width:100%;
- height:50%;
- }
- .reqLinkTitle {
- float:left;
- width:15%;
- height:100%;
- text-indent:5px;
- background:#c5dcfb;
- }
- .reqLinkCont {
- float:left;
- width:85%;
- height:100%;
- }
- #baseOptionTitle {
- float:right;
- width:10%;
- height:100%;
- background:#438dec;
- }
- #boxOptionPlace {
- width:100%;
- }
- .boxOption {
- width:100%;
- height:100px;
- margin-top:6px;
- border-top:2px solid blue;
- border-bottom:2px solid blue;
- }
- .boxOptionCont {
- float:left;
- width:90%;
- height:100%;
- }
- .options {
- width:100%;
- height:33%;
- border-bottom:0.5px solid blue;
- }
- .optionsTitle {
- float:left;
- width:15%;
- height:100%;
- line-height:30px;
- text-indent:5px;
- background:#c5dcfb;
- }
- .optionsCont {
- float:right;
- width:85%;
- height:100%;
- }
- .options span {
- font-size:12px;
- }
- .options input {
- height:10px;
- }
- .optionsContCube {
- float:left;
- width:50%;
- height:100%;
- }
- .optionsContName {
- width:100%;
- height:40%;
- line-height:10px;
- text-align:center;
- border-left:2px solid #fff;
- background:#deebf3;
- }
- .optionsContInput {
- width:100%;
- height:60%;
- line-height:15px;
- }
- .inputName {
- width:28%;
- }
- .inputNumb {
- width:12%;
- }
- .inputLink {
- width:56%;
- }
- .boxOptionTitle {
- float:right;
- width:10%;
- height:100%;
- background:#438dec;
- }
- .boxOptionTitle span {
- font-size:18px;
- color:#fff;
- }
- #dealOptionPlace {
- width:100%;
- height:36px;
- }
- .dealBtn {
- float:left;
- width:14%;
- height:25px;
- line-height:25px;
- margin:5px 10px;
- font-size:12px;
- text-align:center;
- border-radius:3px;
- background:rgba(0,0,0,0.5);
- transition:all 0.1s linear;
- cursor: pointer;
- }
- #start {
- background:#438dec;
- color:#fff;
- }
- #add {
- background:#c9defb;
- }
- #redu {
- background:#c9defb;
- }
- #add:hover {
- background:#438dec;
- color:#fff;
- }
- #redu:hover {
- background:#438dec;
- color:#fff;
- }
- #showCollectState {
- width:100%;
- height:40px;
- border-top:1px solid blue;
- }
- #sCsTitle {
- float:left;
- width:13%;
- height:100%;
- line-height:40px;
- font-size:14px;
- font-weight:bold;
- text-align:center;
- color:#0451ad;
- }
- #sCsCont {
- float:left;
- width:87%;
- height:100%;
- line-height:40px;
- }
- #showAllPicture {
- width:100%;
- height:490px;
- background:#438dec;
- overflow-y:scroll;
- }
- .cubeBox {
- float:left;
- width:85px;
- height:50px;
- margin:1px;
- background:rgba(0,0,0,0.5);
- overflow:hidden;
- }
- .cubeBox img {
- width:100%;
- }`;
- document.head.append(mystyle);
- //创建界面html
- var interFace=document.createElement('div');
- interFace.id='popUpBox';
- interFace.innerHTML=`
- <div id="boxTitle">
- <button id="show_hid"><<</button>
- <span>图片采集器(v.1.0.5)</span>
- </div>
- <div id="boxCont">
- <div id="showAllConfig">
- <div id="baseOptionPlace">
- <div id="baseOptionCont">
- <div class="baseOption">
- <div class="reqLinkTitle"><span>分页链接拆分</span></div>
- <div class="reqLinkCont">
- <span>索引前:</span><input class="inputLink" type="text">
- <span>索引后:</span><input class="inputNumb" type="text">
- </div>
- </div>
- <div class="baseOption">
- <div class="reqLinkTitle"><span>采集分页范围</span></div>
- <div class="reqLinkCont">
- <span>开始索引:</span><input class="inputNumb" type="number" min="2">
- <span>结束索引:</span><input class="inputNumb" type="number" min="2">
- </div>
- </div>
- </div>
- <div id="baseOptionTitle">基础信息配置</div>
- </div>
- <div id="boxOptionPlace"></div>
- <div id="dealOptionPlace">
- <div id="start" class="dealBtn">开始采集</div>
- <div id="add" class="dealBtn">选择器+</div>
- <div id="redu" class="dealBtn">选择器-</div>
- </div>
- </div>
- <div id="showCollectState">
- <div id="sCsTitle">采集状态:</div>
- <div id="sCsCont">null</div>
- </div>
- <div id="showAllPicture">
- <div class="cubeBox"></div>
- <div class="cubeBox"></div>
- <div class="cubeBox"></div>
- <div class="cubeBox"></div>
- <div class="cubeBox"></div>
- <div class="cubeBox"></div>
- <div class="cubeBox"></div>
- </div>
- </div>`;
- document.body.append(interFace);
- //添加界面逻辑
- var popUpBox=document.getElementById("popUpBox");
- var boxCont=document.getElementById("boxCont");
- var show_hid=document.getElementById("show_hid");
- var display=false;
- show_hid.onclick=function(){
- if(display){
- startMove(popUpBox,{
- "height":20,
- "right":-618
- },function(){
- display=false;
- show_hid.innerHTML="<<";
- })
- } else {
- boxCont.style.display="block";
- startMove(popUpBox,{
- "height":750,
- "right":0
- },function(){
- display=true;
- show_hid.innerHTML=">>";
- })
- }
- }
- var boxOptionPlace=document.getElementById('boxOptionPlace');
- boxOptionPlace.n=0;
- var boxOption=document.getElementsByClassName("boxOption");
- var add=document.getElementById("add");
- var redu=document.getElementById("redu");
- add.onclick=function(){
- var boxOptionTemp=document.createElement('div');
- boxOptionTemp.className='boxOption';
- boxOptionTemp.innerHTML=`
- <div class="boxOptionCont">
- <div class="options">
- <div class="optionsTitle"><span>父级节点</span></div>
- <div class="optionsCont parent">
- <div class="optionsContCube">
- <div class="optionsContName"><span>id</span></div>
- <div class="optionsContInput">
- <span>名称:</span><input class="inputName" type="text">
- </div>
- </div>
- <div class="optionsContCube">
- <div class="optionsContName"><span>class</span></div>
- <div class="optionsContInput">
- <span>名称:</span><input class="inputName" type="text">
- <span>索引:</span><input class="inputNumb" type="number" min="0">
- </div>
- </div>
- </div>
- </div>
- <div class="options">
- <div class="optionsTitle"><span>子级节点集</span></div>
- <div class="optionsCont children">
- <div class="optionsContCube">
- <div class="optionsContName"><span>tag</span></div>
- <div class="optionsContInput">
- <span>名称:</span><input class="inputName" type="text">
- </div>
- </div>
- <div class="optionsContCube">
- <div class="optionsContName"><span>class</span></div>
- <div class="optionsContInput">
- <span>名称:</span><input class="inputName" type="text">
- </div>
- </div>
- </div>
- </div>
- <div class="options">
- <div class="optionsTitle"><span>目标元素位置</span></div>
- <div class="optionsCont flower">
- <div class="optionsContCube">
- <div class="optionsContName"><span>tag</span></div>
- <div class="optionsContInput">
- <span>名称:</span><input class="inputNumb" type="text">
- <span>索引:</span><input class="inputNumb" type="number" min="0">
- <span>属性:</span><input class="inputNumb" type="text" min="0">
- </div>
- </div>
- <div class="optionsContCube">
- <div class="optionsContName"><span>class</span></div>
- <div class="optionsContInput">
- <span>名称:</span><input class="inputNumb" type="text">
- <span>索引:</span><input class="inputNumb" type="number" min="0">
- <span>属性:</span><input class="inputNumb" type="text" min="0">
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="boxOptionTitle"><span>${++boxOptionPlace.n}级</span>页面元素选择器</div>`;
- boxOptionPlace.appendChild(boxOptionTemp);
- }
- redu.onclick=function(){
- if(boxOptionPlace.n==0) return;
- boxOptionPlace.removeChild(boxOption[--boxOptionPlace.n]);
- }
- add.click();
- /**
- * 输入数据处理
- */
- //基础数据获取
- var baseOptionCont=document.getElementById('baseOptionCont');
- var baseOptionData=baseOptionCont.getElementsByTagName('input');
- var arrUrlFirst=[];
- var start=document.getElementById('start');
- //父级选择器获取
- var parent=document.getElementsByClassName('parent');
- //子级选择器获取
- var children=document.getElementsByClassName('children');
- //flower选择器获取
- var flower=document.getElementsByClassName('flower');
- //存放临时选择器数据的容器
- var arrPCFselect=[[],[],[]];
- //存放最终选择器数据的容器
- var arrSelector=[];
- //显示提示的容器
- var sCsCont=document.getElementById('sCsCont');
- start.onclick=function(){
- arrUrlFirst=[];
- if(baseOptionData[0].value!=''&&baseOptionData[1].value!=''&&baseOptionData[2].value!=''&&baseOptionData[3].value!=''){
- if(parseInt(baseOptionData[2].value)>parseInt(baseOptionData[3].value)){
- sCsCont.innerHTML='<span style="color:red">开始索引勿大于结束索引!</span>';
- return;
- }
- for(let i=parseInt(baseOptionData[2].value);i<=parseInt(baseOptionData[3].value);i++){
- arrUrlFirst.push(baseOptionData[0].value+i+baseOptionData[1].value);
- }
- } else {
- sCsCont.innerHTML='<span style="color:red">基础数据需填写完全,请检查!</span>';
- return;
- }
- //清空容器
- arrPCFselect=[[],[],[]];
- arrSelector=[];
- //存放临时选择器数据
- for(let i=0;i<boxOptionPlace.n;i++){
- //父级选择器
- var prtInput=parent[i].getElementsByTagName('input');
- if(prtInput[0].value!=''){
- arrPCFselect[0].push('id___'+prtInput[0].value);
- } else if(prtInput[1].value!=''&&prtInput[2].value!='') {
- arrPCFselect[0].push('class___'+prtInput[1].value+'___'+prtInput[2].value);
- } else {
- sCsCont.innerHTML='<span style="color:red">'+(i+1)+'级页面的父级节点选择器配置不能为空,请检查!</span>';
- return;
- }
- //子级选择器
- var cldInput=children[i].getElementsByTagName('input');
- if(cldInput[0].value!=''){
- arrPCFselect[1].push('tag___'+cldInput[0].value);
- } else if(cldInput[1].value!='') {
- arrPCFselect[1].push('class___'+cldInput[1].value);
- } else {
- sCsCont.innerHTML='<span style="color:red">'+(i+1)+'级页面的子级节点集选择器配置不能为空,请检查!</span>';
- return;
- }
- //flower选择器
- var flrInput=flower[i].getElementsByTagName('input');
- if(flrInput[0].value!=''&&flrInput[1].value!=''&&flrInput[2].value!=''){
- arrPCFselect[2].push('tag___'+flrInput[0].value+'___'+flrInput[1].value+'___'+flrInput[2].value);
- } else if(flrInput[3].value!=''&&flrInput[4].value!=''&&flrInput[5].value!='') {
- arrPCFselect[2].push('class___'+flrInput[3].value+'___'+flrInput[4].value+'___'+flrInput[5].value);
- } else {
- sCsCont.innerHTML='<span style="color:red">'+(i+1)+'级页面的目标元素选择器配置不能为空,请检查!</span>';
- return;
- }
- }
- //console.log("临时选择器数据如下:");
- //console.log(JSON.stringify(arrPCFselect));
- //获取最终选择器数据
- for(let i=0;i<boxOptionPlace.n;i++){
- var timerObj={
- parent:`${arrPCFselect[0][i]}`,
- children:`${arrPCFselect[1][i]}`,
- flower:`${arrPCFselect[2][i]}`
- }
- arrSelector.push(timerObj);
- }
- console.log("基础配置数据如下:");
- console.log(arrUrlFirst);
- console.log("最终选择器结果如下:");
- console.log(arrSelector);
- //清空待请求队列
- watingRequest=[];
- //设置清秋层级
- intDiving=arrSelector.length;
- //放入待请求队列集合
- watingRequest.push(arrUrlFirst);
- //记录队列长度
- watingLength.push(arrUrlFirst.length);
- console.log("队列结果如下:");
- console.log(watingRequest);
- if("当前没有其他采集任务"){
- console.log("执行采集任务");
- sCsCont.innerHTML='<span style="color:purple">采集中,请稍等...</span>';
- //开启采集程序
- spider();
- }
- }
- /*******************采集核心代码**************************/
- //存放各级待请求队列集合
- var watingRequest=[];
- var watingLength=[];
- var intDiving=0;
- var j=0;
- var finalResult=[];
- function spider(){
- ajax({
- url:watingRequest[j][0],
- type:"GET",
- sync:true,
- responseType:"document",
- success:function(xhr){
- var _document=xhr.responseXML.documentElement;
- var nowSelector=arrSelector[j];
- var parent=null;
- var children=null;
- var flower=null;
- var ArrUrl=[];
- var parentMegs=nowSelector.parent.split("___");
- switch(parentMegs[0]){
- case "id":parent=_document.getElementById(parentMegs[1]);break;
- case "class":parent=_document.getElementsByClassName(parentMegs[1])[parentMegs[2]];break;
- default: alert("parent空缺!");
- }
- var childrenMegs=nowSelector.children.split("___");
- switch(childrenMegs[0]){
- case "class":children=parent.getElementsByClassName(childrenMegs[1]);break;
- case "tag":children=parent.getElementsByTagName(childrenMegs[1]);break;
- default: alert("children空缺!");
- }
- var flowerMegs=nowSelector.flower.split("___");
- switch(flowerMegs[0]){
- case "class":getArrUrlByClass();break;
- case "tag":getArrUrlByTag();break;
- default: alert("flower空缺!");
- }
- function getArrUrlByClass(){
- for(let i=0;i<children.length;i++){
- flower=children[i].getElementsByClassName(flowerMegs[1])[flowerMegs[2]];
- var url=flower.getAttribute(flowerMegs[3]);
- if(url!=null){
- ArrUrl.push(url);
- }
- }
- }
- function getArrUrlByTag(){
- for(let i=0;i<children.length;i++){
- flower=children[i].getElementsByTagName(flowerMegs[1])[flowerMegs[2]];
- var url=flower.getAttribute(flowerMegs[3]);
- if(url!=null){
- ArrUrl.push(url);
- }
- }
- }
- if(ArrUrl.length==0){
- alert("队列为空!");
- console.log(xhr);
- console.log(_document);
- console.log(arrSelector[j]);
- console.log(ArrUrl);
- } else {
- //console.log("成功获取队列!");
- //console.log(_document);
- //console.log(arrSelector[j]);
- //console.log(ArrUrl);
- }
- watingRequest[j].shift();
- if((j+1)==intDiving){
- var strName="_";
- for(let i=0;i<=j;i++){
- strName += (watingLength[i]-watingRequest[i].length)+"_";
- }
- /**
- * 获取到图片链接
- */
- //1.直接下载
- /*
- for(var i=0;i<ArrUrl.length;i++){
- var imgName=strName+(i+1)+".jpg";
- var imgUrl=ArrUrl[i];
- //downloadPicture(imgName,imgUrl);
- console.log("下载了: "+strName+(i+1)+".jpg"+" :"+ArrUrl[i]); //后缀动态生成
- }
- */
- //2.添加到最终下载集合(推荐)
- /*
- for(var i=0;i<ArrUrl.length;i++){
- finalResult.push(ArrUrl[i]);
- }
- */
- //3.添加到页面显示 showAllPicture
- for(let i=0;i<ArrUrl.length;i++){
- var imgName=strName+(i+1)+".jpg";
- var imgUrl=ArrUrl[i];
- var elem=document.createElement('div');
- elem.className='cubeBox';
- elem.innerHTML=`<img src="${imgUrl}" title="${imgName}">`;
- showAllPicture.appendChild(elem);
- }
- if(watingRequest[j].length!=0){
- spider();
- } else {
- console.log("判断是否完成前的j和队列:");
- console.log(j);
- console.log(JSON.stringify(watingRequest));
- //判断是否完成
- function isEnd(){
- for(var i=j;i>=0;i--){
- if(watingRequest[i].length!=0){
- j=i;
- return false;
- } else {
- watingRequest.pop();
- }
- }
- return true;
- }
- var end=isEnd();
- console.log("判断是否完成后的j和队列:");
- console.log(j);
- console.log(JSON.stringify(watingRequest));
- if(end){
- console.log("程序结束,任务队列如下");
- var allImgLoaded=checkImgLoaded();
- var startCheckTime=Date.now();
- var timer=setInterval(function(){
- if(allImgLoaded){
- clearInterval(timer);
- console.log('图片加载完,改变页面形态');
- var showAllConfig=document.getElementById('showAllConfig');
- boxCont.removeChild(showAllConfig);
- while(mystyle.previousElementSibling){
- document.head.removeChild(document.head.firstChild);
- }
- var title=document.createElement('title');
- title.innerHTML='采集图片——文件夹';
- document.head.appendChild(title);
- while(popUpBox.previousElementSibling){
- document.body.removeChild(document.body.firstChild);
- }
- sCsCont.innerHTML='<span style="color:green">完成,请按组合键"Ctrl+S"选择一个位置保存采集的图片</span> '+
- `<a href="${selfUrl}" alt="返回">否则返回</a>`;
- } else {
- if(Date.now()-startCheckTime>10000){
- sCsCont.innerHTML='<span style="color:yellowgreen">图片大部分加载完...可以按组合键"Ctrl+S"选择一个位置保存采集的图片</span>';
- allImgLoaded='true';
- }
- sCsCont.innerHTML='<span style="color:red">图片还未加载完,请稍等...</span>';
- }
- },200);
- return;
- } else {
- spider();
- }
- }
- } else {
- watingRequest.push(ArrUrl);
- watingLength.push(ArrUrl.length);
- j++;
- spider();
- }
- },
- error:function(xhr){
- alert(xhr.status+":ajax请求"+this.url+"失败!");
- console.log(xhr);
- }
- })
- }
- //ajax工具函数
- function ajax(obj){
- var xhr=null;
- if(window.XMLHttpRequest){
- xhr=new window.XMLHttpRequest();
- } else {
- xhr=new ActiveXObject("Microsoft.XMLHTTP");
- }
- xhr.responseType=obj.responseType;
- xhr.onreadystatechange=function(){
- if (xhr.readyState!=4) return;
- if(xhr.status==200){
- obj.success(xhr);
- } else {
- obj.error(xhr);
- }
- }
- xhr.open(obj.type,obj.url,obj.sync);
- xhr.send();
- }
- //工具函数4 下载图片(待完善)
- function downloadPicture(imgName,imgUrl){
- //return new Promise(function(resolve,reject){
- var anchor=document.createElement("A");
- anchor.href=imgUrl;
- anchor.download=imgName;
- anchor.target="_blank";
- document.body.appendChild(anchor);
- anchor.click();
- //给单个图片下载任务分配0.5s
- // setTimeout(function(){
- // resolve();
- // },500)
- //})
- }
- //动画工具函数
- function startMove(obj,json,fn){
- clearInterval(obj.timer);
- obj.timer=setInterval(function(){
- var now='';
- var onStop=true;
- for(var attr in json){
- if(attr=='opacity'){
- now=parseInt(parseFloat(getStyle(obj,attr))*100);
- } else {
- now=parseInt(getStyle(obj,attr));
- }
- var speed=(json[attr]-now)/5;
- speed=speed>0?Math.ceil(speed):Math.floor(speed);
- if(now!=json[attr]){
- onStop=false;
- }
- if(attr=='opacity'){
- obj.style[attr]=(now+speed)/100;
- } else {
- obj.style[attr]=now+speed+'px';
- }
- }
- if(onStop){
- clearInterval(obj.timer);
- if(fn){
- fn();
- }
- }
- },50);
- }
- function getStyle(obj,attr){
- if(obj.currentStyle){
- return obj.currentStyle(attr);
- } else {
- return getComputedStyle(obj,false)[attr];
- }
- }
- var showAllPicture=document.getElementById('showAllPicture');
- var allImg=showAllPicture.getElementsByTagName('img');
- //检查所有图片是否加载完全(待优化:不一定是所有图片都加载);
- function checkImgLoaded(){
- for(let i=0;i<allImg.length;i++){
- if(allImg[i].complete==false){
- return false;
- }
- }
- return true;
- }
- })()