fix download excel

This commit is contained in:
Niko 2026-05-05 22:05:32 +08:00
parent b86d0bf82f
commit 1b7ebb4325
4 changed files with 20 additions and 158 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@ -99,8 +99,10 @@ public class EtsScraper {
try (Playwright playwright = Playwright.create()) { try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.chromium().launch( Browser browser = playwright.chromium().launch(
new BrowserType.LaunchOptions().setHeadless(true) new BrowserType.LaunchOptions()
.setHeadless(false)
); );
BrowserContext context = browser.newContext( BrowserContext context = browser.newContext(
new Browser.NewContextOptions() new Browser.NewContextOptions()
.setIgnoreHTTPSErrors(true) .setIgnoreHTTPSErrors(true)
@ -127,7 +129,7 @@ public class EtsScraper {
// Close notification dialog FIRST (before filling credentials) // Close notification dialog FIRST (before filling credentials)
closeNotificationDialog(page); closeNotificationDialog(page);
screenshot(page, "after_close_dialog"); // screenshot(page, "after_close_dialog");
// Download captcha image // Download captcha image
downloadCaptcha(page); downloadCaptcha(page);
@ -142,7 +144,7 @@ public class EtsScraper {
System.out.println("[+] Login successful!"); System.out.println("[+] Login successful!");
sleep(2000); sleep(2000);
screenshot(page, "after_login"); // screenshot(page, "after_login");
System.out.println("[+] Page title: " + page.title()); System.out.println("[+] Page title: " + page.title());
System.out.println("[+] Page URL: " + page.url()); System.out.println("[+] Page URL: " + page.url());
@ -152,7 +154,7 @@ public class EtsScraper {
page.locator("#module_2094F683-C542-4904-B33E-0D227C4DE199").first().click(); page.locator("#module_2094F683-C542-4904-B33E-0D227C4DE199").first().click();
sleep(3000); sleep(3000);
screenshot(page, "after_sanliandan"); // screenshot(page, "after_sanliandan");
System.out.println("[+] 三联单 page title: " + page.title()); System.out.println("[+] 三联单 page title: " + page.title());
// 设置日期筛选 // 设置日期筛选
@ -185,21 +187,16 @@ public class EtsScraper {
// 点击查询按钮等待列表加载 // 点击查询按钮等待列表加载
if (queryBtnExists) { if (queryBtnExists) {
System.out.println("[*] Clicking query button..."); System.out.println("[*] Clicking query button...");
page.locator("#Search_ThreeBillList_Button").first().click();
// 等待列表内容出现 // 等待列表内容出现
try { page.waitForResponse("https://101.227.180.215/SHCityEnvCW/Services/CWSServ.asmx/ThreeBillQueryBiTripList", () -> {
page.waitForSelector("tbody tr", new Page.WaitForSelectorOptions() page.locator("#Search_ThreeBillList_Button").first().click();
.setTimeout(30000)); });
System.out.println("[+] Query completed, list loaded"); page.waitForTimeout(3 * 1000);
} catch (Exception e) {
System.out.println("[!] Wait for list timeout, but query was submitted");
}
} else { } else {
System.out.println("[!] Query button not found"); System.out.println("[!] Query button not found");
} }
screenshot(page, "after_query"); // screenshot(page, "after_query");
// 点击导出按钮 // 点击导出按钮
if (page.locator("#Export_ThreeBillList_Button").count() > 0) { if (page.locator("#Export_ThreeBillList_Button").count() > 0) {
@ -210,34 +207,25 @@ public class EtsScraper {
() -> { () -> {
page.locator("#Export_ThreeBillList_Button").first().click(); page.locator("#Export_ThreeBillList_Button").first().click();
sleep(2000); sleep(2000);
System.out.println("[*] Triggering dialog export via JS...");
page.evaluate("document.querySelectorAll('button').forEach(b => { if (b.textContent.trim() === '导出') b.click(); })");
}); });
System.out.println("[*] Waiting for download to complete..."); System.out.println("[*] Waiting for download to complete...");
long[] totalBytes = {0}; dl.saveAs(savedFile);
try (java.io.InputStream stream = dl.createReadStream();
java.io.OutputStream out = Files.newOutputStream(savedFile)) { long totalBytes = savedFile.toFile().length();
byte[] buf = new byte[8192]; System.out.println("[+] Download saved to: " + savedFile + " (" + totalBytes + " bytes)");
int n; if (totalBytes == 0) {
while ((n = stream.read(buf)) > 0) {
out.write(buf, 0, n);
totalBytes[0] += n;
}
}
System.out.println("[+] Download saved to: " + savedFile + " (" + totalBytes[0] + " bytes)");
if (totalBytes[0] == 0) {
System.out.println("[-] Downloaded file is empty"); System.out.println("[-] Downloaded file is empty");
} else { } else {
System.out.println("[+] Download size: " + totalBytes[0] + " bytes"); System.out.println("[+] Download size: " + totalBytes + " bytes");
// Auto-import to ets-proxy
autoImportBill(savedFile, proxyHost, proxyUser, proxyPass); autoImportBill(savedFile, proxyHost, proxyUser, proxyPass);
} }
} }
screenshot(page, "after_export"); // screenshot(page, "after_export");
System.out.println("[+] Query and export completed!"); System.out.println("[+] Query and export completed!");
} else { } else {
System.out.println("[-] Login failed. Check screenshots/ for debugging."); System.out.println("[-] Login failed. Check screenshots/ for debugging.");
screenshot(page, "login_failed"); // screenshot(page, "login_failed");
} }
} finally { } finally {
browser.close(); browser.close();

View File

@ -1,90 +0,0 @@
package com.ets.scraper;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.io.TempDir;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.junit.jupiter.api.Assertions.*;
class EtsScraperTest {
@TempDir
Path tempDir;
@Test
void testGifToPngConversion() throws Exception {
Path gifPath = tempDir.resolve("captcha.png");
// Copy the actual captcha (GIF stored as .png) to temp
Files.copy(
Path.of("screenshots/captcha.png").toAbsolutePath(),
gifPath
);
byte[] imageBytes = Files.readAllBytes(gifPath);
ByteArrayInputStream bais = new ByteArrayInputStream(imageBytes);
BufferedImage gifImage = ImageIO.read(bais);
assertNotNull(gifImage, "GIF should be readable by ImageIO");
assertTrue(gifImage.getWidth() > 0, "Image should have positive width");
ByteArrayOutputStream pngOut = new ByteArrayOutputStream();
ImageIO.write(gifImage, "png", pngOut);
byte[] pngBytes = pngOut.toByteArray();
assertTrue(pngBytes.length > 0, "PNG output should not be empty");
// Verify converted PNG is valid
ByteArrayInputStream bais2 = new ByteArrayInputStream(pngBytes);
BufferedImage pngImage = ImageIO.read(bais2);
assertNotNull(pngImage, "Converted PNG should be readable");
}
@Test
void testGifToPngProducesValidPng() throws Exception {
byte[] gifBytes = Files.readAllBytes(Path.of("screenshots/captcha.png").toAbsolutePath());
ByteArrayInputStream bais = new ByteArrayInputStream(gifBytes);
BufferedImage image = ImageIO.read(bais);
ByteArrayOutputStream pngOut = new ByteArrayOutputStream();
ImageIO.write(image, "png", pngOut);
// PNG header: 89 50 4E 47 0D 0A 1A 0A
byte[] pngHeader = pngOut.toByteArray();
// bytes are signed in Java, mask with & 0xFF
assertEquals(0x89 & 0xFF, pngHeader[0] & 0xFF, "PNG magic number");
assertEquals(0x50 & 0xFF, pngHeader[1] & 0xFF, "P");
assertEquals(0x4E & 0xFF, pngHeader[2] & 0xFF, "N");
assertEquals(0x47 & 0xFF, pngHeader[3] & 0xFF, "G");
}
@Test
void testBase64Encoding() throws Exception {
byte[] imageBytes = Files.readAllBytes(Path.of("screenshots/captcha.png").toAbsolutePath());
String base64 = java.util.Base64.getEncoder().encodeToString(imageBytes);
assertNotNull(base64);
assertTrue(base64.length() > 0, "Base64 should not be empty");
assertFalse(base64.contains("\n"), "Base64 should be single line");
// Verify roundtrip
byte[] decoded = java.util.Base64.getDecoder().decode(base64);
assertArrayEquals(imageBytes, decoded, "Base64 roundtrip should match original");
}
@Test
void testCaptchaRecognition() throws Exception {
Path captchaPath = Path.of("screenshots/captcha.png");
String captchaText = EtsScraper.recognizeCaptcha(captchaPath);
System.out.println("[+] Recognized captcha: " + captchaText);
assertNotNull(captchaText, "Captcha recognition should return a result");
assertFalse(captchaText.isEmpty(), "Captcha text should not be empty");
System.out.println("[+] Captcha length: " + captchaText.length() + " chars");
}
}

View File

@ -1,36 +0,0 @@
package com.ets.scraper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.File;
import java.nio.file.Path;
import static org.junit.jupiter.api.Assertions.*;
class ImportTest {
private static final String PROXY_HOST = "https://api.ets.niko.red";
private static final String USERNAME = "admin";
private static final String PASSWORD = "123456";
@TempDir
Path tempDir;
@Test
void testImportExcel() throws Exception {
File testFile = tempDir.resolve("三联单列表_20260504.xls").toFile();
Path source = Path.of("downloads/三联单列表_20260504.xls");
if (source.toFile().exists()) {
java.nio.file.Files.copy(source, testFile.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
} else {
System.out.println("[!] Test file not found at " + source + ", using temp file as fallback");
}
assertTrue(testFile.exists(), "Test file must exist");
String token = EtsScraper.proxyLogin(PROXY_HOST, USERNAME, PASSWORD);
assertNotNull(token);
EtsScraper.proxyImport(testFile.toPath(), PROXY_HOST, token);
}
}