基于nodejs+selenium自动过滑动验证码的QQ刷赞

引子

不知道大家是否还记得之前让我刷赞的小朋友,自从他回到学校后,可能是由于学业太忙,把我们组成刷赞团队的事情忘记了,只是每天早上给我发信息帮他刷赞,迟迟没有新的用户,刷赞就没有量产的动力,我怠慢了几天没给他刷,他就不再理我了,我觉得是中了他的圈套,他只是嘴上说说要发展团队,其实只是贪恋我每天给他刷几万个赞。

效果

selnium过滑动验证码

代码

const webdriver = require('selenium-webdriver')
const firefox = require('selenium-webdriver/firefox');
const fs = require('fs')
const getPixels = require("get-pixels")
const ndarray = require("ndarray")


!async function(){
	// 新建一个 firefox 的 driver 实例
	var options = new firefox.Options()
	.setProfile('C:/Users/2bt/AppData/Roaming/Mozilla/Firefox/Profiles/m1mwcwm8.default')
	var driver = await new webdriver.Builder().forBrowser('firefox').setFirefoxOptions(options).build()


	console.log('开始模拟操作,命令提示符跳动代表着等待网页过程,默认都是10秒。如果网络较差,可能导致错误。')
	console.log('———————————————————————————————————————————————————————————————————————————————')

	main();

	async function main(){

	var distance = 0, dragX = 0 ,bgX =0 ,errX=0;

// 访问极验demo页
await driver.get('http://www.jg520.com/?fid=1&tid=2095')

 var searchBox = driver.wait(webdriver.until.elementLocated(webdriver.By.id('inputvalue')), 10000)
 searchBox.sendKeys('809101180');
await driver.sleep(500)
console.log('填写QQ号')

var btn = await driver.wait(webdriver.until.elementLocated(webdriver.By.id('submit_buy')), 10000)

await driver.sleep(5000)

await btn.click();
console.log('点击免费领取,等待验证码')


try{
await driver.wait(webdriver.until.alertIsPresent(),5000);
let alert = await driver.switchTo().alert();
let alertText = await alert.getText();
if(alertText) console.log('每天限领一次,已领取,结束进程。')
await alert.accept();
return 0;
}catch(err){}


btn = await driver.wait(webdriver.until.elementLocated(webdriver.By.css('.geetest_radar_tip')), 10000)
await btn.click();
await driver.sleep(3000)

//找到验证码背景图元素, 是一个 canvas
const bgCanvas = await driver.wait(webdriver.until.elementLocated(webdriver.By.css('.geetest_window')), 30000)


//1 截取bg图片
await driver.executeScript('document.querySelector(".geetest_canvas_bg").style.opacity = 1;document.querySelector(".geetest_canvas_slice").style.opacity = 0;')
const bgPng = await bgCanvas.takeScreenshot()
//取消隐藏
await driver.executeScript('document.querySelector(".geetest_canvas_bg").style.opacity = 1;document.querySelector(".geetest_canvas_slice").style.opacity = 1')


getPixels('data:image/png;base64,'+bgPng,function(err, pixels) {
	if(err) {
		console.log("读取背景缺口位置错误")
		return
	}
	bgX = getBoundary(pixels,getGrey(pixels)/10*3)
	//console.log('读取背景缺口边界X坐标: ',bgX);
})


	// 获取拼图滑块按钮
	const button = await driver.wait(webdriver.until.elementLocated(webdriver.By.css('.geetest_slider_button')), 30000)
	// 初始化 action
	let actions = driver.actions({async: true})

	console.log('开始计算拖动位置')


	await driver.sleep(3000)
	// 把鼠标移动到滑块上, 然后点击
	await actions.move({
		origin: button,
		duration: 1000
	}).pause(100).press().move({
		origin: button,
		x: 1,
		duration: 10
	}).pause(300).perform()


	//截取slice图片,用于计算拖动后产生的随机位移
	await driver.executeScript('document.querySelector(".geetest_canvas_bg").style.opacity = 0;document.querySelector(".geetest_canvas_slice").style.opacity = 1;')
	const slice = await bgCanvas.takeScreenshot()
	//取消隐藏
	await driver.executeScript('document.querySelector(".geetest_canvas_bg").style.opacity = 1;document.querySelector(".geetest_canvas_slice").style.opacity = 1')

	getPixels('data:image/png;base64,'+slice.toString(),function(err, pixels) {
		if(err) {
			console.log("读取初始位置错误")
			return
		}
		dragX = getBoundary(pixels,360)
	})


	await driver.sleep(500)
	distance = bgX - dragX;
	var arr = getTrack(distance*0.8+20)
	//乘以0.8是因为计算出的值是以截取的canvas为基础的,真实拖动的距离需要乘以5:4这个比值

	console.log('开始拖动滑块,需要滑动的距离: ',distance*0.8+20)

	var backArr =  [-4,-5,-6,-4,-2,-1]
	await moveTrack(arr,backArr)

	//4 再次截取slice图片,看看那里出错了
	await driver.executeScript('document.querySelector(".geetest_canvas_bg").style.opacity = 0;document.querySelector(".geetest_canvas_slice").style.opacity = 1;')
	const err = await bgCanvas.takeScreenshot()
	//取消隐藏
	await driver.executeScript('document.querySelector(".geetest_canvas_bg").style.opacity = 1;document.querySelector(".geetest_canvas_slice").style.opacity = 1')

	getPixels('data:image/png;base64,'+err,function(err, pixels) {
		if(err){
			console.log('获取最终位置错误')
			return
		}
		errX = getBoundary(pixels,360)
		console.log('完成移动到: ',errX,',错位: ',(errX - bgX)*0.8);
	})
	


	await driver.sleep(3000)

	const successTip =  driver.wait(webdriver.until.elementLocated(webdriver.By.id('layui-layer10'),10000)).getText()



	if(successTip === '领取成功,等待到账,请收藏本站网址每天领福利,好东西一定要分享给好友哦!'){
		console.log('成功~')
	}else{
		console.log('失败~重新操作')
		await driver.sleep(3000)	
		main()
	}

}


async function moveTrack(arr,backArr){
	let actions = driver.actions({bridge: true})

	for(i=0;i<arr.length;i++){
		var random = Math.floor(Math.random()*200+30)
		await actions.move({
			origin: webdriver.Origin.POINTER,
			x:arr[i],
			duration:random
		})
	}


	await actions.pause(100)

	for(i=0;i<backArr.length;i++){

		var random = Math.floor(Math.random()*200+30)
		await actions.move({
			origin: webdriver.Origin.POINTER,
			x:backArr[i],
			duration:random
		})
	}


	await actions.release().perform()
}


async function move(distance){
	await driver.sleep(1000)
	let actions = driver.actions({bridge: true})
	await actions.move({
		origin: webdriver.Origin.POINTER,
		x:distance,
		duration:1000
	}).release().perform()
	console.log("滑动距离: ",distance)
}

async function getStep(){
    //截取slice图片,用于计算拖动后产生的随机位移
    await driver.executeScript('document.querySelector(".geetest_canvas_bg").style.opacity = 0;document.querySelector(".geetest_canvas_slice").style.opacity = 1;')
    const slice = await bgCanvas.takeScreenshot()
	//取消隐藏
	await driver.executeScript('document.querySelector(".geetest_canvas_bg").style.opacity = 1;document.querySelector(".geetest_canvas_slice").style.opacity = 1')

	getPixels('data:image/png;base64,'+slice.toString(),function(err, pixels) {
		if(err) {
			console.log("读取初始位置错误")
			return
		}

		dragX = getBoundary(pixels,360)
		console.log('getStep函数返回:' ,dragX)
	})
}


//取模拟拖动滑块的数据
//用等差数列代替了匀加速运动
//因为匀加速运动取得的小数经过四舍五入会出现不精确,导致拖动的距离出差错
function getTrack(distance){
	var track = [],d=2,n=0,s=0,S=0
	while(S<distance){
		s=1+n;
		n=n+d;
		S+=s;
		track.push(s)
	}

	var diff = (S - distance);
	track.splice(-1,1,Math.round(Number(track.slice(-1))-diff))

	return track;
}

//getBoundary查找边界函数。  
//参数
//pixels是get-pixel库获取的内容
//level是灰度,用来与一个像素点rgb三个值加起来的数比较,用于确定该点的黑色程度,level越小表示越黑。
function getBoundary(pixels, level){
	var lastY=0, count=0;

	for(var i=0; i < pixels.shape[0]; i++) {
		for(var j=0; j < pixels.shape[1]; j++) {
			var rgb = pixels.get(i,j,0) + pixels.get(i,j,1) + pixels.get(i,j,2)
			if(rgb < level && lastY+1 == j) {
				count++;
        //console.log(rgb, i,j ,count);
    }
    else count = 0;
    lastY = j;
    if(count > 6) return i;
}
}

return 0;
}


//获取灰度值
function getGrey(pixels){
	var rgb = 0;
	for(var i=0; i < pixels.shape[0]; i++) {
		for(var j=0; j < pixels.shape[1]; j++) {
			rgb += pixels.get(i,j,0) + pixels.get(i,j,1) + pixels.get(i,j,2)
		}
	}

	return Math.floor(rgb/pixels.shape[0]/pixels.shape[1])
}

}()

使用方法

好像没啥特殊的,直接node就可以。

需要用npm安装get-pixelsndarray这两个包,用来识别图像的。
我用的是firefox,如果用chrocme或safari,需要自己去替换引用和下载驱动。

周末看了点node教程,讲node适用于任务调度,强项不是计算,怪不得网上的验证码代码大多都是python写的,而且遇到问题nodejs+selenium相关的答案较少,官网的文档又比较简单,废了好大的劲。

你可能感兴趣的:(自动化,Node.js)