2019.5.25,今天用selenium+chromedriver做了一个12306抢票小爬虫,总共100+行代码,写的真费劲,看来还是没学到家,话不多说,首先看一下README:
12306抢票功能:
通过手动登录,手动填写出发地,目的地,出发日期,然后自动完成抢票
程序流程:
- 1、首先进入登录界面(logging_page),然后等待用户登录。
- 2、在登录成功页面处“购买”中找到“单程”,执行点击事件,进入余票查询页面。
- 3、等待用户在网页中手动输入出发地,目的地,出发日期,然后判断“查询”按钮是否可以点击,若可以,执行点击事件,否则等待。
- 4、执行“查询”按钮后,等待页面显示车次信息,找到对应的车次,判断有无票,有,则找到“预定”按钮,执行点击事件。
- 5、进入选择乘客信息页面,找到对应乘客的CheckBox,执行点击事件。然后找到“提交订单”按钮,执行点击事件。
- 6、出现确认信息页面,找到“确认”按钮,执行点击事件。
- 7、完成抢票。
代码里也写了很清楚的注释了,上代码:


1 # Author:K 2 from selenium import webdriver 3 from selenium.webdriver.support.ui import WebDriverWait 4 from selenium.webdriver.support import expected_conditions as EC 5 from selenium.webdriver.common.by import By 6 7 class TicketGrabbing(object): 8 def __init__(self): 9 self.driver = webdriver.Chrome(executable_path = 'D:\ChromeDriver\chromedriver.exe') 10 self.login_url = 'https://kyfw.12306.cn/otn/login/init' # 这个不行'https://kyfw.12306.cn/otn/resources/login.html' 11 self.index_url = 'https://kyfw.12306.cn/otn/view/index.html' 12 self.order_url = 'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc' 13 self.commit_url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc' 14 15 16 def run(self): 17 self._login() 18 self._order_ticket() 19 20 21 def _wait_input(self): 22 self.from_station = input('请输入出发地:') 23 self.to_station = input('请输入目的地:') 24 self.date = input('请输入出发日期(格式为yyyy-mm-dd):') 25 self.trains = input('请输入车次(多个车次用英文逗号隔开):').split(',') 26 self.passengers = input('请输入乘客(多个乘客用英文逗号隔开):').split(',') 27 # 等待出发地输入 28 WebDriverWait(self.driver,300).until( 29 # 因为此标签'input'是单标签,所以要用text_to_be_present_in_element_value, 30 # 如果是双标签的话就用text_to_be_present_in_element 31 EC.text_to_be_present_in_element_value((By.ID,'fromStationText'),self.from_station) 32 ) 33 # 等待目的地输入 34 WebDriverWait(self.driver, 300).until( 35 EC.text_to_be_present_in_element_value((By.ID, 'toStationText'), self.to_station) 36 ) 37 # 等待出发日期输入 38 WebDriverWait(self.driver, 300).until( 39 EC.text_to_be_present_in_element_value((By.ID, 'train_date'), self.date) 40 ) 41 # 等待查询按钮是否可用 42 WebDriverWait(self.driver,300).until( 43 EC.element_to_be_clickable((By.ID,'query_ticket')) 44 ) 45 46 47 48 def _login(self): 49 self.driver.get(self.login_url) 50 # 登录成功后,等待页面跳转至首页 51 WebDriverWait(self.driver,300).until( 52 EC.url_to_be(self.index_url) 53 ) 54 print('登录成功!') 55 # 等待是否到达订票页面 56 WebDriverWait(self.driver,300).until( 57 EC.url_to_be(self.order_url) 58 ) 59 60 61 def _order_ticket(self): 62 self._wait_input() 63 query_button = self.driver.find_element_by_id('query_ticket') 64 query_button.click() 65 # 等待车次信息出现 66 WebDriverWait(self.driver,300).until( 67 EC.presence_of_element_located((By.XPATH,'.//tbody[@id="queryLeftTable"]/tr')) 68 ) 69 # 获取车次信息 70 tr_list = self.driver.find_elements_by_xpath('.//tbody[@id="queryLeftTable"]/tr[not(@datatran)]') 71 # print(tr_list) # 测试 72 for tr in tr_list: 73 train_number = tr.find_element_by_class_name('number').text 74 if train_number in self.trains: 75 tickets_left = tr.find_element_by_xpath('./td[4]').text 76 if tickets_left == '有' or tickets_left.isdigit: 77 # print(train_number,tickets_left) # 测试 78 # print('='*30) # 测试 79 book_button = tr.find_element_by_class_name('btn72') 80 book_button.click() 81 # 等待页面是否跳转到提交订单页面,并且出现乘客信息 82 WebDriverWait(self.driver,300).until( 83 EC.presence_of_element_located((By.XPATH,'.//ul[@id="normal_passenger_id"]/li')) 84 ) 85 # 找到所有乘客信息 86 li_list = self.driver.find_elements_by_xpath('.//ul[@id="normal_passenger_id"]/li') 87 for li in li_list: 88 if li.text in self.passengers: 89 print(li.text) 90 # 找到乘客对应的CheckBox,并执行点击事件 91 check_box = li.find_element_by_class_name('check') 92 check_box.click() 93 # 找到提交订单按钮,并执行点击事件 94 commit_button = self.driver.find_element_by_id('submitOrder_id') 95 commit_button.click() 96 # 等待确认订单弹窗出现 97 WebDriverWait(self.driver,300).until( 98 EC.presence_of_element_located((By.CLASS_NAME,'dhtmlx_wins_body_outer')) 99 ) 100 # 等待确认按钮加载 101 WebDriverWait(self.driver, 300).until( 102 EC.presence_of_element_located((By.ID, 'qr_submit_id')) 103 ) 104 # 找到确认按钮,并执行点击事件 105 confirm_button = self.driver.find_element_by_id('qr_submit_id') 106 confirm_button.click() 107 # 因为确认按钮可能会未被点击,所以用一个while循环点击,若正确点击了确认按钮,则调出while循环 108 while confirm_button: 109 confirm_button.click() 110 confirm_button = self.driver.find_element_by_id('qr_submit_id') 111 # 打开一个新的窗口,并将driver转换成新的窗口 112 self.driver.execute_script('window.open("%s")' % self.order_url) 113 self.driver.switch_to.window(self.driver.window_handles[1]) 114 # 再次等待车次信息出现 115 WebDriverWait(self.driver, 300).until( 116 EC.presence_of_element_located((By.XPATH, './/tbody[@id="queryLeftTable"]/tr')) 117 ) 118 119 120 if __name__ == '__main__': 121 spider = TicketGrabbing() 122 spider.run()
测试的时候用的4G网,感觉用4G网更快一些,不知道是不是错觉。。。。
好了,这个小案例的功能还有待完善,欢迎补充!