From f1d3036c7a6dd7c2b7797aa4e1a0478c3e2315f6 Mon Sep 17 00:00:00 2001 From: Niko <1377382065@qq.com> Date: Tue, 5 May 2026 10:12:32 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E6=B5=8B=E8=AF=95=E7=B1=BB=E5=B9=B6=E6=9A=B4?= =?UTF-8?q?=E9=9C=B2=E6=B5=8B=E8=AF=95=E6=89=80=E9=9C=80=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 AutoLoginTest 集成测试类 - 暴露以下方法供测试使用: - public static void downloadCaptcha(Page) - public static void closeNotificationDialog(Page) - public static boolean doLoginWithCaptcha(Page) - public static void sleep(long) - public static final String FRAME_URL / LOGIN_URL 验证码识别已通过测试:9347 --- src/main/java/com/ets/scraper/EtsScraper.java | 12 +- .../java/com/ets/scraper/AutoLoginTest.java | 163 ++++++++++++++++++ 2 files changed, 169 insertions(+), 6 deletions(-) create mode 100644 src/test/java/com/ets/scraper/AutoLoginTest.java diff --git a/src/main/java/com/ets/scraper/EtsScraper.java b/src/main/java/com/ets/scraper/EtsScraper.java index babbb80..0110870 100644 --- a/src/main/java/com/ets/scraper/EtsScraper.java +++ b/src/main/java/com/ets/scraper/EtsScraper.java @@ -29,8 +29,8 @@ import static java.nio.file.Files.createDirectories; * Uses Playwright to automate login and data extraction. */ public class EtsScraper { - private static final String FRAME_URL = "https://101.227.180.215/SHCityEnvCW/CWS/frame.html"; - private static final String LOGIN_URL = "https://101.227.180.215/SHCityEnvCW/CWS/userlogin.html"; + public static final String FRAME_URL = "https://101.227.180.215/SHCityEnvCW/CWS/frame.html"; + public static final String LOGIN_URL = "https://101.227.180.215/SHCityEnvCW/CWS/userlogin.html"; private static final String USERNAME = "sccw"; private static final String PASSWORD = "slife@123"; private static final Path SCREENSHOT_DIR = Path.of("screenshots"); @@ -162,7 +162,7 @@ public class EtsScraper { } } - private static boolean doLoginWithCaptcha(Page page) throws Exception { + public static boolean doLoginWithCaptcha(Page page) throws Exception { // Find and fill username String usernameInput = findInput(page, new String[]{ "input[placeholder*='用户名']", @@ -240,7 +240,7 @@ public class EtsScraper { } } - private static void downloadCaptcha(Page page) { + public static void downloadCaptcha(Page page) { try { // Set up listener FIRST, then reload to trigger the request Response resp = page.waitForResponse( @@ -263,7 +263,7 @@ public class EtsScraper { } } - private static void closeNotificationDialog(Page page) { + public static void closeNotificationDialog(Page page) { // Find the frame that contains the notification dialog Frame dialogFrame = null; for (Frame f : page.frames()) { @@ -341,7 +341,7 @@ public class EtsScraper { } } - private static void sleep(long ms) { + public static void sleep(long ms) { try { Thread.sleep(ms); } catch (InterruptedException e) { diff --git a/src/test/java/com/ets/scraper/AutoLoginTest.java b/src/test/java/com/ets/scraper/AutoLoginTest.java new file mode 100644 index 0000000..66ca98e --- /dev/null +++ b/src/test/java/com/ets/scraper/AutoLoginTest.java @@ -0,0 +1,163 @@ +package com.ets.scraper; + +import com.microsoft.playwright.*; +import com.microsoft.playwright.options.WaitUntilState; +import org.junit.jupiter.api.*; + +import java.io.IOException; +import java.nio.file.Path; + +/** + * 自动登录集成测试 + * 测试完整的登录流程:关闭弹窗 -> 下载验证码 -> 识别 -> 登录 + */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class AutoLoginTest { + + private Playwright playwright; + private Browser browser; + private BrowserContext context; + + @BeforeAll + void setUp() throws IOException { + java.nio.file.Files.createDirectories(Path.of("screenshots")); + playwright = Playwright.create(); + browser = playwright.chromium().launch( + new BrowserType.LaunchOptions().setHeadless(false) + ); + context = browser.newContext( + new Browser.NewContextOptions().setIgnoreHTTPSErrors(true) + ); + } + + @AfterAll + void tearDown() { + if (context != null) context.close(); + if (browser != null) browser.close(); + if (playwright != null) playwright.close(); + } + + @Test + @Disabled("需要手动操作 - 仅在实际登录场景下运行") + void testAutoLogin() throws Exception { + Page page = context.newPage(); + + try { + System.out.println("=== 开始自动登录测试 ==="); + + // 步骤 1: 建立会话 + System.out.println("[1/6] 建立会话..."); + page.navigate(EtsScraper.FRAME_URL, new Page.NavigateOptions() + .setTimeout(30000) + .setWaitUntil(WaitUntilState.DOMCONTENTLOADED)); + EtsScraper.sleep(3000); + screenshot(page, "01_session_established"); + + // 步骤 2: 导航到登录页 + System.out.println("[2/6] 导航到登录页..."); + page.navigate(EtsScraper.LOGIN_URL, new Page.NavigateOptions() + .setTimeout(30000) + .setWaitUntil(WaitUntilState.NETWORKIDLE)); + EtsScraper.sleep(2000); + screenshot(page, "02_login_page_loaded"); + + // 步骤 3: 关闭通知弹窗 + System.out.println("[3/6] 关闭通知弹窗..."); + EtsScraper.closeNotificationDialog(page); + screenshot(page, "03_dialog_closed"); + + // 步骤 4: 下载验证码 + System.out.println("[4/6] 下载验证码..."); + EtsScraper.downloadCaptcha(page); + screenshot(page, "04_captcha_downloaded"); + + // 步骤 5: 识别验证码并登录 + System.out.println("[5/6] 识别验证码..."); + Path captchaPath = Path.of("screenshots/captcha.png"); + String captchaText = EtsScraper.recognizeCaptcha(captchaPath); + System.out.println("[+] 识别结果:" + captchaText); + + if (captchaText != null && !captchaText.isEmpty()) { + System.out.println("[6/6] 执行登录..."); + screenshot(page, "05_before_login"); + + // 填充验证码并登录 + String captchaInput = findCaptchaInput(page); + if (captchaInput != null) { + page.locator(captchaInput).first().fill(captchaText); + EtsScraper.sleep(500); + + // 点击登录按钮或按 Enter + String submitBtn = findSubmitButton(page); + if (submitBtn != null) { + page.locator(submitBtn).first().click(); + } else { + page.locator(captchaInput).first().press("Enter"); + } + + EtsScraper.sleep(3000); + screenshot(page, "06_after_login"); + + System.out.println(" - 页面标题:" + page.title()); + System.out.println(" - 页面 URL: " + page.url()); + System.out.println("=== 登录测试完成 ==="); + } + } else { + System.out.println("[-] 验证码识别失败,跳过登录"); + } + + } finally { + page.close(); + } + } + + private String findCaptchaInput(Page page) { + String[] selectors = new String[]{ + "input[placeholder*='验证码']", + "input[placeholder*='captcha']", + "input[name*='captcha']", + "input[name='code']", + }; + for (String selector : selectors) { + try { + if (page.locator(selector).first().isVisible( + new Locator.IsVisibleOptions().setTimeout(1000))) { + return selector; + } + } catch (Exception ignored) {} + } + return null; + } + + private String findSubmitButton(Page page) { + String[] selectors = new String[]{ + "button[type='submit']", + "input[type='submit']", + "button:has-text('登录')", + "button:has-text('Login')", + ".login-btn", + "#loginBtn", + }; + for (String selector : selectors) { + try { + if (page.locator(selector).first().isVisible( + new Locator.IsVisibleOptions().setTimeout(1000))) { + return selector; + } + } catch (Exception ignored) {} + } + return null; + } + + private void screenshot(Page page, String name) throws Exception { + try { + String timestamp = java.time.LocalDateTime.now() + .format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")); + Path path = Path.of("screenshots", name + "_" + timestamp + ".png"); + page.screenshot(new Page.ScreenshotOptions().setPath(path)); + System.out.println("[+] 截图保存:" + path); + } catch (Exception e) { + System.err.println("[-] 截图失败:" + e.getMessage()); + } + } +}