自动滑块验证登录QQ-java实现
之前,我用php配合java写了一个qq群签到的脚本。需要手动更新cookie,很烦。
最近学习刷题过程中,碰到了很多事情,很烦。就准备写几天代码,把之前的脚本,完整的只用java来实现,顺便平复一下最近烦躁的情绪。
登录QQ之后,能干的事情很多。这里只讲述如何自动登录,至于自动登录之后干啥,根据自己需求自由发挥。
授人以鱼不如授人以渔,我把思路分享出来。
一、登录
下载selenium相应的jar包。加载ChromeDriver驱动,下载地址
加载驱动之后,就可以考虑开始登录了。
- 切换账号密码登录
- 输入账号
- 输入密码
- 登录
注意,这期间是需要有时间间隔的,因为可能会有网速的影响,所以我在切换账号密码登录和登录这两步中,分别设定了间隔1秒和5秒。
如果页面还没加载完成,就开始执行程序,那会报错。因为没有找到指定的元素。
二、自动解锁滑块验证码
也可以到这里进行滑块测试,代码需要进行修改
本来是想通过识别图像像素或者对比度的方法,来找出滑块缺失的位置。后来发现,腾讯并没有做得那么牛逼。
经过多次测试,发现,QQ的滑块验证,并不是随机产生的,而是固定的。不管怎么弄,都会有三个固定位置。190px,205px,215px.
换句话说,我们顶多进行三次登录,肯定是能登录成功的。
放上完整代码
public class AutoLogin {
private static ChromeDriver driver;
private static String oldUrl;
private static String newUrl;
/**
* 获取驱动
*/
public static void getDriver() {
// 本地测试
// System.setProperty("webdriver.chrome.driver", "C:\\Users\\kitchen\\Desktop\\chromedriver.exe");
// 打包
System.setProperty("webdriver.chrome.driver", "chromedriver.exe");
// 下面两行代码关闭无用的log
System.setProperty("webdriver.chrome.silentOutput", "true");
java.util.logging.Logger.getLogger("org.openqa.selenium").setLevel(Level.OFF);
ChromeOptions chromeOptions = new ChromeOptions();
// 这是指不打开GUI模式
chromeOptions.addArguments("--headless");
driver = new ChromeDriver(chromeOptions);
}
/**
* 获取登录的skey
* @param u
* @param p
* @return
*/
public static String getSkey(String u, String p) {
String skey = null;
if (login(u, p)) {
skey = driver.manage().getCookieNamed("skey").toString().split(";")[0].substring(5);
} else {
System.out.println("本次自动登录失败,邮件通知管理员");
String[] mail = { "QQ自动登录异常", "本次登录失败,请检测程序" };
SendMail.send(mail);
System.exit(0);
}
driver.quit();
return skey;
}
/**
* 登录
*
* @param u
* @param p
* @return true表示登录成功
*/
public static boolean login(String u, String p) {
System.out.println("时间到,开始登录...");
getDriver();
boolean flag = false;
driver.get(
"https://xui.ptlogin2.qq.com/cgi-bin/xlogin?proxy_url=https%3A//qzs.qq.com/qzone/v6/portal/proxy.html&daid=5&&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&appid=549000912&style=22&target=self&s_url=https%3A%2F%2Fqzs.qzone.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone%26specifyurl%3Dhttp%253A%252F%252Fuser.qzone.qq.com%252F5201314&pt_qr_app=%E6%89%8B%E6%9C%BAQQ%E7%A9%BA%E9%97%B4&pt_qr_link=http%3A//z.qzone.com/download.html&self_regurl=https%3A//qzs.qq.com/qzone/v6/reg/index.html&pt_qr_help_link=http%3A//z.qzone.com/download.html&pt_no_auth=1");
try {
Thread.sleep(1000);
// 切换登录模式
driver.findElement(By.id("switcher_plogin")).click();
Thread.sleep(500);
// 输入账号以及密码进行登录
driver.findElement(By.id("u")).clear();
driver.findElement(By.id("u")).sendKeys(u);
driver.findElement(By.id("p")).clear();
driver.findElement(By.id("p")).sendKeys(p);
driver.findElement(By.id("login_button")).click();
Thread.sleep(5000);
//轨迹
int[][] arr = { { 10, 20, 30, 40, 50, 18 }, { 10, 20, 30, 40, 50, 18, 30 }, { 10, 20, 30, 40, 50, 18, 15 },
};
oldUrl = driver.getCurrentUrl();
for (int i = 0; i < arr.length; i++) {
System.out.print("正在尝试第" + (i + 1) + "次登录:");
if (unlock(arr[i])) {
System.out.println("登录成功");
flag = true;
break;
} else {
System.out.println("登录失败");
flag = false;
}
Thread.sleep(2000);
}
} catch (InterruptedException e) {
System.out.println("登录失败");
driver.quit();
}
return flag;
}
/**
* 自动进行滑块解锁
*
* @return true表示解锁成功
*/
public static boolean unlock(int[] arr) {
boolean flag = false;
Actions actions = new Actions(driver);
try {
//qq里面嵌套了iframe,需要将驱动转到iframe内部,才可以选择元素。
//如果第一次登录错误,需要将驱动再跳回到当前内容
driver.switchTo().frame("tcaptcha_iframe");
WebElement slideBtn = driver.findElement(By.id("tcaptcha_drag_button"));
// 按下滑动按钮
actions.clickAndHold(slideBtn).perform();
for (int i : arr) {
actions.moveByOffset(i, 0).perform();
}
// 松开按钮
actions.release(slideBtn).perform();
Thread.sleep(3000);
newUrl = driver.getCurrentUrl();
if (oldUrl.equals(newUrl)) {
//如果登录失败,需要让驱动重新跳回到原来的内容
driver.switchTo().defaultContent();
flag = false;
} else {
flag = true;
}
Thread.sleep(500);
} catch (InterruptedException e) {
System.out.println("登录失败");
driver.quit();
}
return flag;
}
}