不知道大家是否还记得之前让我刷赞的小朋友,自从他回到学校后,可能是由于学业太忙,把我们组成刷赞团队的事情忘记了,只是每天早上给我发信息帮他刷赞,迟迟没有新的用户,刷赞就没有量产的动力,我怠慢了几天没给他刷,他就不再理我了,我觉得是中了他的圈套,他只是嘴上说说要发展团队,其实只是贪恋我每天给他刷几万个赞。
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-pixels
,ndarray
这两个包,用来识别图像的。
我用的是firefox,如果用chrocme或safari,需要自己去替换引用和下载驱动。
周末看了点node教程,讲node适用于任务调度,强项不是计算,怪不得网上的验证码代码大多都是python写的,而且遇到问题nodejs+selenium相关的答案较少,官网的文档又比较简单,废了好大的劲。