大家好啊!我是NiJiMingCheng
我的博客:NiJiMingCheng
上一节我们分享了安装selenium的内容,这一节我们继续来实战,这一节我们主要学习爬取上海软科中国大学排名并存入表格,本文仅以办学层次进行演示,其他数据同理可得,加油
Selenium 各浏览器驱动下载与配置使用(详细流程)
在如今这个快节奏的时代,出行需求日益增长,尤其是在节假日或者特殊时期,购买火车票往往成为一件颇具挑战性的事情。为了帮助大家更顺利地抢到心仪的车票,今天我将为大家详细解析一段 12306 抢票助手的代码,并教大家如何使用它。
目录
Python Selenium 各浏览器驱动下载与配置使用(详细流程)
2. login_QR 函数和 login_password 函数
结果展示(文末附完整代码):
Python Selenium 各浏览器驱动下载与配置使用(详细流程)
一、代码概述
这段代码主要是利用 Python 的 Selenium 库来实现自动化操作 12306 网站,完成登录、输入行程信息以及查询和抢购指定车次车票的功能。下面我们将逐步分析代码中的各个关键部分。
1. 导入必要的库
代码开头导入了一系列必要的库,包括:
import time
import logging
from datetime import datetime
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.edge.options import Options
这些库分别用于处理时间、日志记录、网页元素定位以及设置 Edge 浏览器的相关选项等操作,它们是整个抢票程序能够正常运行的基础。
2. 配置类 Config
class Config:
def __init__(self):
self.username = ''
self.password = ''
self.fromstation = ''
self.destination = ''
self.date = '2024-12-12'
self.trainnumber = ''
这里定义了一个 Config
类,用于存储抢票所需的各种配置信息,如用户名、密码、出发地、目的地、出发日期以及要抢购的车次等。在实际使用时,我们需要根据自己的需求填充这些信息。
二、主要函数功能解析
1. input_info
函数
def input_info(driver, conf):
# 输入出发地和目的地信息
from_station_tag = driver.find_element(By.XPATH, '//*[@id="fromStationText"]')
from_station_tag.click()
from_station_tag.clear()
from_station_tag.send_keys(conf.fromstation)
from_station_tag.send_keys(Keys.ENTER)
# 目的地
to_station_tag = driver.find_element(By.XPATH, '//*[@id="toStationText"]')
to_station_tag.click()
to_station_tag.clear()
to_station_tag.send_keys(conf.destination)
to_station_tag.send_keys(Keys.ENTER)
# 出发日期
date_tag = driver.find_element(By.XPATH, '//*[@id="train_date"]')
date_tag.click()
date_tag.clear()
date_tag.send_keys(conf.date)
date_tag.send_keys(Keys.ENTER)
这个函数的主要作用是在 12306 的订票页面上自动输入出发地、目的地以及出发日期等信息。它通过 Selenium
的 find_element
方法根据 XPATH
定位到相应的网页元素,然后进行点击、清除原有内容并输入新内容等操作,最后通过按下回车键完成信息的输入。
2. login_QR
函数和 login_password
函数
这两个函数分别实现了通过扫码登录和账号密码登录 12306 的功能。
login_QR
函数:
def login_QR(url):
# 反检测设置
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
"""})
driver.maximize_window()
driver.get(url)
# 最多等待5秒使页面加载进来,隐式等待
driver.implicitly_wait(5)
# 获取并点击右上角登录按钮
login = driver.find_element(By.ID, 'J-btn-login')
login.click()
driver.implicitly_wait(10)
# 扫码登录
scan_QR = driver.find_element(By.XPATH, '//*[@id="toolbar_Div"]/div[2]/div[2]/ul/li[2]/a')
scan_QR.click()
在这个函数中,首先进行了反检测设置,这是为了避免 12306 网站检测到我们使用自动化工具而采取的措施。然后打开 12306 网站,等待页面加载后点击登录按钮,最后进入扫码登录的流程。
login_password
函数:
def login_password(url):
# 反检测设置
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
"""})
driver.maximize_window()
driver.get(url)
# 最多等待5秒使页面加载进来,隐式等待
driver.implicitly_wait(5)
# 获取并点击右上角登录按钮
login = driver.find_element(By.ID, 'J-btn-login')
login.click()
driver.implicitly_wait(10)
# 账号密码登录
username_tag = driver.find_element(By.ID, 'J-userName')
username_tag.send_keys(conf.username)
password_tag = driver.find_element(By.ID, 'J-password')
password_tag.send_keys(conf.password)
login_now = driver.find_element(By.ID, 'J-login')
login_now.click()
driver.find_element(By.ID, 'id_card').send_keys(8834)
driver.find_element(By.ID, 'verification_code').click()
driver.find_element(By.ID, 'code').send_keys(int(input('请输入验证码:')))
driver.find_element(By.ID, 'sureClick').click()
# idcard.send_keys(8834)
logging.info('已成功进入12306啦!!!正在努力抢票呀!!!')
与 login_QR
类似,先进行反检测设置和页面加载等待等操作,然后在点击登录按钮后,通过定位相应的网页元素,输入用户名、密码,并根据提示输入验证码等步骤完成账号密码登录的过程。
3. get_ticket
函数
def get_ticket(conf, driver, url):
# 扫码登录
login_QR(url)
# 账号密码登录
# login_password(url)
driver.implicitly_wait(10)
# 点击车票预订
driver.find_element(By.XPATH, '//*[@id="link_for_ticket"]').click()
time.sleep(2) # 等待页面加载
input_info(driver, conf)
start_time = time.time()
query_tag = driver.find_element(By.XPATH, '//*[@id="query_ticket"]')
# 设置 logging
logging.basicConfig(level=logging.INFO)
while True:
# 点击查询
driver.execute_script("arguments[0].click();", query_tag)
time.sleep(0.01) # 等待页面更新
try:
if ticket_G(driver):
logging.info('本次购票成功啦!!!')
# time.sleep(1)
break
else:
pass
except Exception as e:
logging.warning(e)
这个函数是整个抢票流程的核心控制函数。它首先调用 login_QR
函数进行扫码登录(也可以选择调用 login_password
函数进行账号密码登录),然后点击车票预订按钮,接着通过调用 input_info
函数输入行程信息,之后设置日志记录并点击查询按钮开始查询车票。在查询到符合条件的车票之前,它会不断循环尝试,一旦通过调用 ticket_G
函数判断购票成功,就会跳出循环并记录相应的日志信息。
4. ticket_G
函数和 ticket_K
函数
这两个函数分别用于处理高铁(G 字头)车次和其他类型(这里以 K 字头为例)车次的购票具体操作。
ticket_G
函数:
def ticket_G(driver):
logging.info('OK,时间到啦,进入购票啦')
# 获取所有车票
tickets = driver.find_elements(By.XPATH, '//*[@id="queryLeftTable"]/tr')
# 每张车票有两个tr,但是第二个tr没什么用
tickets = [tickets[i] for i in range(len(tickets) - 1) if i % 2 == 0]
for ticket in tickets:
# 高铁二等座
if ticket.find_element(By.CLASS_NAME, 'number').text == conf.trainnumber and ticket.find_element(By.XPATH,
'//td[5]').text!= "候补":
# 点击预订
ticket.find_element(By.CLASS_NAME, 'btn72').click()
driver.find_element(By.ID, "normalPassenger_0").click()
// 点击确认购买学生票,如果不是学生,把这行注释了就行
driver.find_element(By.XPATH, '//*[@id="dialog_xsertcj_ok"]').click()
// 提交订单
driver.find_element(By.XPATH, '//*[@id="submitOrder_id"]').click()
// 选座 D座
driver.find_element(By.XPATH, '/html/body/div[6]/div/div[5]/div[1]/div/div[2]/div[2]/div[3]/div[2]/div['
'2]/ul['
'2]/li[1]/a[@id="1D"]').click()
// 确认提交订单,然后这里和上面是一样的
driver.find_element(By.XPATH, '/html/body/div[6]/div/div[5]/div[1]/div/div[2]/div[2]/div[8]/a[2]['
'@class="btn92s"]').click()
logging.info(f"{conf.trainnumber}次列车抢票成功,请尽快在10分钟内支付!")
return True
else:
pass
在这个函数中,首先获取所有车票信息,然后筛选出有用的车票记录(这里排除了每张车票的第二个 tr
元素)。接着遍历这些车票记录,当找到指定车次且该车次的二等座不是候补状态时,就会依次点击预订、选择乘车人、确认购买学生票(如果需要)、提交订单、选座以及确认提交订单等操作,最后记录抢票成功的日志信息并返回 True
。
ticket_K
函数:
def ticket_K(driver):
logging.info('OK,时间到啦,进入购票啦!!!')
// 获取所有车票
tickets = driver.find_elements(By.XPATH, '//*[@id="queryLeftTable"]/tr')
// 每张车票有两个tr,但是第二个tr没什么用
tickets = [tickets[i] for i in range(len(tickets) - 1) if i % 2 == 0]
for ticket in tickets:
if ticket.find_element(By.CLASS_NAME, 'number').text == conf.trainnumber and ticket.find_element(
By.XPATH, './td[10]').text!= "候补":
logging.info(ticket.find_element(By.XPATH, './td[10]').get_attribute('aria-label'))
ticket.find_element(By.CLASS_NAME, 'btn72').click()
driver.find_element(By.ID, "normalPassenger_0").click()
// 点击确认购买学生票,如果不是学生,把这行注释了就行
driver.find_element(By.XPATH, '//*[@id="dialog_xsertcj_ok"]').call('click');
// 提交订单
driver.find_element(By.XPATH, '//*[@id="submitOrder_id"]').click();
// 确认提交订单,然后这里和上面是一样的
driver.find_element(By.XPATH, '/html/body/div[6]/div/div[5]/div[1]/div/div[2]/div[2]/div[8]/a[2]['
'@class="btn92s"]').click();
logging.info(f"{conf.trainnumber}次列车抢票成功,请尽快在10分钟内支付!");
return True;
else:
pass;
与 ticket_G
函数类似,ticket_K
函数也是先获取车票信息并筛选,然后遍历查找指定车次且不是候补状态的车票,之后进行一系列的购票操作,最后记录抢票成功信息并返回 True
。
三、主运行代码
1. 配置 Edge 浏览器选项
if __name__ == '__main__':
edge_options = Options()
edge_options.add_experimental_option('excludeSwitches', ['enable-automation'])
edge_options.add_argument('--disable-blink-features=AutomationControlled')
- 首先创建了一个
Options
对象,用于设置 Edge 浏览器的一些启动选项。 add_experimental_option('excludeSwitches', ['enable-automation'])
这行代码的作用是排除某些开关选项,这里特别排除了enable-automation
这个选项,目的是为了绕过一些网站对自动化工具(如 Selenium)的检测机制。很多网站会通过检测浏览器是否处于自动化控制状态来判断是否是正常的用户访问,如果检测到是自动化控制,可能会拒绝服务或者采取其他限制措施,通过排除这个开关选项可以在一定程度上伪装成正常的浏览器访问。add_argument('--disable-blink-features=AutomationControlled')
进一步设置浏览器的启动参数,禁用特定的 Blink 特性(Blink 是浏览器渲染引擎的一部分),这里也是与绕过自动化检测相关,使得浏览器在运行时表现得更像普通用户使用的浏览器,而不是被自动化工具明显控制的状态。
3. 启动 Edge 浏览器驱动
driver = webdriver.Edge(options=edge_options)
这行代码创建了一个 Edge 浏览器的驱动实例 driver
,并传入了之前设置好的 edge_options
。这个驱动实例将用于后续与 Edge 浏览器进行交互,例如打开网页、查找网页元素、执行点击、输入等操作,它是通过 Selenium 库来实现对浏览器自动化控制的核心对象。
4. 创建配置对象并设置 URL
conf = Config()
url = 'https://www.12306.cn/index/'
conf = Config()
创建了一个Config
类的实例对象,这个类在前面代码中应该已经定义过(从提供的完整代码来看,它用于存储诸如用户名、密码、出发地、目的地等抢票相关的配置信息),这里创建实例后可以通过它来设置和传递具体的抢票配置参数。url = 'https://www.12306.cn/index/'
定义了要访问的 12306 网站的首页地址,后续会通过浏览器驱动driver
将这个网址打开,以便在这个网站上进行抢票相关的操作。
5. 执行抢票流程
get_ticket(conf, driver, url)
这行代码调用了 get_ticket
函数,并传入了之前创建的配置对象 conf
、浏览器驱动对象 driver
以及 12306 网站的网址 url
。这个 get_ticket
函数应该是整个抢票程序的核心逻辑所在,它内部会包含一系列操作,比如登录(可能是扫码登录或者账号密码登录等方式)、输入行程信息、查询车票、判断是否有符合条件的车票并尝试进行购票等一系列流程,通过这一行代码的调用,整个抢票程序就正式启动并按照预设的逻辑进行运作。
四、代码使用步骤
完整代码:
# -*- coding:utf-8 -*-
import time
import logging
from datetime import datetime
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.edge.options import Options
class Config:
def __init__(self):
self.username = ''
self.password = ''
self.fromstation = ''
self.destination = ''
self.date = '2024-12-12'
self.trainnumber = ''
def input_info(driver, conf):
# 输入出发地和目的地信息
from_station_tag = driver.find_element(By.XPATH, '//*[@id="fromStationText"]')
from_station_tag.click()
from_station_tag.clear()
from_station_tag.send_keys(conf.fromstation)
from_station_tag.send_keys(Keys.ENTER)
# 目的地
to_station_tag = driver.find_element(By.XPATH, '//*[@id="toStationText"]')
to_station_tag.click()
to_station_tag.clear()
to_station_tag.send_keys(conf.destination)
to_station_tag.send_keys(Keys.ENTER)
# 出发日期
date_tag = driver.find_element(By.XPATH, '//*[@id="train_date"]')
date_tag.click()
date_tag.clear()
date_tag.send_keys(conf.date)
date_tag.send_keys(Keys.ENTER)
def login_QR(url):
# 反检测设置
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
"""})
driver.maximize_window()
driver.get(url)
# 最多等待5秒使页面加载进来,隐式等待
driver.implicitly_wait(5)
# 获取并点击右上角登录按钮
login = driver.find_element(By.ID, 'J-btn-login')
login.click()
driver.implicitly_wait(10)
# 扫码登录
scan_QR = driver.find_element(By.XPATH, '//*[@id="toolbar_Div"]/div[2]/div[2]/ul/li[2]/a')
scan_QR.click()
def login_password(url):
# 反检测设置
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
"""})
driver.maximize_window()
driver.get(url)
# 最多等待5秒使页面加载进来,隐式等待
driver.implicitly_wait(5)
# 获取并点击右上角登录按钮
login = driver.find_element(By.ID, 'J-btn-login')
login.click()
driver.implicitly_wait(10)
# 账号密码登录
username_tag = driver.find_element(By.ID, 'J-userName')
username_tag.send_keys(conf.username)
password_tag = driver.find_element(By.ID, 'J-password')
password_tag.send_keys(conf.password)
login_now = driver.find_element(By.ID, 'J-login')
login_now.click()
driver.find_element(By.ID, 'id_card').send_keys(8834)
driver.find_element(By.ID, 'verification_code').click()
driver.find_element(By.ID, 'code').send_keys(int(input('请输入验证码:')))
driver.find_element(By.ID, 'sureClick').click()
# idcard.send_keys(8834)
logging.info('已成功进入12306啦!!!正在努力抢票呀!!!')
def get_ticket(conf, driver, url):
# 扫码登录
login_QR(url)
# 账号密码登录
# login_password(url)
driver.implicitly_wait(10)
# 点击车票预订
driver.find_element(By.XPATH, '//*[@id="link_for_ticket"]').click()
time.sleep(2) # 等待页面加载
input_info(driver, conf)
start_time = time.time()
query_tag = driver.find_element(By.XPATH, '//*[@id="query_ticket"]')
# 设置 logging
logging.basicConfig(level=logging.INFO)
while True:
# 点击查询
driver.execute_script("arguments[0].click();", query_tag)
time.sleep(0.01) # 等待页面更新
try:
if ticket_G(driver):
logging.info('本次购票成功啦!!!')
# time.sleep(1)
break
else:
pass
except Exception as e:
logging.warning(e)
def ticket_G(driver):
logging.info('OK,时间到啦,进入购票啦')
# 获取所有车票
tickets = driver.find_elements(By.XPATH, '//*[@id="queryLeftTable"]/tr')
# 每张车票有两个tr,但是第二个tr没什么用
tickets = [tickets[i] for i in range(len(tickets) - 1) if i % 2 == 0]
for ticket in tickets:
# 高铁二等座
if ticket.find_element(By.CLASS_NAME, 'number').text == conf.trainnumber and ticket.find_element(By.XPATH,
'//td[5]').text != "候补":
# 点击预订
ticket.find_element(By.CLASS_NAME, 'btn72').click()
driver.find_element(By.ID, "normalPassenger_0").click()
# 点击确认购买学生票,如果不是学生,把这行注释了就行
driver.find_element(By.XPATH, '//*[@id="dialog_xsertcj_ok"]').click()
# time.sleep(2000)
# 第二个乘车人
# driver.find_element(By.XPATH, '//*[@id="normalPassenger_1"]').click()
# 如果第二个乘车人也是学生,则需要点击确认第二个人也购买学生票
# driver.find_element(By.XPATH, '//*[@id="dialog_xsertcj_ok"]').click()
# 提交订单
driver.find_element(By.XPATH, '//*[@id="submitOrder_id"]').click()
# 选座 D座
driver.find_element(By.XPATH, '/html/body/div[6]/div/div[5]/div[1]/div/div[2]/div[2]/div[3]/div[2]/div['
'2]/ul['
'2]/li[1]/a[@id="1D"]').click()
# 确认提交订单,然后这里和上面是一样的
driver.find_element(By.XPATH, '/html/body/div[6]/div/div[5]/div[1]/div/div[2]/div[2]/div[8]/a[2]['
'@class="btn92s"]').click()
logging.info(f"{conf.trainnumber}次列车抢票成功,请尽快在10分钟内支付!")
return True
else:
pass
def ticket_K(driver):
logging.info('OK,时间到啦,进入购票啦!!!')
# 获取所有车票
tickets = driver.find_elements(By.XPATH, '//*[@id="queryLeftTable"]/tr')
# 每张车票有两个tr,但是第二个tr没什么用
tickets = [tickets[i] for i in range(len(tickets) - 1) if i % 2 == 0]
for ticket in tickets:
if ticket.find_element(By.CLASS_NAME, 'number').text == conf.trainnumber and ticket.find_element(
By.XPATH, './td[10]').text != "候补":
logging.info(ticket.find_element(By.XPATH, './td[10]').get_attribute('aria-label'))
ticket.find_element(By.CLASS_NAME, 'btn72').click()
driver.find_element(By.ID, "normalPassenger_0").click()
# 点击确认购买学生票,如果不是学生,把这行注释了就行
driver.find_element(By.XPATH, '//*[@id="dialog_xsertcj_ok"]').click()
# 提交订单
driver.find_element(By.XPATH, '//*[@id="submitOrder_id"]').click()
# time.sleep(1000)
# time.sleep(0.1)
# 确认提交订单,然后这里和上面是一样的
driver.find_element(By.XPATH, '/html/body/div[6]/div/div[5]/div[1]/div/div[2]/div[2]/div[8]/a[2]['
'@class="btn92s"]').click()
logging.info(f"{conf.trainnumber}次列车抢票成功,请尽快在10分钟内支付!")
return True
else:
pass
if __name__ == '__main__':
edge_options = Options()
edge_options.add_experimental_option('excludeSwitches', ['enable-automation'])
edge_options.add_argument('--disable-blink-features=AutomationControlled')
driver = webdriver.Edge(options=edge_options)
conf = Config()
url = 'https://www.12306.cn/index/'
get_ticket(conf, driver, url)
1. 配置信息填写
首先,我们需要打开代码文件,找到 Config
类的定义部分,根据自己的实际情况填写以下信息:
username
:你的 12306 账号用户名。password
:你的 12306 账号密码。fromstation
:出发地车站名称,需与 12306 网站上显示的一致。destination
:目的地车站名称,同样需与网站上显示的一致。date
:出发日期,格式为YYYY-MM-DD
,如2024-12-12
。trainnumber
:要抢购的车次编号,比如G1234
等。
2. 安装必要的库
确保你的电脑上已经安装了以下库:
selenium
:可以通过pip install selenium
命令进行安装。logging
:这是 Python 内置的标准库,一般无需额外安装。
3. 浏览器驱动安装
代码中使用的是 Edge 浏览器的 webdriver
,你需要根据自己使用的 Edge 浏览器版本下载对应的 EdgeDriver
,并将其放置在系统的环境变量可访问的路径下,或者在代码中指定其具体路径。
4. 运行代码
在完成上述准备工作后,就可以运行代码了。在命令行或者你的 Python 开发环境中,执行代码所在的脚本文件(假设文件名为 ticket_booking.py
),可以通过以下命令:
python ticket_booking.py
代码将会按照我们设定的流程自动登录 12306 网站,输入行程信息,查询并尝试抢购指定车次的车票。
五、注意事项
1. 合法性问题
虽然这段代码是为了方便大家抢购车票,但需要注意的是,在使用自动化工具操作 12306 网站时,要确保遵守相关的法律法规和网站的使用规定。过度频繁地使用自动化工具可能会被视为违规行为,导致账号受限等后果。
2. 验证码处理
代码中对于验证码的处理是通过手动输入的方式(driver.find_element(By.ID, 'code').send_keys(int(input('请输入验证码:')))
),在实际运行过程中,你需要及时关注验证码的出现并准确输入,否则可能会影响抢票的顺利进行。
3. 网络和服务器状况
抢票的成功与否还很大程度上取决于网络状况以及 12306 服务器的负载情况。即使代码正常运行,在高峰期也可能因为网络拥堵或者服务器繁忙而无法成功抢到车票。
希望通过这篇博客文章教程,大家能够对这段 12306 抢票助手代码有更清晰的理解,并能在合法合规的前提下,利用它来提高自己抢到心仪车票的几率。祝大家出行顺利!
请注意,在实际使用时,请务必遵守 12306 的相关规定以及法律法规,不要滥用抢票工具造成不必要的麻烦。