def show_alert_info(text=None, split=' '): """ @param text 添加到打印信息头部 @param split 打印信息分隔符 打印通知警告信息 """ print_info = [] if text: print_info.append(text) # 对话框 check_el = browser.find_el_if_exist('content_checkticketinfo_id', by=By.ID) if check_el and check_el.is_displayed(): check_text = check_el.find_element_by_id('sy_ticket_num_id').text console.print(check_text, style="bold red") # 提示框 notice_el = browser.find_el_if_exist('content_transforNotice_id', by=By.ID) if notice_el and notice_el.is_displayed(): el = browser.find_el_if_exist('#orderResultInfo_id > div > span') if el: print_info.append(f'[red]{el.text}[/red]') el = find_el_if_exist(notice_el, 'p', by=By.TAG_NAME) if el: print_info.append(el.text) console.print(split.join(print_info))
def check_alert(): alert_el = browser.find_el_if_exist('content_defaultwarningAlert_id', by=By.ID) if alert_el and alert_el.is_enabled(): btn = browser.find_el_if_exist('qd_closeDefaultWarningWindowDialog_id', by=By.ID) if btn and btn.is_enabled(): btn.click()
def _try_submit(self, index, left_tr, train_name): """ 尝试提交 :param index: 表格索引 :param left_tr: 列车信息行 :param train_name: 列车车次名称 """ left_tr_id = left_tr.get_attribute('id') submit_btn = browser.find_el_if_exist('#' + left_tr_id + ' > td.no-br > a') if submit_btn: ss, es, st, et, du = _get_train_info(index) if str.startswith(left_tr_id, 'ticket_'): serial_num = left_tr_id[len('ticket_'):].split('_')[0] # 座位类型是否匹配 for seat_type in config.seat_types: if seat_type_dict[seat_type]: seat_selector = '#' + seat_type_dict[ seat_type] + '_' + serial_num seat = left_tr.find_element_by_css_selector( seat_selector) if seat: ticket_info = { "address": f"{ss} - {es}", "time": f"{st} - {et}", "duration": du, 'train': train_name } # 判断是否有余票,如果有余票就尝试提交 def try_submit(seat_el): if seat_el.text and seat_el.text is not '无' \ and seat_el.text is not '--': self._running = False ticket_info['seat_type'] = seat_type ticket_info['value'] = seat_el.text self._ticket_info = ticket_info console.print( _table_ticket_info(ticket_info)) submit_btn.click() return True return False seat_div = browser.find_el_if_exist(seat_selector + ' > div') if try_submit(seat_div if seat_div else seat): return True console.print( f":vampire: {config.from_time} - {train_name} - {seat_type}", "[red]暂无余票[/red]") else: console.print(f":vampire: {config.from_time} - {train_name}", "[red]暂无余票[/red]") return False
def has_login(): """ 判断用户是否登录 """ url = browser.current_url if url.startswith(index_page): return browser.find_el_if_exist( '#J-header-logout > a.logout') is not None if url.startswith(ticket_url): return browser.find_el_if_exist( '#J-header-logout > a:nth-child(3)') is not None return False
def _get_train_info(index): """ 获取列车信息 :param index: 表格索引 """ train_num_id = '#train_num_' + str(index) cds = train_num_id + ' > div.cds' cdz = train_num_id + ' > div.cdz' ss = browser.find_el_if_exist(cdz + ' > strong.start-s').text es = browser.find_el_if_exist(cdz + ' > strong.end-s').text st = browser.find_el_if_exist(cds + ' > strong.start-t').text et = browser.find_el_if_exist(cds + ' > strong.color999').text du = browser.find_el_if_exist(train_num_id + '> div.ls > strong').text return ss, es, st, et, du
def _init(): # 跳转到登录页 browser.get(login_page) time.sleep(1) if browser.find_el_if_exist('ERROR', by=By.ID) is not None: console.print('[red]12306请求过于频繁,请稍等重试 . . . [/red]') browser.wait_unblock() # 等待用户密码登录按钮可以点击,切换到用户密码登录 Tab wait.WebDriverWait(browser, 5).until( ec.element_to_be_clickable( (By.CLASS_NAME, 'login-hd-account'))).click() time.sleep(1)
def _create_order(self): """ 创建订单 """ time.sleep(0.5) passenger_list = browser.find_els_if_exist('#normal_passenger_id > li') # 选择乘坐人 passenger_index = 1 self._ticket_info['passengers'] = [] for passenger in config.passengers: for passenger_li in passenger_list: passenger_input = passenger_li.find_element_by_tag_name( 'input') if passenger_li.find_element_by_tag_name( 'label').text == passenger: console.print(f"选择乘坐人 [{passenger}] . . .") self._ticket_info['passengers'].append(passenger) passenger_input.click() warning_alert = browser.find_el_if_exist( 'content_defaultwarningAlert_id', by=By.ID) if warning_alert: warning_alert.find_element_by_id( 'qd_closeDefaultWarningWindowDialog_id').click() time.sleep(0.5) # 选择席座 console.print( f"开始选择席座 [{self._ticket_info['seat_type']}] . . .") seat_select = browser.find_element_by_id( f"seatType_{str(passenger_index)}") _, seat_type_value = _get_seat_type_index_value( self._ticket_info['seat_type']) if seat_type_value != 0: Select(seat_select).select_by_value( str(seat_type_value)) passenger_index += 1 time.sleep(0.5) if passenger_index == 1: console.print("未找到乘客信息 ... 提交订单失败", style="bold red") print('正在提交订单 . . .') wait.WebDriverWait(browser, 5).until( ec.element_to_be_clickable((By.ID, 'submitOrder_id'))).click() print('正在确认订单 . . .') wait.WebDriverWait(browser, 5).until( ec.element_to_be_clickable((By.ID, 'qr_submit_id'))).click() # 截取屏幕,订单信息页 print('预订成功,正在截取屏幕 . . .') time.sleep(5) browser.screenshot( f'{self.fs}_{self.ts}_{config.from_time.replace("-", "")}_{self._ticket_info["train"].lower()}.png' ) time.sleep(60)
def slider_captcha(): try_time = 1 div = browser.find_el_if_exist('nc_1_n1z', by=By.ID) while div and div.is_displayed(): if try_time > 10: console.print('滑块验证码验证失败 . . .', style='bold red') sys.exit(-1) # 动作链 action = ActionChains(browser) # 点击长按指定的标签 action.click_and_hold(div) # 处理滑动模块 for i in range(5): # perform()立即执行动作链操作 # move_by_offset(x,y):x水平方向 y竖直方向 try: action.move_by_offset(350, 0).perform() # 速度为30mm except WebDriverException: time.sleep(0.5) time.sleep(0.5) action.release() try_time += 1 div = browser.find_el_if_exist('nc_1_n1z', by=By.ID)
def _try_submit(self, train_trs): """ 尝试提交 :param train_trs: 列车车次名称 """ for train_tr in train_trs: submit_btn = find_el_if_exist(train_tr, 'td.no-br > a') ss, es, st, et, du, tn = tk.get_train_info(train_tr) if submit_btn and submit_btn: left_tr_id = train_tr.get_attribute('id') serial_num = left_tr_id[len('ticket_'):].split('_')[0] # 座位类型是否匹配 for seat_type in config.seat_types: if tk.seat_type_dict[seat_type]: seat_type_id = tk.seat_type_dict[seat_type][ "code"] + '_' + serial_num seat = train_tr.find_element_by_id(seat_type_id) if seat: ticket_info = { "address": f"{ss} - {es}", "time": f"{st} - {et}", "duration": du, 'train': tn } # 判断是否有余票,如果有余票就尝试提交 seat_text = seat.text if seat_text == '有' or re.match( "^\\d+$", seat_text): self._running = False ticket_info['seat_type'] = seat_type ticket_info['value'] = seat_text self._ticket_info = ticket_info console.print( tk.table_ticket_info(ticket_info)) submit_btn.click() return True else: console.print(f"未找到坐席类型 :[red] {seat_type} [/red]") console.print("请按照要求配置坐席类型:", ",".join(tk.seat_type_dict.keys())) sys.exit(-1) console.print( f":vampire: {config.from_time} - {tn} - {seat_type}", "[red]暂无余票[/red]") else: console.print(f":vampire: {config.from_time} - {tn}", "[red]暂无余票[/red]") return False
def _create_order(self): """ 创建订单 """ time.sleep(1) passenger_list = browser.find_els_if_exist('#normal_passenger_id > li') # 选择乘坐人 passenger_index = 1 self._ticket_info['passengers'] = [] # 检查余票数量 ticket_value = self._ticket_info['value'] surplus_ticket_number = int( ticket_value) if ticket_value != '有' else 9999 for passenger in config.passengers[:surplus_ticket_number]: for passenger_li in passenger_list: passenger_input = passenger_li.find_element_by_tag_name( 'input') if passenger_li.find_element_by_tag_name( 'label').text == passenger: console.print(f"选择乘坐人 [{passenger}] . . .") self._ticket_info['passengers'].append(passenger) passenger_input.click() warning_alert = browser.find_el_if_exist( 'content_defaultwarningAlert_id', by=By.ID) if warning_alert: warning_alert.find_element_by_id( 'qd_closeDefaultWarningWindowDialog_id').click() time.sleep(0.5) # 选择席座 console.print( f"开始选择席座 [{self._ticket_info['seat_type']}] . . .") seat_select = browser.find_element_by_id( f"seatType_{str(passenger_index)}") seat_type = tk.seat_type_dict[ self._ticket_info['seat_type']] if not seat_type: console.print(f"未找到坐席类型 :[red] {seat_type} [/red]") sys.exit(-1) seat_type_value = seat_type['value'] if seat_type_value != '0': Select(seat_select).select_by_value(seat_type_value) passenger_index += 1 time.sleep(0.5) if passenger_index == 1: console.print("未找到乘客信息 ... 无法选择乘客和坐席", style="bold red") try: print('正在提交订单 . . .') wait.WebDriverWait(browser, 10).until( ec.element_to_be_clickable((By.ID, 'submitOrder_id'))).click() time.sleep(1) # 确认提交订单 print('正在确认订单 . . .') wait.WebDriverWait(browser, 10).until( ec.element_to_be_clickable((By.ID, 'qr_submit_id'))).click() # 等待跳转到支付页面, 如果超时未跳转, 说明订单生成失败 wait.WebDriverWait(browser, 10).until( lambda driver: driver.current_url.startswith(pay_order_url)) submit_btn = browser.find_el_if_exist('qr_submit_id', by=By.ID) if not submit_btn or not submit_btn.is_displayed(): console.print(f'该车次无法提交[{self._ticket_info["train"]}]。', style="bold yellow") config.trains.remove(self._ticket_info["train"]) show_alert_info('该车次无法提交[{self._ticket_info["train"]}]。', '\n') return False except WebDriverException as e: browser.screenshot( f'{datetime.now().strftime(datetime_format_str)}-error.png') show_alert_info('提交订单失败:\n') raise e # 截取屏幕,订单信息页 print('预订成功,正在截取屏幕 . . .') browser.screenshot( f'{self.fs}_{self.ts}_{config.from_time.replace("-", "")}_{self._ticket_info["train"].lower()}.png' ) return True