使用Selenium 爬虫12306 实现自动抢票
1.12306抢票
import org.jsoup.Jsoup
import org.openqa.selenium.By
import org.openqa.selenium.Keys
import org.openqa.selenium.firefox.FirefoxDriver
import org.openqa.selenium.firefox.FirefoxOptions
import org.openqa.selenium.firefox.FirefoxProfile
import org.openqa.selenium.interactions.Actions
import java.io.InputStreamReader
import java.util.*
const val URL = "https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc"
const val LOGIN_URL = "https://kyfw.12306.cn/otn/resources/login.html"
class Info_12306 {
}
fun main() {
val timer = Timer()
timer.schedule(object : TimerTask() {
override fun run() {
use()
}
}, 0, 80000)
}
fun use() {
val pro = Properties()
pro.load(InputStreamReader(Info_12306::class.java.classLoader.getResourceAsStream("12306.properties"),"UTF-8"))
val date = pro.getProperty("date")
val fromStation = pro.getProperty("startStation")
val toStation = pro.getProperty("endStation")
val lUsername = pro.getProperty("username")
val lPassword = pro.getProperty("password")
val passenger=pro.getProperty("passenger")
println(fromStation)
println(toStation)
System.setProperty("webdriver.gecko.driver", "/usr/local/bin/geckodriver")
var options = FirefoxOptions()
val profile = FirefoxProfile()
//禁止GPU渲染
options.addArguments("--disable-gpu")
// options.addArguments("--headless")
//忽略错误
options.addArguments("ignore-certificate-errors")
//禁止浏览器被自动化的提示
options.addArguments("--disable-infobars")
//反爬关键:window.navigator.webdrive值=false*********************
options.addPreference("dom.webdriver.enabled", false)
//设置请求头
profile.setPreference(
"general.useragent.override",
"Mozilla/5.0(iPhone;CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML,like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"
)
//禁用缓存
options.addPreference("network.http.use-cache", false)
options.addPreference("browser.cache.memory.enable", false)
options.addPreference("browser.cache.disk.enable", false)
options.addPreference("browser.sessionhistory.max_total_viewers", 3)
options.addPreference("network.dns.disableIPv6", true)
options.addPreference("Content.notify.interval", 750000)
options.addPreference("content.notify.backoffcount", 3)
options.addPreference("network.http.pipelining", true)
options.addPreference("network.http.proxy.pipelining", true)
options.addPreference("network.http.pipelining.maxrequests", 32)
val driver = FirefoxDriver(options)
// 访问登录界面
driver.get(LOGIN_URL)
// 必须执行 去除浏览器对selenium的识别 不然滑动验证码会报错
val script = "Object.defineProperty(navigator, 'webdriver', {get: () => false,});"
driver.executeScript(script)
// 用户名 密码 处理
val username = driver.findElement(By.id("J-userName"))
val password = driver.findElement(By.id("J-password"))
username.sendKeys(lUsername)
Thread.sleep(500)
password.sendKeys(lPassword)
Thread.sleep(500)
// 登录按钮
driver.findElement(By.id("J-login")).click()
Thread.sleep(1000)
//验证码
val block = driver.findElement(By.id("nc_1_n1z"))
val action = Actions(driver)
action.clickAndHold(block)
// 移动
action.moveByOffset(350, 0).perform()
Thread.sleep(300)
action.release().perform()
Thread.sleep(1000)
// 访问买票页面
driver.get(URL)
driver.findElement(By.id("qd_closeDefaultWarningWindowDialog_id")).click()
val startStation = driver.findElement(By.id("fromStationText"))
startStation.click()
startStation.sendKeys(fromStation)
startStation.sendKeys(Keys.ENTER)
val endStation = driver.findElement(By.id("toStationText"))
endStation.clear()
endStation.click()
endStation.sendKeys(toStation)
endStation.sendKeys(Keys.ENTER)
val startDate = driver.findElement(By.id("train_date"))
startDate.click()
startDate.clear()
startDate.sendKeys(date)
driver.findElement(By.id("cc_train_type_btn_all")).findElement(By.xpath("//input[@value='G']")).click()
driver.findElement(By.id("query_ticket")).click()
driver.findElement(By.id("avail_ticket")).click()
for (i in 0..3) {
driver.findElement(By.id("query_ticket")).click()
var flag = false
if (driver.findElement(By.id("show_all_query_result")).text != "显示全部车次") {
val trCollection = driver.findElement(By.id("queryLeftTable")).findElements(By.tagName("tr"))
trCollection.forEach {
val time = try {
it.findElement(By.className("start-t")).text.substring(0 until 2).toInt()
} catch (t: Throwable) {
100000
}
// 筛选时间
try {
if (time in 1..19 && it.findElements(By.tagName("td"))[3].text == "有") {
it.findElement(By.className("btn72")).click()
Thread.sleep(1500)
val dom= Jsoup.parse(driver.pageSource)
println(dom.getElementById("qd_closeDefaultWarningWindowDialog_id"))
// 买票
if (dom.getElementById("qd_closeDefaultWarningWindowDialog_id")!=null){
driver.findElement(By.id("qd_closeDefaultWarningWindowDialog_id")).click()
}
val liCollection =
driver.findElement(By.id("normal_passenger_id")).findElements(By.tagName("li"))
liCollection.forEach { info ->
if (info.findElement(By.tagName("label")).text == passenger) {
info.findElement(By.tagName("label")).click()
driver.findElement(By.id("submitOrder_id")).click()
Thread.sleep(2000)
driver.findElement(By.id("qr_submit_id")).click()
flag = true
}
}
}
} catch (t: Throwable) {
}
}
}
if (flag) {
driver.quit()
break
}
Thread.sleep(10000)
}
driver.quit()
}
config.properties
date=2022-10-09
startStation=武汉
endStation=北京西
username=aa
password=bb
passenger=乘车人
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了