我们平常在使用selenium爬虫的时候,通常会遇到登录这个操作,然鹅登录的时候,如果对方服务器反应时间太久,或者太快,时间不稳定,那么此时进行登录验证,密码是否正确,信息是否填对的时候,就会非常麻烦。
在我查阅大量资料过后,仍然找不到满意的元素等待方法,所以索性自己实现一个,在这里分享给大家。
函数说明
函数 | 说明 |
---|---|
waitElement() | 等待指定元素。传入WebDriver 对象,和selenium的By对象。如果对象存在,执行回调,或者抛出异常 |
waitUrl() | 等待指定网页。传入WebDriver 对象,和网页url。如果对象存在,执行回调,或者抛出异常 |
waitElementText() | 等待指定元素的文本。传入WebDriver 对象,和selenium的By对象,还有要判断的文文本。如果文本存在,执行回调,或者抛出异常 |
源码
主类
/**
* @Author: KL-Skeleton
* @Description: ${Description}
* @Date: Created in 19:22 2020/8/27
*/
public class ElementTimeOutUtils {
//线程的超时时间默认为一分钟
private static long runnable_timeout = 60*1000;
/**
*线程池
*/
private static ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//抛出错误的语句
private static String exceptionStr(WebDriver driver,Object by){
return "the " + driver + " time out waiting for the element(" + by+")";
}
//元素等待
public static void waitElement(WebDriver driver, By by, long time) throws ElementTimeOutException {
long beginTime = System.currentTimeMillis();
//如果当前时间减去开始的时间,小于time,并且传入的等待条件不符合,那么将一直堵塞此进程,直到超时,或者条件符合即可。
while ((System.currentTimeMillis()-beginTime<time)&&(driver.findElements(by).size()==0)){
}
if(System.currentTimeMillis()-beginTime>=time){
throw new ElementTimeOutException(exceptionStr(driver,by));
}
}
public static void waitElement(WebDriver driver, By by,MyRunnable runnable){
cachedThreadPool.execute(()->{
long beginTime = System.currentTimeMillis();
//如果当前时间减去开始的时间,小于time,并且传入的等待条件不符合,那么将一直堵塞此进程,直到超时,或者条件符合即可。
while ((System.currentTimeMillis()-beginTime<runnable_timeout)&&(driver.findElements(by).size()==0)){
}
if(System.currentTimeMillis()-beginTime<runnable_timeout){
runnable.run();
}else {
runnable.timeout();
}
});
}
//网页等待
public static void waitUrl(WebDriver driver,String url,long time) throws ElementTimeOutException{
long beginTime = System.currentTimeMillis();
//如果当前时间减去开始的时间,小于time,并且传入的等待条件不符合,那么将一直堵塞此进程,直到超时,或者条件符合即可。
while ((System.currentTimeMillis()-beginTime<time)&&(!driver.getCurrentUrl().contains(url))){
}
if(System.currentTimeMillis()-beginTime>=time){
throw new ElementTimeOutException(exceptionStr(driver,url));
}
}
public static void waitUrl(WebDriver driver, String url, MyRunnable runnable){
cachedThreadPool.execute(()->{
long beginTime = System.currentTimeMillis();
//如果当前时间减去开始的时间,小于time,并且传入的等待条件不符合,那么将一直堵塞此进程,直到超时,或者条件符合即可。
while ((System.currentTimeMillis()-beginTime<runnable_timeout)&&(!driver.getCurrentUrl().contains(url))){
}
if(System.currentTimeMillis()-beginTime<runnable_timeout) {
runnable.run();
}else {
runnable.timeout();
}
});
}
//文本等待
public static void waitElementText(WebDriver driver, By by, String text, long time) throws ElementTimeOutException{
long beginTime = System.currentTimeMillis();
//如果当前时间减去开始的时间,大于time,并且传入的布尔值为false。则抛出异常。
while ((System.currentTimeMillis()-beginTime<time)&&(!driver.findElements(by).get(0).getText().contains(text))){
}
if(System.currentTimeMillis()-beginTime>=time){
throw new ElementTimeOutException(exceptionStr(driver,by+" and text:"+text));
}
}
public static void waitElementText(WebDriver driver, By by,String text,MyRunnable runnable){
cachedThreadPool.execute(()->{
long beginTime = System.currentTimeMillis();
//如果当前时间减去开始的时间,小于time,并且传入的等待条件不符合,那么将一直堵塞此进程,直到超时,或者条件符合即可。
while ((System.currentTimeMillis()-beginTime<runnable_timeout)&&(!driver.findElements(by).get(0).getText().contains(text))){
}
if(System.currentTimeMillis()-beginTime<runnable_timeout){
runnable.run();
} else {
runnable.timeout();
}
});
}
//geter and seter
public static long getRunnable_timeout() {
return runnable_timeout;
}
public static void setRunnable_timeout(long runnable_timeout) {
ElementTimeOutUtils.runnable_timeout = runnable_timeout;
}
public abstract static class MyRunnable{
public void run(){
}
public void timeout(){
}
}
}
异常类
public class ElementTimeOutException extends Exception{
public ElementTimeOutException() {
super();
}
public ElementTimeOutException(String message) {
super(message);
}
}
使用示例
百度模拟搜索,搜索框输入“a”,然后点击搜索,直到底部元素“content_bottom”加载完成,即可实现回调,如果因为网络原因搜索缓慢超过1分钟,或者元素“content_bottom”始终找不到,则执行timeout回调。
public static void main(String[] args) {
System.setProperty("webdriver.chrome.driver","C:\\Users\\ASUS\\Desktop\\chromedriver7.9.exe");
WebDriver driver = new ChromeDriver();
driver.get("https://www.baidu.com/");
driver.findElement(By.id("kw")).sendKeys("a");
driver.findElement(By.id("su")).click();
//方法一:开启元素等待线程,最大等待时间默认为1分钟,这里可以设置为10秒,
//优点:不会阻塞进程
ElementTimeOutUtils.setRunnable_timeout(10*1000);
ElementTimeOutUtils.waitElement(driver, By.id("content_bottom"), new ElementTimeOutUtils.MyRunnable() {
@Override
public void run() {
System.out.println("百度搜索加载成功");
}
@Override
public void timeout() {
super.timeout();
System.out.println("百度搜索加载失败");
}
});
//方法二:不开启线程,指定超时时间5秒,如果超时,则抛出异常
//缺点:会阻塞进程
try {
ElementTimeOutUtils.waitElement(driver, By.id("content_bottoms"),5000);
System.out.println("百度搜索加载成功");
} catch (ElementTimeOutException e) {
System.out.println("百度搜索加载失败");
e.printStackTrace();
}
}
运行结果:
- 同理也可以用来判断登录的时候,账号密码是否错误,等等
TimeOutUtil.waitElementText(driver, By.id("show_error"),"验证码错误", new TimeOutUtil.MyRunnable() {
@Override
public void run() {
System.out.println("验证码错误");
}
});