您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
解决腾讯QQ登录验证码拖动问题
当前为
// ==UserScript== // @name 腾讯验证码自动滑动 // @namespace mscststs // @version 0.2 // @description 解决腾讯QQ登录验证码拖动问题 // @author mscststs // @match *://t.captcha.qq.com/cap_union_new_show* // @icon https://www.google.com/s2/favicons?domain=qq.com // @grant none // ==/UserScript== (function() { 'use strict'; // 工具库 var mscststs= new class{ sleep(miliseconds){ return new Promise(resolve=>{ setTimeout(()=>{resolve();},miliseconds); }); } async _Step(selector,callback,need_content,timeout){ while(timeout--){ if(document.querySelector(selector)===null){ await this.sleep(100); continue; }else{ if(need_content){ if(document.querySelector(selector).innerText.length==0){ await this.sleep(100); continue; } } } break; } callback(selector); } wait(selector,need_content = false,timeout=Infinity){ return new Promise(resolve=>{ this._Step(selector,function(selector){resolve(document.querySelector(selector));},need_content,timeout); }); } }(); async function eventHijacker(cb){ let hijackEventList = ["mousedown","mousemove","mouseup","click","dblclick","pointerup","pointerdown","pointermove"]; function handler(e){ if(!e.fake){ // 拦截真事件,防止触发 e.stopPropagation(); e.preventDefault(); return false } } hijackEventList.forEach(eventKey=>{ window.addEventListener(eventKey,handler,true) }) await cb() hijackEventList.forEach(eventKey=>{ window.removeEventListener(eventKey,handler,true) }) }; (async function load(){ // 初始化 ,监听canvas await mscststs.sleep(500) // console.log("重放!") await mscststs.wait("#slideBg") await mscststs.wait("#tcaptcha_drag_thumb") // await mscststs.sleep(500) // 重放开始 eventHijacker(async ()=>{ await replay(getTargetRecorder(fetchCanvas()-30,1000),"#tcaptcha_drag_thumb") setTimeout(()=>{ if(document.querySelector("#guideText").innerText.indexOf("对齐缺口")>0){ // 出现未对齐,重试一次 let event = new Event("click",{"bubbles":true, "cancelable":false}); event.fake = true; document.querySelector(".tcaptcha-embed-refresh").dispatchEvent(event); load() } },500) }) })(); // 亲自录制的老奶奶轨迹,成功率 100% const recoder = [{"type":"pointerdown","clientX":256,"clientY":709,"ts":2176},{"type":"pointermove","clientX":256,"clientY":709,"ts":2190},{"type":"pointermove","clientX":256,"clientY":707,"ts":2239},{"type":"pointermove","clientX":257,"clientY":707,"ts":2247},{"type":"pointermove","clientX":258,"clientY":707,"ts":2254},{"type":"pointermove","clientX":259,"clientY":707,"ts":2263},{"type":"pointermove","clientX":259,"clientY":708,"ts":2279},{"type":"pointermove","clientX":260,"clientY":708,"ts":2287},{"type":"pointermove","clientX":261,"clientY":708,"ts":2296},{"type":"pointermove","clientX":263,"clientY":708,"ts":2303},{"type":"pointermove","clientX":265,"clientY":708,"ts":2312},{"type":"pointermove","clientX":268,"clientY":708,"ts":2319},{"type":"pointermove","clientX":271,"clientY":709,"ts":2328},{"type":"pointermove","clientX":277,"clientY":709,"ts":2335},{"type":"pointermove","clientX":280,"clientY":710,"ts":2346},{"type":"pointermove","clientX":284,"clientY":710,"ts":2351},{"type":"pointermove","clientX":289,"clientY":711,"ts":2362},{"type":"pointermove","clientX":294,"clientY":711,"ts":2367},{"type":"pointermove","clientX":299,"clientY":713,"ts":2379},{"type":"pointermove","clientX":303,"clientY":713,"ts":2386},{"type":"pointermove","clientX":306,"clientY":713,"ts":2396},{"type":"pointermove","clientX":309,"clientY":713,"ts":2399},{"type":"pointermove","clientX":311,"clientY":713,"ts":2407},{"type":"pointermove","clientX":315,"clientY":713,"ts":2415},{"type":"pointermove","clientX":318,"clientY":713,"ts":2422},{"type":"pointermove","clientX":322,"clientY":713,"ts":2431},{"type":"pointermove","clientX":326,"clientY":713,"ts":2439},{"type":"pointermove","clientX":330,"clientY":713,"ts":2447},{"type":"pointermove","clientX":333,"clientY":713,"ts":2455},{"type":"pointermove","clientX":336,"clientY":713,"ts":2463},{"type":"pointermove","clientX":338,"clientY":714,"ts":2471},{"type":"pointermove","clientX":339,"clientY":714,"ts":2481},{"type":"pointermove","clientX":338,"clientY":714,"ts":2719},{"type":"pointermove","clientX":337,"clientY":716,"ts":2732},{"type":"pointermove","clientX":336,"clientY":716,"ts":2735},{"type":"pointermove","clientX":334,"clientY":716,"ts":2746},{"type":"pointermove","clientX":333,"clientY":716,"ts":2751},{"type":"pointermove","clientX":332,"clientY":716,"ts":2762},{"type":"pointermove","clientX":330,"clientY":716,"ts":2767},{"type":"pointermove","clientX":329,"clientY":716,"ts":2779},{"type":"pointermove","clientX":328,"clientY":716,"ts":2783},{"type":"pointermove","clientX":327,"clientY":716,"ts":2799},{"type":"pointermove","clientX":328,"clientY":716,"ts":3063},{"type":"pointermove","clientX":329,"clientY":716,"ts":3087},{"type":"pointermove","clientX":330,"clientY":716,"ts":3103},{"type":"pointermove","clientX":331,"clientY":716,"ts":3127},{"type":"pointermove","clientX":332,"clientY":716,"ts":3146},{"type":"pointermove","clientX":331,"clientY":716,"ts":3583},{"type":"pointermove","clientX":330,"clientY":716,"ts":3639},{"type":"pointermove","clientX":329,"clientY":716,"ts":3655},{"type":"pointerup","clientX":329,"clientY":716,"ts":4407},{"type":"click","clientX":329,"clientY":716,"ts":4420},{"type":"pointermove","clientX":329,"clientY":716,"ts":4422},{"type":"mousemove","clientX":329,"clientY":716,"ts":4422}] /** * ImageData 转色值矩阵 */ function imageDataToBrightnessArray(imageData,width,height){ let brightnessArray = [] let pixel_color = imageData let pointer = 0 for(let i=0;i< height;i++) { brightnessArray[i] = []; //将每一个子元素又定义为数组 for( let n=0;n< width;n++) { brightnessArray[i][n]= parseInt((pixel_color[pointer] + pixel_color[pointer+1] + pixel_color[pointer+2]) / 3) ; //此时pix[i][n]可以看作是一个二级数组 pointer = pointer+4; } } return brightnessArray } function zipArray_row(b_array){ let result = [] let height = b_array.length; let width = b_array[0].length; for(let i = 0;i<width;i++){ let val = 0; for(let j= 0;j<height ; j++){ val += b_array[j][i] } result[i] = parseInt(val/height) } return result } function drawVline(ctx,left){ ctx.fillStyle = "#FF0000"; ctx.fillRect(left, 0, 1, ctx.height) } function createCanvas(element){ const {width,height} = element.getBoundingClientRect(); let canvas = document.createElement("Canvas") canvas.width=width canvas.height=height document.body.appendChild(canvas) let ctx = canvas.getContext("2d") ctx.drawImage(element,0,0,width,height) return canvas } function getctx(selector){ let bgCanvas = document.querySelector(selector); console.dir(bgCanvas) if(bgCanvas.tagName != 'CANVAS'){ bgCanvas = createCanvas(bgCanvas) } let {width, height} = bgCanvas; // 宽度,高度 let ctx = bgCanvas.getContext("2d"); ctx.height = height; ctx.width = width; return ctx } function getImageData(selector){ let ctx = getctx(selector) return ctx.getImageData(0,0,ctx.width,ctx.height).data } window.fetchCanvas = function(brightStep=10){ //let fullBgData = getImageData("#slideBg") // 完整背景图 let bgctx = getctx("#slideBg") let bgData = bgctx.getImageData(0,0,bgctx.width,bgctx.height).data // 残缺背景图 window.brightnessArray = imageDataToBrightnessArray(bgData,bgctx.width,bgctx.height) window.brightnessArray_row = zipArray_row(window.brightnessArray) console.log(window.brightnessArray_row) let leftOffset = 0; window.brightnessChange_row = window.brightnessArray_row.map((item,index)=>{ let next = window.brightnessArray_row[index+1] || item return { index:index, value:Math.abs(next-item) } }) window.brightnessChange_row = window.brightnessChange_row.filter(item=>{ if(item.index < bgctx.width*0.6){ return false } return true }) window.brightnessChange_row.sort((a,b)=>{ return b.value-a.value }) drawVline(bgctx ,window.brightnessChange_row[0].index) drawVline(bgctx ,window.brightnessChange_row[1].index) drawVline(bgctx ,window.brightnessChange_row[2].index) leftOffset = Math.min(window.brightnessChange_row[0].index, window.brightnessChange_row[1].index,window.brightnessChange_row[2].index) // console.log(window.brightnessChange_row) //throw new Error("暂停") // 拿到 leftOffset ,就是对应的缺口的偏移量 console.log(leftOffset) return leftOffset } // 录制鼠标事件 window.record = async function(){ return await new Promise((resolve,reject)=>{ let ms = new Date().valueOf(); const getTime = ()=>{ // 时间打点 return new Date().valueOf() - ms; } let eventList = []; function eventRecorder(e){ let { type, clientX, clientY, target } = e; let eventMsg = { type, clientX, clientY, ts:getTime()} eventList.push(eventMsg) } // 开始录制 window.addEventListener("keyup",(e)=>{ ["mousedown","mousemove","mouseup","click","dblclick","pointerup","pointerdown","pointermove"].forEach(eventKey=>{ window.addEventListener(eventKey,eventRecorder,true) }) // 停止录制 window.addEventListener("keyup",(e)=>{ ["mousedown","mousemove","mouseup","click","dblclick","pointerup","pointerdown","pointermove"].forEach(eventKey=>{ window.removeEventListener(eventKey,eventRecorder,true) }) resolve(eventList) },{once:true}) },{once:true}) }) } // 轨迹压缩和重整 window.getTargetRecorder = function getTargetRecorder(targetlength=100, targetduration=1000, recorder=recoder, ){ console.log(`重放,长度 ${targetlength}, 时间 ${targetduration}`) // step 1. 首先以第一个事件的位置为起始,压缩整个轨迹 let base = recorder[0]; let ziped_recorder = recorder.map(event=>{ return { type:event.type, offsetX:event.clientX - base.clientX, offsetY:event.clientY - base.clientY, ts:event.ts - base.ts } }) // 压缩后的事件记录 // console.log("ziped", ziped_recorder) let max = ziped_recorder[ziped_recorder.length -1] // 拿到最后一个 ziped_recorder.reduce((p,e,i)=>{ e.offsetX = parseInt(e.offsetX * targetlength / max.offsetX) // 轨迹缩放 e.ts = parseInt(e.ts * targetduration / max.ts ) // 时间戳缩放 return e }) return ziped_recorder } // 轨迹事件重放 window.replay = function(recorder, dom){ if(typeof dom === "string"){ dom = document.querySelector(dom) } let {left, top} = dom.getBoundingClientRect(); left = left + 20* Math.random() top = top + 20* Math.random() return Promise.all( recorder.map(e=>{ return new Promise(resolve=>{ setTimeout(()=>{ let type = ""; // 由于以前极验用的是pointer,现在要用mouse if(e.type === "pointerdown") type = "mousedown"; if(e.type === "pointermove") type = "mousemove"; if(e.type === "pointerup") type = "mouseup"; let event = new Event(type,{"bubbles":true, "cancelable":false}); event.offsetX = e.offsetX; event.offsetY = e.offsetY; event.screenX = event.pageX = event.clientX = e.offsetX + left; event.screenY = event.pageY = event.clientY = e.offsetY + top; event.fake = true; dom.dispatchEvent(event); resolve() //console.log("....",e.type,event) },e.ts) }) }) ) } })();