样板代码
# 多个元素
// 分页码:a标签 List<WebElement> elementPageNums = EmptyHelper.emptyArrayList(); try { elementPageNums = new WebDriverWait(driver, Duration.ofMillis(Timeout.T_10_sec)) .until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.cssSelector(".s-pagination-container .s-pagination-strip a"))); } catch (Exception e) { errMsg = "没有查询到【分页条1】"; log.error(errMsg, new Throwable()); }
# 单个元素
// 暂停几秒 ThreadUtil.sleep(Timeout.T_3_sec); // 输入 登录名 try { WebElement elementUserName = new WebDriverWait(driver, Duration.ofMillis(Timeout.T_10_sec)) .until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#ap_email"))); if (ObjectUtil.isNotNull(elementUserName)) { elementUserName.clear(); elementUserName.sendKeys(account.getUsername()); } } catch (Exception e) { errMsg = "未找到【登录名】输入框"; log.error(errMsg, e); return res.setMsg(errMsg); } // 暂停几秒 ThreadUtil.sleep(Timeout.T_3_sec); // 点击 登录.下一步按钮 try { WebElement elementLoginNext = new WebDriverWait(driver, Duration.ofMillis(Timeout.T_10_sec)) .until(ExpectedConditions.elementToBeClickable(By.cssSelector("#continue"))); if (ObjectUtil.isNotNull(elementLoginNext)) { elementLoginNext.click(); } } catch (Exception e) { errMsg = "未找到【登录.下一步】按钮"; log.error(errMsg, e); return res.setMsg(errMsg); }
SeleniumHelper.java
package com.wanma.framework_noweb.helper; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.resource.ResourceUtil; import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.wanma.framework_noweb.config.Timeout; import com.wanma.framework_noweb.constant.PageName; import org.openqa.selenium.WindowType; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import java.nio.charset.Charset; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; /** * Selenium 组手类 * * @author Albert * @date 2022/8/25 */ public class SeleniumHelper { private static ChromeDriver driver; private static final Map<String, String> pageHandleMap = new LinkedHashMap<>(); // 预设置6个页面 private static final String[] pageNameArr = { PageName.page1, PageName.page2, PageName.page3, PageName.page4, PageName.page5, PageName.page6 }; /** * 实例化 ChromeDriver 单例对象 */ public static ChromeDriver getSingleDriver() { if (ObjectUtil.isNull(driver)) { // Chrome选项 ChromeOptions options = new ChromeOptions(); // 浏览器窗口 最大化 // options.addArguments("--start-maximized"); // 忽略掉证书错误 // /36.html // options.setExperimentalOption("excludeSwitches", "ignore-certificate-errors"); // options.setExperimentalOption("excludeSwitches", "enable-automation"); // 禁止显示:Chrome 正在受到自动软件的控制 options.setExperimentalOption("excludeSwitches", CollectionUtil.toList("enable-automation", "ignore-certificate-errors")); // 禁止显示:请停用以开发者… options.setExperimentalOption("useAutomationExtension", false); options.setExperimentalOption("w3c", false); // 禁止显示:“保存密码”弹框 Map<String, Object> prefsMap = new HashMap<>(); prefsMap.put("credentials_enable_service", false); prefsMap.put("profile.password_manager_enabled", false); options.setExperimentalOption("prefs", prefsMap); options.addArguments("lang=zh-CN,zh,zh-TW,en-US,en"); options.addArguments("user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"); // options.addArguments("disable-infobars"); // options.addArguments("--no-sandbox"); options.addArguments("disable-blink-features=AutomationControlled"); // 就是这一行告诉chrome去掉了webdriver痕迹 options.addArguments("--ignore-certificate-errors"); // 忽略掉证书错误 options.addArguments("--disable-extensions"); // 屏蔽 youtube、google等网站的资源 options.addArguments("--host-resolver-rules=MAP www.youtube.com 127.0.0.1" + ",MAP www.google.com 127.0.0.1" + ",MAP cmacgm.matomo.cloud 127.0.0.1" + ",MAP ec.walkme.com 127.0.0.1" + ",MAP www.googletagmanager.com 127.0.0.1" + ",MAP www.freeprivacypolicy.com 127.0.0.1" + ",MAP www.googletagmanager.com 127.0.0.1" + ",MAP s.go-mpulse.net 127.0.0.1" + // ",MAP cdnjs.cloudflare.com 127.0.0.1" + ",MAP geolocation.onetrust.com 127.0.0.1" ); ChromeDriver _driver = new ChromeDriver(options); // 突破【反爬虫】,抹去 Chrome浏览器 的 Selenium 属性 Map<String, Object> parameters = new HashMap<>(); byte[] jsData = ResourceUtil.readBytes("stealth.min.js"); String stealth = StrUtil.str(jsData, Charset.defaultCharset()); parameters.put("source", stealth); _driver.executeCdpCommand("Page.addScriptToEvaluateOnNewDocument", parameters); // 浏览器窗口 最大化 _driver.manage().window().maximize(); driver = _driver; } return driver; } /** * 切换页面 */ public static void switchPage(String pageName) { // 限制取值访问 if (!ArrayUtil.contains(pageNameArr, pageName)) { throw new RuntimeException("参数pageName值错误"); } // 特殊处理第1个页面 if (ObjectUtil.isEmpty(pageHandleMap)) { pageHandleMap.put(PageName.page1, getSingleDriver().getWindowHandle()); } boolean newHandle = true; String pageHandle = pageHandleMap.getOrDefault(pageName, ""); if (StrUtil.isNotEmpty(pageHandle) && CollectionUtil.contains(getSingleDriver().getWindowHandles(), pageHandle)) { newHandle = false; } if (newHandle) { pageHandle = getSingleDriver().switchTo().newWindow(WindowType.TAB).getWindowHandle(); pageHandleMap.put(pageName, pageHandle); } else { getSingleDriver().switchTo().window(pageHandle); } } /** * 加载页面(失败重试3次) */ public static void navigate(String pageName, String url) { int tryMax = 3; int tryTimes = 1; boolean ret = _navigate(pageName, url); while (!ret && (tryTimes < tryMax)) { ret = _navigate(pageName, url); tryTimes++; ThreadUtil.sleep(Timeout.T_2_sec); } } private static boolean _navigate(String pageName, String url) { boolean ret = true; try { switchPage(pageName); getSingleDriver().get(url); } catch (Exception e) { ret = false; System.out.println("【加载页面出错】" + FileUtil.getLineSeparator() + url); e.printStackTrace(); } return ret; } /** * 加载页面(默认窗口) */ public static void navigate(String url) { navigate(PageName.page1, url); } /** * 获取当前页面URL */ public static String getCurrentUrl() { return StrUtil.removeSuffix(getSingleDriver().getCurrentUrl(), "/"); } }
UrlHelper.java
package com.wanma.framework_noweb.helper; import cn.hutool.core.net.url.UrlBuilder; import cn.hutool.core.util.StrUtil; /** * Url助手类 */ public class UrlHelper { /** * 获取参数值 */ public static String getParam(String url, String name) { if (StrUtil.isEmpty(url) || StrUtil.isEmpty(name)) { return ""; } return StringHelper.toString(UrlBuilder.of(url).getQuery().get(name)); } /** * 格式化URL */ public static String formatUrl(String url, String siteUrl) { if (StrUtil.isEmpty(url)) { return ""; } if (!StrUtil.contains(url, "http")) { url = siteUrl + url; } return addLanguage(url); } /** * 添加 语言参数 */ public static String addLanguage(String url) { if (!StrUtil.contains(url, "?")) { return url + "?language=en_US"; } return url + "&language=en_US"; } }