如何用Java Streams优化Ebay自动化Selenium代码及FilterCarrier方法?
eBay自动化脚本优化:Java Streams应用与FilterCarrier方法改进
我是编程新手,编写了一段可运行的Ebay网站自动化脚本,但代码较为杂乱。现咨询如何使用Java Streams优化该代码,同时想了解是否有更简便的方式编写FilterCarrier方法,即是否存在更优的迭代实现方式。
以下是我的原代码:
import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.time.Duration; import java.util.Arrays; import java.util.List; import javax.imageio.ImageIO; import org.openqa.selenium.By; import org.openqa.selenium.OutputType; import org.openqa.selenium.Point; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.io.FileHandler; public class EbayTestCase { public static void main(String[] args) throws InterruptedException, IOException { // TODO Auto-generated method stub System.setProperty("webdriver.chrome.driver", "C:\\Users\\Mehdee\\Documents\\Eclipse projects\\Selenium\\ChromeDriver\\chromedriver.exe"); WebDriver driver = new ChromeDriver(); driver.manage().window().maximize(); driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(30)); // WebDriverWait w = new WebDriverWait(driver, Duration.ofSeconds(30)); driver.get("https://www.ebay.com/"); String[] carrFilter = { "Verizon", "T-Mobile", "Unlocked", "1&1" }; driver.findElement(By.id("gh-ac")).sendKeys("iPhone 14"); driver.findElement(By.id("gh-btn")).click(); System.out.println(ResultCount(driver) + " For iPhone 14"); Thread.sleep(1500); driver.findElement(By.cssSelector("input[aria-label='Apple iPhone 14 Pro Max']")).click(); System.out.println(ResultCount(driver) + " For Apple iPhone 14 Pro Max"); FilterCarrier(driver, carrFilter); ElementScreenshot(driver); driver.quit(); } public static void ElementScreenshot(WebDriver driver) throws IOException { WebElement ele = driver.findElement( By.xpath("//body/div[5]/div[4]/div[2]/div[1]/div[2]/ul[1]/li[2]/div[1]/div[1]/div[1]/a[1]/div[1]")); File SC = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); Point location = ele.getLocation(); int height = ele.getSize().getHeight(); int width = ele.getSize().getWidth(); BufferedImage img = ImageIO.read(SC); BufferedImage cropped = img.getSubimage(location.getX(), location.getY(), width, height); ImageIO.write(cropped, "png", SC); File fis = new File("C:\\Users\\Mehdee\\Documents\\SeleniumScreenshots\\screenshot.png"); FileHandler.copy(SC, fis); System.out.println("Screenshot has been successfully stored in C://Documents/SeleniumScreenshots directory"); } public static String ResultCount(WebDriver driver) { String[] t = driver.findElement(By.cssSelector(".srp-controls__count-heading")).getText().split(" "); String resultCount = t[0] + " Results Found"; return resultCount; } public static void FilterCarrier(WebDriver driver, String[] carrFilter) { List<WebElement> options = driver .findElements(By.xpath("//div[@id='x-refine__group_1__1']/ul/li/div/a/div/span/input")); int b = 0; for (int i = 0; i < options.size(); i++) { List<String> carrNames = Arrays.asList(carrFilter); WebElement option = options.get(i); String label = option.getAttribute("aria-label"); if (carrNames.contains(label)) { b++; options.get(i).click(); System.out.println(ResultCount(driver) + " for: " + label); options = driver.findElements(By.xpath("//div[@id='x-refine__group_1__1']/ul/li/div/a/div/span/input")); if (b == 4) { break; } } } } }
优化方案
一、核心问题梳理
原代码存在几个可优化的点:
FilterCarrier方法中每次循环都创建List<String> carrNames,重复操作浪费性能;- 硬编码的路径、选择器不易维护;
- 字符串处理、元素遍历可以通过Java Streams简化,提升可读性;
- 手动计数的迭代逻辑冗余。
二、具体优化实现
1. 提取常量,提升可维护性
把硬编码的驱动路径、截图路径、页面选择器等抽成类常量,避免重复修改:
private static final String CHROME_DRIVER_PATH = "C:\\Users\\Mehdee\\Documents\\Eclipse projects\\Selenium\\ChromeDriver\\chromedriver.exe"; private static final String SCREENSHOT_SAVE_PATH = "C:\\Users\\Mehdee\\Documents\\SeleniumScreenshots\\screenshot.png"; private static final By CARRIER_FILTER_OPTIONS = By.xpath("//div[@id='x-refine__group_1__1']/ul/li/div/a/div/span/input"); private static final By RESULT_COUNT_SELECTOR = By.cssSelector(".srp-controls__count-heading");
2. 用Java Streams优化ResultCount方法
原方法通过数组分割处理字符串,用Streams可以更严谨地提取第一个元素,避免数组越界风险:
public static String ResultCount(WebDriver driver) { return Arrays.stream(driver.findElement(RESULT_COUNT_SELECTOR).getText().split(" ")) .findFirst() .orElse("0") + " Results Found"; }
3. 改进FilterCarrier方法(核心优化)
原方法的迭代逻辑可以用Streams结合Set优化:
- 将
carrFilter转为HashSet,提升contains查询效率(O(1) vs List的O(n)); - 用Stream的
filter筛选目标元素,处理点击后DOM更新的问题(每次获取最新元素列表,避免旧元素失效); - 移除已处理的运营商,避免重复点击。
优化后的FilterCarrier:
public static void FilterCarrier(WebDriver driver, String[] carrFilter) { Set<String> targetCarriers = new HashSet<>(Arrays.asList(carrFilter)); int processedCount = 0; while (processedCount < carrFilter.length) { List<WebElement> options = driver.findElements(CARRIER_FILTER_OPTIONS); Optional<WebElement> targetOption = options.stream() .filter(elem -> targetCarriers.contains(elem.getAttribute("aria-label"))) .findFirst(); if (targetOption.isEmpty()) { break; } WebElement elem = targetOption.get(); String label = elem.getAttribute("aria-label"); elem.click(); processedCount++; System.out.println(ResultCount(driver) + " for: " + label); targetCarriers.remove(label); // 可选:等待页面加载,避免元素失效 try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }
4. 简化ElementScreenshot方法
简化变量声明,用常量存储元素定位器,提升代码可读性:
private static final By TARGET_SCREENSHOT_ELEMENT = By.xpath("//body/div[5]/div[4]/div[2]/div[1]/div[2]/ul[1]/li[2]/div[1]/div[1]/div[1]/a[1]/div[1]"); public static void ElementScreenshot(WebDriver driver) throws IOException { WebElement ele = driver.findElement(TARGET_SCREENSHOT_ELEMENT); File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); BufferedImage fullImg = ImageIO.read(screenshot); Point location = ele.getLocation(); BufferedImage croppedImg = fullImg.getSubimage( location.getX(), location.getY(), ele.getSize().getWidth(), ele.getSize().getHeight() ); ImageIO.write(croppedImg, "png", screenshot); FileHandler.copy(screenshot, new File(SCREENSHOT_SAVE_PATH)); System.out.println("截图已保存至:" + SCREENSHOT_SAVE_PATH); }
三、完整优化后代码
import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.time.Duration; import java.util.Arrays; import java.util.HashSet; import java.util.Optional; import java.util.Set; import javax.imageio.ImageIO; import org.openqa.selenium.By; import org.openqa.selenium.OutputType; import org.openqa.selenium.Point; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.io.FileHandler; public class EbayTestCase { // 常量提取 private static final String CHROME_DRIVER_PATH = "C:\\Users\\Mehdee\\Documents\\Eclipse projects\\Selenium\\ChromeDriver\\chromedriver.exe"; private static final String SCREENSHOT_SAVE_PATH = "C:\\Users\\Mehdee\\Documents\\SeleniumScreenshots\\screenshot.png"; private static final By CARRIER_FILTER_OPTIONS = By.xpath("//div[@id='x-refine__group_1__1']/ul/li/div/a/div/span/input"); private static final By RESULT_COUNT_SELECTOR = By.cssSelector(".srp-controls__count-heading"); private static final By TARGET_SCREENSHOT_ELEMENT = By.xpath("//body/div[5]/div[4]/div[2]/div[1]/div[2]/ul[1]/li[2]/div[1]/div[1]/div[1]/a[1]/div[1]"); public static void main(String[] args) throws InterruptedException, IOException { System.setProperty("webdriver.chrome.driver", CHROME_DRIVER_PATH); WebDriver driver = new ChromeDriver(); driver.manage().window().maximize(); driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(30)); driver.get("https://www.ebay.com/"); String[] carrFilter = { "Verizon", "T-Mobile", "Unlocked", "1&1" }; // 搜索iPhone 14 driver.findElement(By.id("gh-ac")).sendKeys("iPhone 14"); driver.findElement(By.id("gh-btn")).click(); System.out.println(ResultCount(driver) + " For iPhone 14"); Thread.sleep(1500); // 筛选Pro Max型号 driver.findElement(By.cssSelector("input[aria-label='Apple iPhone 14 Pro Max']")).click(); System.out.println(ResultCount(driver) + " For Apple iPhone 14 Pro Max"); // 筛选运营商 FilterCarrier(driver, carrFilter); // 截图 ElementScreenshot(driver); driver.quit(); } public static void ElementScreenshot(WebDriver driver) throws IOException { WebElement ele = driver.findElement(TARGET_SCREENSHOT_ELEMENT); File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); BufferedImage fullImg = ImageIO.read(screenshot); Point location = ele.getLocation(); BufferedImage croppedImg = fullImg.getSubimage( location.getX(), location.getY(), ele.getSize().getWidth(), ele.getSize().getHeight() ); ImageIO.write(croppedImg, "png", screenshot); FileHandler.copy(screenshot, new File(SCREENSHOT_SAVE_PATH)); System.out.println("截图已保存至:" + SCREENSHOT_SAVE_PATH); } public static String ResultCount(WebDriver driver) { return Arrays.stream(driver.findElement(RESULT_COUNT_SELECTOR).getText().split(" ")) .findFirst() .orElse("0") + " Results Found"; } public static void FilterCarrier(WebDriver driver, String[] carrFilter) { Set<String> targetCarriers = new HashSet<>(Arrays.asList(carrFilter)); int processedCount = 0; while (processedCount < carrFilter.length) { List<WebElement> options = driver.findElements(CARRIER_FILTER_OPTIONS); Optional<WebElement> targetOption = options.stream() .filter(elem -> targetCarriers.contains(elem.getAttribute("aria-label"))) .findFirst(); if (targetOption.isEmpty()) { break; } WebElement elem = targetOption.get(); String label = elem.getAttribute("aria-label"); elem.click(); processedCount++; System.out.println(ResultCount(driver) + " for: " + label); targetCarriers.remove(label); try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } }
内容的提问来源于stack exchange,提问作者Mehdee Ahmed
相关产品推荐
相关产品推荐

