用到的驱动和谷歌浏览器可在我的资源列表中查看到
驱动存放位置:
src/main/resources/chromedriver.exe
maven配置
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>com.springsource.com.gargoylesoftware.htmlunit</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<version>2.49.1</version>
</dependency>
<!-- selenium 浏览器测试 不添加此依赖会抛com.google.common.util.concurrent.SimpleTimeLimiter.create异常-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
话不多说,直接上代码
private static final String loginUrl = "https://kyfw.12306.cn/otn/resources/login.html";
private static final String indexUrl = "https://kyfw.12306.cn/otn/view/index.html";
private static final String searchUrl = "https://kyfw.12306.cn/otn/leftTicket/init";
private static final String confirmUrl = "https://kyfw.12306.cn/otn/payOrder/init";
public static void main(String[] args) throws InterruptedException {
// 获取驱动
WebDriver driver = getWebDriver();
// 最大化
driver.manage().window().maximize();
// 处理登录
handleLogin(driver);
// 前往搜索
handleSearch(driver);
// 用户输入的车次
String carCode = handleInputCarCode();
// 处理预定
handleReserve(driver, carCode);
// 处理提交
handleSubmit(driver);
// 处理确认提交信息
handleConfirm(driver);
// 处理提醒用户
handleCallUser(driver);
driver.get(confirmUrl);
List<WebElement> elements = driver.findElements(By.id("payButton"));
elements.get(0).click();
driver.get("https://epay.12306.cn/pay/payGateway");
Thread.sleep(2000);
WebElement element = driver.findElement(By.name("支付宝"));
element.click();
// 睡眠等待用户确认信息完毕
Thread.sleep(1000000);
// 关闭浏览器
driver.close();
}
private static void handleCallUser(WebDriver driver) throws InterruptedException {
String windowHandle = driver.getWindowHandle();
JavascriptExecutor executor = (JavascriptExecutor) driver;
executor.executeScript("window.open('https://music.163.com/#/song?id=224877')");
// 切换到网易云窗口
Thread.sleep(1000);
List<String> windowHandles = new ArrayList<>(driver.getWindowHandles());
driver.switchTo().window(windowHandles.get(windowHandles.size() - 1));
Thread.sleep(1000);
driver.switchTo().frame("contentFrame");
Thread.sleep(1000);
driver.findElement(By.cssSelector("[id=content-operation]>a:first-child")).click();
Thread.sleep(1000);
driver.switchTo().window(windowHandle);
}
private static void handleConfirm(WebDriver driver) throws InterruptedException {
Thread.sleep(1000);
if(driver.findElements(By.cssSelector("#checkticketinfo_id #qr_submit_id")).size() > 0) {
// 点击确认订单信息
driver.findElements(By.cssSelector("#checkticketinfo_id #qr_submit_id")).get(0).click();
}
log.debug("购票成功");
}
private static void handleSubmit(WebDriver driver) throws InterruptedException {
Thread.sleep(1000);
driver.findElement(By.cssSelector("#normalPassenger_0")).click();
//
do {
if(driver.findElements(By.cssSelector("#transforNotice_id #qr_closeTranforDialog_id")).size() > 0) {
// 这里有可能会出现网络繁忙的情况, 如果出现就点击确认, 关闭窗口, 然后再重试
driver.findElement(By.cssSelector("#transforNotice_id #qr_closeTranforDialog_id")).click();
}
Thread.sleep(1000);
driver.findElement(By.cssSelector("#submitOrder_id")).click();
//
} while(driver.findElements(By.cssSelector("#transforNotice_id #qr_closeTranforDialog_id")).size() > 0);
}
private static void handleLogin(WebDriver driver) throws InterruptedException {
driver.get(loginUrl);
List<WebElement> elements = driver.findElements(By.id("J-userName"));
elements.get(0).sendKeys("xxx");
List<WebElement> element2s = driver.findElements(By.id("J-password"));
element2s.get(0).sendKeys("xxx");
List<WebElement> element3s = driver.findElements(By.id("J-login"));
element3s.get(0).click();
List<WebElement> element4s = driver.findElements(By.id("id_card"));
Thread.sleep(3000);
element4s.get(0).sendKeys("xxx");
List<WebElement> element5s = driver.findElements(By.id("verification_code"));
element5s.get(0).click();
List<WebElement> element6s = driver.findElements(By.id("code"));
element6s.get(0).click();
List<WebElement> element7s = driver.findElements(By.id("sureClick"));
element7s.get(0).click();
// log.debug("等待用户登录");
// // 登录成功
// WebDriverWait wait = new WebDriverWait(driver, 120);
// wait.until(ExpectedConditions.urlContains(indexUrl));
log.debug("用户登录成功~");
}
private static void handleReserve(WebDriver driver, String carCode) throws InterruptedException {
clickSearch : for (int i = 1; ; i++) {
List<WebElement> trs = driver.findElements(By.cssSelector("table tbody#queryLeftTable:first-of-type tr"));
for (WebElement tr : trs) {
if (tr.getAttribute("id").contains("ticket_")) {
String currentCarCode = tr.findElements(By.cssSelector("td div.ticket-info > div.train a.number")).get(0).getText();
if (carCode.equals(currentCarCode)) {
// 找到了车次
WebElement purchaseTd = tr.findElement(By.cssSelector("td:last-of-type"));
String text = purchaseTd.getText();
log.debug("找到预定text:" + text);
List<WebElement> aElementList = purchaseTd.findElements(By.tagName("a"));
if (aElementList.size() > 0) {
log.debug("点击预定:");
purchaseTd.click();
Thread.sleep(1000);
if (driver.findElements(By.id("defaultwarningAlert_id")).size() > 0) {
// 可能出现不可以预定时间
List<WebElement> tips = driver.findElements(By.id("content_defaultwarningAlert_hearder"));
if (tips.size() > 0) {
String tip = tips.get(0).getText();
log.debug("预定失败:" + tip);
}
// 关闭弹窗
driver.findElement(By.id("qd_closeDefaultWarningWindowDialog_id")).click();
continue clickSearch;
}
// 需要处理登录问题
break clickSearch;
}
}
}
}
// 没有找到车次, 或者, 点击查询按钮, 10次刷新一下页面
if (i % 10 == 0) {
log.debug("重新刷新页面");
driver.navigate().refresh();
continue;
}
long sleepTime = ThreadLocalRandom.current().nextLong(800, 2000);
Thread.sleep(sleepTime);
List<WebElement> query_ticket = driver.findElements(By.id("query_ticket"));
if (query_ticket.size() > 0) {
log.debug("准备点击查询更新数据第: " + i + " 次");
query_ticket.get(0).click();
// 等待页面数据出来
WebDriverWait wait = new WebDriverWait(driver, 120);
wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("table tbody#queryLeftTable:first-of-type tr")));
} else {
log.debug("查询按钮不可用");
}
}
}
private static String handleInputCarCode() {
System.err.println("=============================请在下方输入你需要抢购的车次==================================");
String carCode = null;
try (Scanner scanner = new Scanner(System.in)) {
while (StringUtils.isEmpty(carCode)) {
System.out.println();
carCode = scanner.nextLine();
}
}
System.out.println("您输入的车次为:" + carCode);
return carCode;
}
private static void handleSearch(WebDriver driver) {
driver.get(searchUrl);
System.out.println();
System.err.println("请在打开的浏览器页面中填写 '出发地' '目的地' '出发日' 等相关信息, 并且点击 '查询' 按钮完成本次操作");
// 获取搜索的条数
WebDriverWait wait = new WebDriverWait(driver,120);
wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("table tbody#queryLeftTable:first-of-type tr")));
List<WebElement> trs = driver.findElements(By.cssSelector("table tbody#queryLeftTable:first-of-type tr"));
List<String> currentCarCodeList = new ArrayList<>(16);
for (WebElement tr : trs) {
if (tr.getAttribute("id").contains("ticket_")) {
String currentCarCode = tr.findElements(By.cssSelector("td div.ticket-info > div.train a.number")).get(0).getText();
currentCarCodeList.add(currentCarCode);
}
}
System.out.println("本次查找到车次数量为: " + currentCarCodeList.size());
for (int i = 0; i < currentCarCodeList.size(); i++) {
String currentCarCode = currentCarCodeList.get(i);
System.out.print(currentCarCode + "\t||\t");
if (i % 5 == 1) {
System.out.println();
}
}
}
private static WebDriver getWebDriver() {
// System.setProperty("webdriver.chrome.driver", "C:\\install\\chromedriver\\chromedriver.exe");// chromedriver地址
System.setProperty("webdriver.chrome.driver", "src/main/resources/chromedriver.exe");// chromedriver地址
WebDriver driver = new ChromeDriver(); // 新建一个WebDriver 的对象,但是new 的是谷歌的驱动
return driver;
}