class Ticket(object): def __init__(self, config_file): ## config parser setting self.config_file = config_file self.settings = configparser.ConfigParser() self.settings._interpolation = configparser.ExtendedInterpolation() self.settings.read(self.config_file,'utf-8') ## environment setting self.brower='chrome' self.b = Browser(driver_name=self.brower) self.station={} self.url = "https://kyfw.12306.cn/otn/leftTicket/init" # 席别类型(对应列标号) self.ticket_index = [ '', u'商务座', u'特等座', u'一等座', u'二等座', u'高级软卧', u'软卧', u'硬卧', u'软座', u'硬座', u'无座' ] self.username = '' self.password = '' self.date_format='%Y-%m-%d' self.tolerance = -1 self.blacklist = {} self.date = [] self.isStudent = False self.success = 0 self.find_ticket = 0 self.config_parser() self.playmusic = False self.count = 0 def ConfigSectionMap(self,section): dict1 = {} options = self.settings.options(section) for option in options: try: dict1[option] = self.settings.get(section, option) if dict1[option] == -1: DebugPrint("skip: %s" % option) except: print("exception on %s!" % option) dict1[option] = None return dict1 def daterange(self, start_date, end_date): for n in range(int ((end_date - start_date).days) + 1): yield start_date + timedelta(n) def config_parser(self): if self.retrieve_station_dict() == -1: sys.exit() if self.retrieve_book_options() == -1: sys.exit() def retrieve_station_dict(self): dict_helper=self.ConfigSectionMap('STATIONCOOKIE') for name, value in dict_helper.iteritems(): self.station[name]=value def retrieve_book_options(self): login_info=self.ConfigSectionMap('GLOBAL') self.username = login_info['username'].strip() self.password = login_info['password'].strip() self.brower = login_info['browser'] book_settings = self.ConfigSectionMap('TICKET') self.fromStation = [ station.strip() for station in book_settings['from_station'].split(',')] self.toStation = [ station.strip() for station in book_settings['to_station'].split(',')] trains = [ train.strip() for train in book_settings['trains'].split(',')] if len(trains) == 1 and trains[0] == '': self.trains = [] else: self.trains = trains self.ticket_type =[ _type.strip() for _type in book_settings['ticket_type'].split(',')] rangeQuery = book_settings['range_query'].strip() if rangeQuery == 'Y': date = [ d.strip() for d in book_settings['date'].split(',')] if len(date) < 2: print "未设置正确的起至时间" return -1 else: start_date = datetime.strptime(date[0],self.date_format) end_date = datetime.strptime(date[1],self.date_format) if end_date < start_date: print "查询截止日期不可大于开始日期!" return -1 for single_date in self.daterange(start_date, end_date): self.date.append(single_date.strftime(self.date_format)) else: self.date = [ d.strip() for d in book_settings['date'].split(',')] if book_settings['student'].strip() == 'Y': self.isStudent = True self.tolerance = int(book_settings['tolerance']) self.people = [ people.strip() for people in book_settings['people'].split(',') ] if book_settings['alarm'].strip() == 'Y': self.playmusic = True def login(self): self.b.visit(self.url) self.b.find_by_text(u"登录").click() self.b.fill("loginUserDTO.user_name",self.username) self.b.fill("userDTO.password",self.password) pdb.set_trace() def page_has_loaded(self): page_state = self.b.evaluate_script("document.readyState") return page_state == 'complete' def switch_to_order_page(self): order = [] while len(order) == 0: order = self.b.find_by_text(u"车票预订") order[0].click() def checkTicket(self, date, fromStation, toStation): print 'date: %s, from %s, to %s'%(date, fromStation, toStation) self.b.cookies.add({"_jc_save_fromDate":date}) self.b.cookies.add({"_jc_save_fromStation":self.station[fromStation]}) self.b.cookies.add({"_jc_save_toStation":self.station[toStation]}) self.b.cookies.all() self.b.reload() if self.isStudent: self.b.find_by_text(u'学生').click() self.b.find_by_text(u"查询").click() all_trains = [] while self.page_has_loaded() == False: continue while len(all_trains) == 0: all_trains = self.b.find_by_id('queryLeftTable').find_by_tag('tr') for k, train in enumerate(all_trains): tds = train.find_by_tag('td') if tds and len(tds) >= 10: has_ticket= tds.last.find_by_tag('a') if len(has_ticket) != 0: if k + 1 < len(all_trains): this_train = all_trains[k+1]['datatran'] if len(self.trains) != 0 and this_train not in self.trains: continue if self.tolerance != -1 and this_train in self.blacklist and self.blacklist[this_train] >= self.tolerance: print u"%s 失败 %d 次, 跳过"%(this_train, self.blacklist[this_train]) continue for cat in self.ticket_type: if cat in self.ticket_index: i = self.ticket_index.index(cat) else: print '无效的席别信息' return 0, '' if tds[i].text != u'无' and tds[i].text != '--': if tds[i].text != u'有': print u'%s 的 %s 有余票 %s 张!'%(this_train, cat ,tds[i].text) else: print u'%s 的 %s 有余票若干张!'%(this_train, cat) self.find_ticket = 1 tds.last.click() break if self.find_ticket: break return this_train def book(self): while self.page_has_loaded() == False: continue if len(self.people) == 0: print '没有选择乘车人!' return 1 more = [] while len(more) == 0: more = self.b.find_by_text(u"更多") more[0].click() person = [] people = self.people while len(person) == 0: person=self.b.find_by_xpath('//ul[@id="normal_passenger_id"]/li/label[contains(text(),"%s")]'%people[0]) for p in people: self.b.find_by_xpath('//ul[@id="normal_passenger_id"]/li/label[contains(text(),"%s")]'%p).click() if self.b.find_by_xpath('//div[@id="dialog_xsertcj"]').visible: self.b.find_by_xpath('//div[@id="dialog_xsertcj"]/div/div/div/a[text()="确认"]').click() return 1 def ring(self): pygame.mixer.pre_init(64000, -16, 2, 4096) pygame.init() pygame.display.init() screen=pygame.display.set_mode([300,300]) #pygame.display.flip() pygame.time.delay(1000)#等待1秒让mixer完成初始化 tracker=pygame.mixer.music.load("media/sound.ogg") #track = pygame.mixer.music.load("sound.ogg") pygame.mixer.music.play() # while pygame.mixer.music.get_busy(): #pygame.time.Clock().tick(10) running = True img=pygame.image.load("media/img.jpg") while running: screen.blit(img,(0,0)) pygame.display.flip() for event in pygame.event.get(): if event.type==pygame.QUIT: running = False pygame.quit () return 1 def executor(self): self.login() self.switch_to_order_page() while self.success == 0: self.find_ticket = 0 while self.find_ticket == 0: for date in self.date: try: self.count += 1 print "Try %d times" % self.count for fromStation in self.fromStation: for toStation in self.toStation: this_train = self.checkTicket(date, fromStation, toStation) if self.find_ticket: break if self.find_ticket: break if self.find_ticket: break except KeyboardInterrupt: self.b.find_by_text(u'退出').click() sys.exit() except: continue # book ticket for target people self.find_ticket = 0 while self.find_ticket == 0: try: self.find_ticket = self.book() except KeyboardInterrupt: self.b.find_by_text(u'退出').click() sys.exit() except: continue if self.playmusic: self.ring() print "订票成功了吗?(Y/N)" input_var = '' while input_var == '': input_var= sys.stdin.read(1) if input_var == 'Y' or input_var == 'y': self.success = 1 elif input_var == 'N' or input_var == 'n': if this_train in self.blacklist: self.blacklist[this_train] += 1 else: self.blacklist[this_train] = 1 print u"%s 失败 %d 次"%(this_train, self.blacklist[this_train]) self.b.back() self.b.reload() else: input_var = '' continue self.b.find_by_text(u'退出').click()
class GetInfo(): conn = '' browser = '' def __init__(self, browser, conn=None, to_sql=None): # 数据库存储初始化 表名称、登陆用户名 self.exportSql = to_sql if browser: self.browser = browser self.conn = conn else: try: self.browser = Browser("chrome", headless=False) self.browser.driver.set_window_size(1600, 1000) except Exception as e: self.browser = None # 登陆 def login(self, info): # 账号,密码, account = info.get('account') password = info.get('password') if self.browser.url == 'https://17dz.com/manage/index.html': if account == self.loginName(): return '登陆成功' self.browser.visit('https://17dz.com/home/login.html') # 校验是否为空 if not all([account, password]): return jsonify(errmsg='参数不全') with self.browser.get_iframe('loginIframe') as iframe: iframe.find_by_css('input[id="id__0"]').first.fill(account) iframe.find_by_css('input[id="id__1"]').first.fill(password) iframe.find_by_text('登录').first.click() time.sleep(2) if self.browser.url == 'https://17dz.com/manage/index.html': return '登陆成功' else: return '账号和密码不匹配,请重新输入' def loginName(self): js = '''getloginName=function(){ $.ajax({ type:'GET', url: 'https://17dz.com/xqy-portal-web/manage/login/getLoginSession?_=1544003601263', contentType:'application/json;charset=utf-8', success: function (result) { if(result.success) { top.Id = result; } else { top.Id = result; } } }) }''' self.browser.evaluate_script(js) self.browser.evaluate_script('getloginName()') i = 1 loginName = '' while True: if self.browser.evaluate_script("top.Id"): loginName = self.browser.evaluate_script('top.Id').get( 'body').get('loginName') break elif i > 5: break else: time.sleep(0.5) i += 1 pass self.browser.evaluate_script('top.Id=""') return loginName # 登陆成功后获取账套列表 def getAllzt(self): # self.browser.find_by_text('凭证查看').first.click() import datetime d = datetime.datetime.now() period = datetime.date(d.year - (d.month == 1), d.month - 1 or 12, 1).strftime('%Y') js = '''getCustomerId=function(){ var data = {customerName:"", pageNo:1 , pageSize:"500" , searchType:"ALL"} $.ajax({ type:'POST', url: 'https://17dz.com/xqy-portal-web/manage/customer/queryCustomers', contentType:'application/json;charset=utf-8', data : JSON.stringify(data), success: function (result) { if(result.success) { top.customerId = result; } else { top.customerId = result; } } }) } ''' new_js = '''getCustomerId=function(period){ var data = {"pageNo":1, "pageSize":"500", "period":period, "customerNoOrNameLike":"", "accountCloseStatus":"", "sortField":"", "sortDirection":false } $.ajax({ type:'POST', url: 'https://17dz.com/xqy-portal-web/manage/finance/queryCustomer', contentType:'application/json;charset=utf-8', data : JSON.stringify(data), success: function (result) { if(result.success) { top.customerId = result; } else { top.customerId = result; } } }) }''' self.browser.evaluate_script(new_js) self.browser.evaluate_script('getCustomerId("%s")' % period) i = 1 Id = [] while True: if self.browser.evaluate_script("top.customerId"): Id = self.browser.evaluate_script( 'top.customerId')['body']['list'] break elif i > 5: break else: time.sleep(0.5) i += 1 pass self.browser.evaluate_script('top.customerId=""') customerId = Id[0]['customerId'] js2 = '''getAllzt=function(customerId){ var data = {key: "", customerId: customerId} $.ajax({ type:'POST', url: 'https://17dz.com/xqy-portal-web/manage/workbench/getAccountCustomers', contentType:'application/json;charset=utf-8', data : JSON.stringify(data), success: function (result) { if(result.success) { top.zt_data = result; } else { top.zt_data = result; } } }) }''' self.browser.evaluate_script(js2) self.browser.evaluate_script('getAllzt("%s")' % customerId) i = 1 ztData = {} while True: if self.browser.evaluate_script("top.zt_data"): ztData = self.browser.evaluate_script('top.zt_data').get( 'body', '') break elif i > 5: break else: time.sleep(0.5) i += 1 pass self.browser.evaluate_script('top.zt_data=""') return ztData # 切换账套,得到账套的起始和结束日期 def switchZt(self, params): customerId = params['customerId'] accountSetId = params['accountSetId'] customerName = params['customerName'] customerShortName = params['customerShortName'] # getKhxx('127059881','4320800','上海路卡服装有限公司','上海路卡服装有限公司') js = '''getKhxx=function(customerId,accountSetId,customerName,customerShortName){ $.ajax({ type:'PUT', url:'https://17dz.com/xqy-portal-web/finance/account/session/accountSet', data : {customerId:customerId,accountSetId:accountSetId,customerName:customerName,customerShortName:customerShortName,platform:'yqdz'}, dataType: 'json', success: function (result) { if(result.success) { top.khxx = result; } else { top.khxx = result; } } }) }''' self.browser.evaluate_script(js) self.browser.evaluate_script( 'getKhxx("%s","%s","%s","%s")' % (customerId, accountSetId, customerName, customerShortName)) i = 1 khxx = {} while True: if self.browser.evaluate_script("top.khxx"): khxx = self.browser.evaluate_script('top.khxx') break elif i > 5: break else: time.sleep(0.5) i += 1 pass self.browser.evaluate_script('top.khxx=""') try: startQj = khxx.get('body').get('createPeriod') endQj = khxx.get('body').get('lastPeriod') except Exception as e: return '网络异常,请稍后重试' dateStart = datetime.datetime.strptime(startQj, '%Y%m') dateEnd = datetime.datetime.strptime(endQj, '%Y%m') dates = [] dates.append(dateStart.strftime('%Y%m')) while dateStart <= dateEnd: dateStart += datetime.timedelta(weeks=4) dates.append(dateStart.strftime('%Y%m')) datesList = sorted(list(set(dates))) return datesList # 凭证 def voucher(self, QjList, ztID, infoname): js = '''get_Voucher=function(kjqj_date){ var data = {"beginPeriod":kjqj_date, "endPeriod":kjqj_date, "titleCode":"", "beginNumber":"", "endNumber":"", "beginMoney":"", "endMoney":"", "summary":"", "pageSize":"1000", "pageNo":0 } $.ajax({ type: "POST", url: 'https://17dz.com/xqy-portal-web/finance/accDocs/list', contentType:'application/json;charset=utf-8', data: JSON.stringify(data), success: function (result) { if(result.success) { top.voucher_data = result; } else { top.voucher_data = result; } } }) } ''' self.browser.evaluate_script(js) #创建数据库的infonameID infonameID = self.exportSql.init_infoname(infoname).id try: for Qj in QjList: self.browser.evaluate_script('get_Voucher("%s")' % Qj) i = 1 voucher_data = {} while True: if self.browser.evaluate_script("top.voucher_data"): data = self.browser.evaluate_script('top.voucher_data') if data: voucher_data = data.get('body') break elif i > 5: break else: time.sleep(0.5) i += 1 pass self.browser.evaluate_script('top.voucher_data=""') voucherString = json.dumps(voucher_data) # 保存到数据库 self.exportSql.insert_new(ztID, Qj, infonameID, voucherString) except Exception as e: msg = '凭证导出失败:{}'.format(str(e)) else: msg = '凭证导出成功' return msg # 科目余额表 def kmsheet( self, QjList, ztID, infoname, ): # 创建数据库的infonameID infonameID = self.exportSql.init_infoname(infoname).id try: for Qj in QjList: #获取科目余额 km_data = self.getKMBody(Qj) '''第一版 # #获取数量金额式 # slje_data = self.getKMBody(Qj,"B,S") # #获取外币金额式 # wbje_data = self.getKMBody(Qj,"B,W") # li = {} # li['kmye'] = km_data # li['slje'] = slje_data # li['wbje'] = wbje_data''' # 保存到数据库 kmString = json.dumps(km_data) self.exportSql.insert_new(ztID, Qj, infonameID, kmString) except Exception as e: msg = '科目余额导出失败:{}'.format(str(e)) else: msg = '科目余额导出成功' return msg def getKMBody(self, Qj): js = '''getKMBody=function(kjqj_date){ var data = { "beginPeriod":kjqj_date, "endPeriod":kjqj_date, "beginTitleCode":"", "endTitleCode":"", "pageNo":0, "pageSize":5000, "showYearAccumulated":true, "assistantId":"", "assistantType":"", "showAssistant":true, "titleLevel":6, "showEndBalance0":true, "showQuantity":false, "fcurCode":"" } $.ajax({ type: "POST", url: 'https://17dz.com/xqy-portal-web/finance/accountBalanceSheet/query', contentType:'application/json;charset=utf-8', data: JSON.stringify(data), success: function (result) { if(result.success) { top.KMBody = result; } else { top.KMBody = result; } } }) } ''' self.browser.evaluate_script(js) # 获取科目余额 self.browser.evaluate_script('getKMBody("%s")' % Qj) data_km = {} i = 1 while True: if self.browser.evaluate_script("top.KMBody"): data_km = self.browser.evaluate_script('top.KMBody')['body'] break elif i > 5: break else: time.sleep(0.5) i += 1 pass self.browser.evaluate_script('top.KMBody=""') if Qj == "201601": print(data_km) return data_km # 辅助核算余额表 说明: def fzhssheet(self, QjList, company): js = '''getFzhssheet=function(kjqj_date){ var data = { "assistantType":"c", "beginCode":"", "endCode":"", "beginPeriod":kjqj_date, "endPeriod":kjqj_date, "assistantId":"", "bwsTypeList":"B", "level":"6", "showEmptyBalance":false, "firstAccountTitle":false, "accumulated":true } $.ajax({ type: "POST", url: 'https://17dz.com/xqy-portal-web/finance/assistantBalanceBook/list', contentType:'application/json;charset=utf-8', data: JSON.stringify(data), success: function (result) { if(result.success) { top.fzhs_data = result; } else { top.fzhs_data = result; } } }) }''' self.browser.evaluate_script(js) fzhs_dict = {} for Qj in QjList: self.browser.evaluate_script('getFzhssheet("%s")' % Qj) i = 1 while True: if self.browser.evaluate_script("top.fzhs_data"): fzhsye = self.browser.evaluate_script( 'top.fzhs_data')['body'] break elif i > 5: break else: time.sleep(0.5) i += 1 pass self.browser.evaluate_script('top.fzhs_data=""') slje = self.getFZBody(Qj, "s", "B,S") wbje = self.getFZBody(Qj, "w", "B,W") li = {} li['fzhsye'] = fzhsye li['slje'] = slje li['wbje'] = wbje fzhs_dict[str(Qj)] = li if not fzhs_dict: return '获取辅助核算余额表失败' # 保存到数据库 try: self.exportSql.update_fzsheet(company, fzhs_dict) except Exception as e: return '辅助核算余额表保存失败:%s' % e return '辅助核算余额表导出成功' def getFZBody(self, Qj, balanceType, bwsTypeList): js = '''getFZBody=function(kjqj_date,balanceType,bwsTypeList){ var data = {"beginPeriod":"201811", "endPeriod":"201811", "beginCode":"", "endCode":"", "assistantType":"c", "assistantId":"", "balanceType":balanceType, "ifCondition":false, "bwsTypeList":bwsTypeList, "firstAccountTitle":false, "showEmptyBalance":false, "level":"6", "accumulated":true } $.ajax({ type: "POST", url: 'https://17dz.com/xqy-portal-web/finance/assistantBalanceBook/list', contentType:'application/json;charset=utf-8', data: JSON.stringify(data), success: function (result) { if(result.success) { top.FZBody = result; } else { top.FZBody = result; } } }) }''' self.browser.evaluate_script(js) # 获取科目余额 self.browser.evaluate_script('getFZBody("%s","%s","%s")' % (Qj, balanceType, bwsTypeList)) i = 1 km_data = {} while True: if self.browser.evaluate_script("top.FZBody"): km_data = self.browser.evaluate_script('top.FZBody')['body'] break elif i > 5: break else: time.sleep(0.5) i += 1 pass self.browser.evaluate_script('top.FZBody=""') return km_data #现金流量 def xjll(self, QjList, ztID, infoname): jd_js = '''xjll=function(url){ $.ajax({ type:'GET', url: url, success: function (result) { if(result.success) { top.xjll_data = result; } else { top.xjll_data = result; } } }) }''' # self.browser.evaluate_script(xjll_js) self.browser.evaluate_script('window.open("about:blank")') self.browser.windows.current = self.browser.windows[1] #获取起始季度 jd_url = 'https://17dz.com/xqy-portal-web/finance/cashFlowInitial/queryInitialPeriod?_=1547174631618' self.browser.visit(jd_url) jd_jsonStr = self.browser.find_by_tag('pre').first.text init_jd = json.loads(jd_jsonStr) #月报 # 创建数据库的infonameID Y_infonameID = self.exportSql.init_infoname(infoname + '-月报').id try: for Qj in QjList: time.sleep(0.5) y_url = 'https://17dz.com/xqy-portal-web/finance/cashFlowSheet?accountPeriod={}&sheetType=2&_=1543301545878'.format( Qj) self.browser.visit(y_url) Y_jsonStr = self.browser.find_by_tag('pre').first.text #月报存库 self.exportSql.insert_new(ztID, Qj, Y_infonameID, Y_jsonStr) except Exception as e: msg = '现金流量月报导出失败:{}'.format(str(e)) else: msg = '现金流量月报导出成功' #季报 # 创建数据库的infonameID J_infonameID = self.exportSql.init_infoname(infoname + '-季报').id try: for Qj in QjList: year = Qj[:4] if Qj[4:] in ['01', '02', '03']: jd = '1' elif Qj[4:] in ['04', '05', '06']: jd = '2' elif Qj[4:] in ['07', '08', '09']: jd = '3' elif Qj[4:] in ['10', '11', '12']: jd = '4' time.sleep(0.5) j_url = 'https://17dz.com/xqy-portal-web/finance/cashFlowSheet/quarterlyReport?year={}&season={}&_=1543301545880'.format( year, jd) self.browser.visit(j_url) J_jsonStr = self.browser.find_by_tag('pre').first.text qj = '%s-%s' % (year, jd) # 季报存库 self.exportSql.insert_new(ztID, qj, J_infonameID, J_jsonStr) except Exception as e: msg = '现金流量季报导出失败:{}'.format(str(e)) else: msg = '现金流量季报导出成功' self.browser.windows.current.close() self.browser.windows.current = self.browser.windows[0] return msg # 基础设置 def settings(self, customerId, ztID, accountSetId, QjList, infoname): set_js = '''getSettings=function(url){ $.ajax({ type:'GET', url: url, success: function (result) { if(result.success) { top.load_data = result; } else { top.load_data = result; } } }) }''' self.browser.evaluate_script(set_js) #科目 # 创建数据库的infonameID kmID = self.exportSql.init_infoname(infoname + '-科目').id km_dict = {} # 获取资产,负债,权益,成本,损益对应的编码 code_url = 'https://17dz.com/xqy-portal-web/finance/accountTitle/types?systemAccountId=1&_=1542955356592' AllCodes = self.get_settings(code_url).get('body', []) for i in AllCodes: code = i['code'] name = i['name'] km_url = 'https://17dz.com/xqy-portal-web/finance/customerAccountTitles/' \ 'listByType?customerId={}&subjectType={}&_=1542955356593'.format(customerId,code) res = self.get_settings(km_url) km_dict[name] = res #辅助核算 # 创建数据库的infonameID fzID = self.exportSql.init_infoname(infoname + '-辅助核算').id fz_dict = {} Base_url = 'https://17dz.com/xqy-portal-web/finance/{}/list' \ '/page?key=&accountSetId={}&customerId={}&pageNo=0&pageSize=10000' FZ_List = ['clients', 'suppliers', 'inventories', 'projects'] for name in FZ_List: newUrl = Base_url.format(name, accountSetId, customerId) data = self.get_settings(newUrl).get('body') fz_dict[name] = data # 币别 # 创建数据库的infonameID bbID = self.exportSql.init_infoname(infoname + '-币别').id url = 'https://17dz.com/xqy-portal-web/finance/exchangeRates/all?accountPeriod={}&_=1542955356686' for Qj in QjList: newurl = url.format(Qj) B = self.get_settings(newurl) # 将币别存库 self.exportSql.insert_new(ztID, Qj, bbID, json.dumps(B)) try: # 将科目存库 self.exportSql.insert_new(ztID, '', kmID, json.dumps(km_dict)) # 辅助核算保存入库 self.exportSql.insert_new(ztID, '', fzID, json.dumps(fz_dict)) except Exception as e: return '基础设置导出成功保存失败:{}'.format(str(e)) return '基础设置导出成功' def get_settings(self, url): try: self.browser.evaluate_script('getSettings("%s")' % url) except Exception as e: print(e) i = 1 settings_data = {} while True: if self.browser.evaluate_script("top.load_data"): settings_data = self.browser.evaluate_script('top.load_data') break elif i > 5: break else: time.sleep(0.5) i += 1 pass self.browser.evaluate_script('top.load_data=""') return settings_data #获取现金流量 def get_xjll(self, url): try: self.browser.evaluate_script('xjll("%s")' % url) time.sleep(5.5) except Exception as e: print(e) i = 1 xjll_data = {} while True: if self.browser.evaluate_script("top.xjll_data"): xjll_data = self.browser.evaluate_script('top.xjll_data') break elif i > 5: break else: time.sleep(0.5) i += 1 pass self.browser.evaluate_script('top.xjll_data=""') return xjll_data
browser = Browser('chrome', **executable_path) #browser = Browser('chrome') #Login browser.visit('https://kyfw.12306.cn/otn/login/init') loginBtn = browser.find_by_id('loginSub') browser.fill('loginUserDTO.user_name', 'username') browser.fill('userDTO.password', 'password') loginBtn.click() #Search ticket #browser.visit('https://kyfw.12306.cn/otn/leftTicket/init') time.sleep(4) browser.find_by_xpath('//li[@id="selectYuding"]/a').click() browser.evaluate_script( 'document.getElementById("fromStation").setAttribute("type","visiable")') browser.evaluate_script( 'document.getElementById("toStation").setAttribute("type","visiable")') browser.evaluate_script('document.getElementById("train_date").readOnly=false') browser.fill('leftTicketDTO.from_station', 'TJP') browser.fill('leftTicketDTO.to_station', 'MHL') browser.fill('leftTicketDTO.train_date', '2017-11-30') browser.evaluate_script( 'document.getElementsByClassName("cal-wrap")[0].style.display="none"') #browser.find_by_text('查询').click() time.sleep(2) browser.find_by_text('查询').click() #browser.reload() #browser.find_by_text('预订')[3].click() time.sleep(2)
class Ticket(object): def __init__(self, config_file): ## config parser setting self.config_file = config_file self.settings = configparser.ConfigParser() self.settings._interpolation = configparser.ExtendedInterpolation() self.settings.read(self.config_file) ## environment setting self.brower='chrome' self.b = Browser(driver_name=self.brower) self.station={} self.url = "https://kyfw.12306.cn/otn/leftTicket/init" # 席别类型(对应列标号) self.ticket_index = [ '', u'商务座', u'特等座', u'一等座', u'二等座', u'高级软卧', u'软卧', u'硬卧', u'软座', u'硬座', u'无座' ] self.username = '' self.password = '' self.date_format='%Y-%m-%d' self.tolerance = -1 self.blacklist = {} self.date = [] self.isStudent = False self.success = 0 self.find_ticket = 0 self.config_parser() self.playmusic = False self.count = 0 def ConfigSectionMap(self,section): dict1 = {} options = self.settings.options(section) for option in options: try: dict1[option] = self.settings.get(section, option) if dict1[option] == -1: DebugPrint("skip: %s" % option) except: print("exception on %s!" % option) dict1[option] = None return dict1 def daterange(self, start_date, end_date): for n in range(int ((end_date - start_date).days) + 1): yield start_date + timedelta(n) def config_parser(self): if self.retrieve_station_dict() == -1: sys.exit() if self.retrieve_book_options() == -1: sys.exit() def retrieve_station_dict(self): dict_helper=self.ConfigSectionMap('STATIONCOOKIE') for name, value in dict_helper.iteritems(): self.station[name]=value def retrieve_book_options(self): login_info=self.ConfigSectionMap('GLOBAL') self.username = login_info['username'].strip() self.password = login_info['password'].strip() self.brower = login_info['browser'] book_settings = self.ConfigSectionMap('TICKET') self.fromStation = [ station.strip() for station in book_settings['from_station'].split(',')] self.toStation = [ station.strip() for station in book_settings['to_station'].split(',')] trains = [ train.strip() for train in book_settings['trains'].split(',')] if len(trains) == 1 and trains[0] == '': self.trains = [] else: self.trains = trains self.ticket_type =[ _type.strip() for _type in book_settings['ticket_type'].split(',')] rangeQuery = book_settings['range_query'].strip() if rangeQuery == 'Y': date = [ d.strip() for d in book_settings['date'].split(',')] if len(date) < 2: print "未设置正确的起至时间" return -1 else: start_date = datetime.strptime(date[0],self.date_format) end_date = datetime.strptime(date[1],self.date_format) if end_date < start_date: print "查询截止日期不可大于开始日期!" return -1 for single_date in self.daterange(start_date, end_date): self.date.append(single_date.strftime(self.date_format)) else: self.date = [ d.strip() for d in book_settings['date'].split(',')] if book_settings['student'].strip() == 'Y': self.isStudent = True self.tolerance = int(book_settings['tolerance']) self.people = [ people.strip() for people in book_settings['people'].split(',') ] if book_settings['alarm'].strip() == 'Y': self.playmusic = True def login(self): self.b.visit(self.url) self.b.find_by_text(u"登录").click() self.b.fill("loginUserDTO.user_name",self.username) self.b.fill("userDTO.password",self.password) pdb.set_trace() def page_has_loaded(self): page_state = self.b.evaluate_script("document.readyState") return page_state == 'complete' def switch_to_order_page(self): order = [] while len(order) == 0: order = self.b.find_by_text(u"车票预订") order[0].click() def checkTicket(self, date, fromStation, toStation): print 'date: %s, from %s, to %s'%(date, fromStation, toStation) self.b.cookies.add({"_jc_save_fromDate":date}) self.b.cookies.add({"_jc_save_fromStation":self.station[fromStation]}) self.b.cookies.add({"_jc_save_toStation":self.station[toStation]}) self.b.cookies.all() self.b.reload() if self.isStudent: self.b.find_by_text(u'学生').click() self.b.find_by_text(u"查询").click() all_trains = [] while self.page_has_loaded() == False: continue while len(all_trains) == 0: all_trains = self.b.find_by_id('queryLeftTable').find_by_tag('tr') for k, train in enumerate(all_trains): tds = train.find_by_tag('td') if tds and len(tds) >= 10: has_ticket= tds.last.find_by_tag('a') if len(has_ticket) != 0: if k + 1 < len(all_trains): this_train = all_trains[k+1]['datatran'] if len(self.trains) != 0 and this_train not in self.trains: continue if self.tolerance != -1 and this_train in self.blacklist and self.blacklist[this_train] >= self.tolerance: print u"%s 失败 %d 次, 跳过"%(this_train, self.blacklist[this_train]) continue for cat in self.ticket_type: if cat in self.ticket_index: i = self.ticket_index.index(cat) else: print '无效的席别信息' return 0, '' if tds[i].text != u'无' and tds[i].text != '--': if tds[i].text != u'有': print u'%s 的 %s 有余票 %s 张!'%(this_train, cat ,tds[i].text) else: print u'%s 的 %s 有余票若干张!'%(this_train, cat) self.find_ticket = 1 tds.last.click() break if self.find_ticket: break return this_train def book(self): while self.page_has_loaded() == False: continue if len(self.people) == 0: print '没有选择乘车人!' return 1 more = [] while len(more) == 0: more = self.b.find_by_text(u"更多") more[0].click() person = [] people = self.people while len(person) == 0: person=self.b.find_by_xpath('//ul[@id="normal_passenger_id"]/li/label[contains(text(),"%s")]'%people[0]) for p in people: self.b.find_by_xpath('//ul[@id="normal_passenger_id"]/li/label[contains(text(),"%s")]'%p).click() if self.b.find_by_xpath('//div[@id="dialog_xsertcj"]').visible: self.b.find_by_xpath('//div[@id="dialog_xsertcj"]/div/div/div/a[text()="确认"]').click() return 1 def ring(self): pygame.mixer.pre_init(64000, -16, 2, 4096) pygame.init() pygame.display.init() screen=pygame.display.set_mode([300,300]) #pygame.display.flip() pygame.time.delay(1000)#等待1秒让mixer完成初始化 tracker=pygame.mixer.music.load("media/sound.ogg") #track = pygame.mixer.music.load("sound.ogg") pygame.mixer.music.play() # while pygame.mixer.music.get_busy(): #pygame.time.Clock().tick(10) running = True img=pygame.image.load("media/img.jpg") while running: screen.blit(img,(0,0)) pygame.display.flip() for event in pygame.event.get(): if event.type==pygame.QUIT: running = False pygame.quit () return 1 def executor(self): self.login() self.switch_to_order_page() while self.success == 0: self.find_ticket = 0 while self.find_ticket == 0: for date in self.date: try: self.count += 1 print "Try %d times" % self.count for fromStation in self.fromStation: for toStation in self.toStation: this_train = self.checkTicket(date, fromStation, toStation) if self.find_ticket: break if self.find_ticket: break if self.find_ticket: break except KeyboardInterrupt: self.b.find_by_text(u'退出').click() sys.exit() except: continue # book ticket for target people self.find_ticket = 0 while self.find_ticket == 0: try: self.find_ticket = self.book() except KeyboardInterrupt: self.b.find_by_text(u'退出').click() sys.exit() except: continue if self.playmusic: self.ring() print "订票成功了吗?(Y/N)" input_var = '' while input_var == '': input_var= sys.stdin.read(1) if input_var == 'Y' or input_var == 'y': self.success = 1 elif input_var == 'N' or input_var == 'n': if this_train in self.blacklist: self.blacklist[this_train] += 1 else: self.blacklist[this_train] = 1 print u"%s 失败 %d 次"%(this_train, self.blacklist[this_train]) self.b.back() self.b.reload() else: input_var = '' continue self.b.find_by_text(u'退出').click()
class halfAutoGetTicket(): def __init__(self): self.driver_name = 'chrome' self.executable_path = '/usr/local/lib/python3.6/chromedriver' # # self.driver = webdriver.Chrome(executable_path='/usr/local/lib/python3.6/chromedriver') # self.driver.implicitly_wait(10) self.driver = Browser(driver_name=self.driver_name, executable_path=self.executable_path) self.driver.driver.set_window_size(1400, 1000) self.username = '******' self.passwd = 'yangmeng123' self.train_date = '2018-12-29' self.from_station = '%u90D1%u5DDE%2CZZF' self.to_station = '%u5317%u4EAC%2CBJP' self.order = 0 self.users = '' def login(self): self.driver.visit(login_url) # 填充密码 self.driver.fill("loginUserDTO.user_name", self.username) # sleep(1) self.driver.fill("userDTO.password", self.passwd) print(u"等待验证码,自行输入...") while True: if self.driver.url != initmy_url: print('--------') sleep(1) else: print('+++++++++') break def getTickets(self): # self.driver=Browser(driver_name=self.driver_name,executable_path=self.executable_path) # self.driver.driver.set_window_size(1400, 1000) # self.driver.visit("file:///Users/iyunshu/Desktop/1111.htm") # soup = BeautifulSoup(tempHtml, 'html.parser') html = self.driver.html #获取网页的html数据 soup = BeautifulSoup(html, 'html.parser') table = soup.find(id="queryLeftTable") while len(table.findAll('tr')) == 0: html = self.driver.html #获取网页的html数据 soup = BeautifulSoup(html, 'html.parser') # soup = BeautifulSoup(tempHtml, 'html.parser') table = soup.find(id="queryLeftTable") name = [] tickets = [] tableTitle = soup.find(id='t-list') aaa = tableTitle.table.tbody coutn = 0 for tr in aaa.findAll('tr'): ticketinfo = {} id = tr.get('id') train_id = id.split('_')[1] if len(tr.findAll('td')) == 13: id = 'train_num_%d' % coutn coutn += 1 nameTd = tr.findAll('td')[0] div1 = nameTd.find(id=id) tempsoup = BeautifulSoup(str(div1), 'html.parser') div2 = tempsoup.find_all('div', class_='train') name = div2[0].div.a.get_text() ticketinfo["车次"] = name erdengTD = tr.findAll('td')[3] yingzuoTD = tr.findAll('td')[9] erdeng = 'ZE_' + train_id if erdengTD.get('id') == erdeng: if yingzuoTD.div: ticketinfo["二等"] = erdengTD.div.get_text() else: ticketinfo["二等"] = erdengTD.get_text() yingzuo = 'YZ_' + train_id if yingzuoTD.get('id') == yingzuo: if yingzuoTD.div: ticketinfo["硬座"] = yingzuoTD.div.get_text() else: ticketinfo["硬座"] = yingzuoTD.get_text() yuedingTD = tr.findAll('td')[12].a print(yuedingTD) if ticketinfo["二等"] != '--' or ticketinfo["硬座"] != '--': if ticketinfo["二等"] != '无' or ticketinfo["硬座"] != '无': self.driver.evaluate_script(yuedingTD.onclick) tickets.append(ticketinfo) print(tickets) def start(self): self.login() self.driver.visit(ticket_url) try: print("购票页面开始...") # sleep(1) # 加载查询信息 self.driver.cookies.add( {"_jc_save_fromStation": self.from_station}) self.driver.cookies.add({"_jc_save_toStation": self.to_station}) self.driver.cookies.add({"_jc_save_fromDate": self.train_date}) self.driver.reload() count = 0 if self.order != 0: while self.driver.url == ticket_url: self.driver.find_by_text(u"查询").click() count += 1 print("循环点击查询... 第 %s 次" % count) # sleep(1) # try: # self.driver.find_by_text(u"预订")[self.order - 1].click() # except Exception as e: # print (e) # print ("还没开始预订") # continue else: while self.driver.url == ticket_url: self.driver.find_by_text(u"查询").click() count += 1 print("循环点击查询... 第 %s 次" % count) self.getTickets() # sleep(0.8) # try: # for i in self.driver.find_by_text(u"预订"): # i.click() # sleep(1) # except Exception as e: # print (e) # print ("还没开始预订 %s" %count) # continue print("开始预订...") # sleep(3) # self.driver.reload() sleep(1) print('开始选择用户...') for user in self.users: self.driver.find_by_text(user).last.click() print("提交订单...") sleep(1) # self.driver.find_by_text(self.pz).click() # self.driver.find_by_id('').select(self.pz) # # sleep(1) # self.driver.find_by_text(self.xb).click() # sleep(1) self.driver.find_by_id('submitOrder_id').click() # print u"开始选座..." # self.driver.find_by_id('1D').last.click() # self.driver.find_by_id('1F').last.click() sleep(1.5) print("确认选座...") self.driver.find_by_id('qr_submit_id').click() except Exception as e: print(e)
javascript_advanced_and_organized_code.py """ from splinter.browser import Browser browser = Browser('chrome') # Visit URL url = "http://splinter.cobrateam.info/" browser.visit(url) # 1 - Send code to webpage to be executed # you can execute a simple javascript code browser.execute_script('alert("Hello World")') # assign variable javascript_code = 'message = "After this alert, the body tag will disappear";' javascript_code += 'alert(message);' browser.execute_script(javascript_code) # you just can execute any javascript code, like, # for example, manupulate dom # javascript snippet to hidden the body browser.execute_script('document.getElementsByTagName("body")[0].style.display = "none"') # 2 - Getting data returned from javascript code execution # getting value of the 'display' attribute from the body tag value_of_display = browser.evaluate_script('document.getElementsByTagName("body")[0].style.display') browser.execute_script('alert("As you could see, the body disappeared, so the display is set as: %s");' % value_of_display) browser.execute_script('alert("..but now");') # back to the normal, that is, display:block browser.execute_script('document.getElementsByTagName("body")[0].style.display = "block"') value_of_display = browser.evaluate_script('document.getElementsByTagName("body")[0].style.display') browser.execute_script('alert("back to the normal! And display is set as: %s");' % value_of_display) # NOTE: you can use the jQuery, or any snippet of any # javascript framework, you simply include it before execute
class Tickets(): """ one object "Tickets" means one person's snatching tickets """ def __init__(self, username, pwd): """ Input your username and password to this function to create a object @para: username,pwd are str @return: None """ self.username = username self.password = pwd self.ticket_url = "https://kyfw.12306.cn/otn/leftTicket/init" self.login_page_url = "https://kyfw.12306.cn/otn/login/init" self.my_homepage_url = "https://kyfw.12306.cn/otn/index/initMy12306" self.browser = Browser( driver_name='chrome', user_agent= 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36' ) self.captcha_path = 'info/captcha.jpg' self.query_logs = [] self.passengers_list = [] def _captcha_identify(self): """ # ============================================================================= # This function will identify the captcha of 12306. # The captcha problem in this site is identifying the objects # in the given picture then clicking the ones the prompt suggests. # On the other hand, this function will get the image by relative path # 'info/captcha.jpg', identify the corresponding characters and get to # know what to find to click, and identify the eight small pictures in # the overall picture and choose the ones that are conformed to the # desired ones.Then it returns the answer, each two being a pair, meaning # the click position # ============================================================================= This function will show the users the captcha and format it and return the answer. @return: str """ answer = '' pos_dict = { 1: "36,47,", 2: "110,43,", 3: "182,45,", 4: "260,44,", 5: "36,115,", 6: "115,113,", 7: "184,113,", 8: "264,113," } with PIL.Image.open(self.captcha_path) as img: print('Please input the numbers of the pictures in the captcha ' + 'you want to choose\n(number ranges in [1~8] ' + 'and please separate them with " "):') img.show() numbers = input() for number in numbers.split(' '): answer += pos_dict[int(number)] return answer[:-1] def log_in(self): """ This function helps you log in your account in "kyfw.12306.cn", it is based on the private functions below: (1)_captcha_identify (2)_get_passengers @return: bool, showing whether it succeeds """ self.browser.visit(self.login_page_url) s = requests.session() headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36' } captcha_page = '' #deal with captcha-check while ('4' not in captcha_page): s.cookies.clear_session_cookies() captcha_get_url = "https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand&0.9670588224384102" r = s.get(captcha_get_url) with open(self.captcha_path, 'wb') as f: f.write(r.content) captcha = self._captcha_identify() captcha_data = { 'answer': captcha, 'login_site': 'E', 'rand': 'sjrand' } captcha_check_url = 'https://kyfw.12306.cn/passport/captcha/captcha-check' captcha_page = s.post(captcha_check_url, data=captcha_data, headers=headers, verify=False) captcha_page = captcha_page.text print(captcha_page) print('captcha success') #deal with username password login_data = { 'username': self.username, 'password': self.password, 'appid': 'otn' } login_url = "https://kyfw.12306.cn/passport/web/login" r = s.post(login_url, data=login_data, headers=headers, verify=False) j = json.loads(r.text) if (j["result_message"] != "登录成功"): return False #if successful, it continues to get cookies print("username and password are both right") url1 = "https://kyfw.12306.cn/otn/login/userLogin" r = s.post(url1, data={'_json_att': ''}, headers=headers, verify=False) #print(r.text) url2 = "https://kyfw.12306.cn/otn/passport?redirect=/otn/login/userLogin" r = s.get(url2, headers=headers, verify=False) #print(r.text) url3 = "https://kyfw.12306.cn/passport/web/auth/uamtk" r = s.post(url3, data={'appid': 'otn'}, headers=headers, verify=False) #print(r.text) j = json.loads(r.text) url4 = "https://kyfw.12306.cn/otn/uamauthclient" r = s.post(url4, data={'tk': j['newapptk']}, headers=headers, verify=False) #print(r.text) url5 = url1 r = s.get(url5, headers=headers, verify=False) #print(r.text) r = s.get(self.my_homepage_url, headers=headers, verify=False) #print(r.text) #submit the cookies to the chromedriver self.browser._cookie_manager.add(s.cookies) self.browser.visit(self.my_homepage_url) sleep(1) if (self.browser.url != self.my_homepage_url): raise Exception("The process of getting cookies gets wrong.") print('log in successfully') return True def reset_info(self, new_username, new_pwd): """ This function allows you to reset the information of the users. It aims to deal with the circumstances such as: (1)The user inputs the wrong information and can't log in the site (2)... @para: new_username, new_pwd are str @return: None """ #So far it is only suitable before you log in self.username = new_username self.password = new_pwd # self.query_logs = [] def _get_passengers(self): """ This function get the list of the names of the contacts of the user, and the names contain brackets and "学生" when he/her is a student @return: list(str) """ self.browser.visit("https://kyfw.12306.cn/otn/passengers/init") soup = bs(self.browser.html, "html.parser") tr_list = soup.find("tbody", id="passengerAllTable").find_all("tr") passengers_list = [] for tr in tr_list: td_list = tr.find_all("td") for i in range(len(td_list)): if (i % 8 == 1): name = str(td_list[i].string) elif (i % 8 == 5): if ("学生" in td_list[i]): name = name + "(学生)" passengers_list.append(name) return passengers_list def _query(self, from_station, to_station, date): """ This function queries the site of the information belows: where do you start? (it can be city name or station name) where is your destination? (it can be city name or station name) what date is it for you to depart? (eg. 2018-01-28) And it makes the browser, Chrome, loads the query page and returns the correspoding html of the page Note: the date format must be corrected before being the the argument, and the date should never be out of the bookable time bound. If the date is out of the bookable time bound, it will return a default page given by the site as the one when we input the out-bound date by hand. Often it's the tickets page whose date is the lower bound of the bookable bound. @para: from_station, to_station, date are str @return: str """ self.browser.visit(self.ticket_url) try: #initiate the date self.browser.cookies.add({'_jc_save_fromDate': date}) self.browser.reload() #cope with exception from the input format error from_station_abbr = getAbbr(from_station) to_station_abbr = getAbbr(to_station) if (from_station_abbr == ''): raise Exception("The from_station doesn't exist") if (to_station_abbr == ''): raise Exception("The to_station doesn't exist") #initiate the from_station self.browser.evaluate_script( 'document.getElementById("fromStation").value="' + from_station_abbr + '"') #initiate the to_station self.browser.evaluate_script( 'document.getElementById("toStation").value="' + to_station_abbr + '"') #query with clicking the button self.browser.find_link_by_text('查询').click() sleep(3) return self.browser.html # ============================================================================= # query_url = "https://kyfw.12306.cn/otn/leftTicket/query?" # + "leftTicketDTO.train_date=" + date # + "&leftTicketDTO.from_station=" + from_station_abbr # + "&leftTicketDTO.to_station=" + to_station_abbr # + "&purpose_codes=ADULT" # ============================================================================= except: print("Error. The browser will quit soon.") self.browser.screenshot(name='error_of_fun_query') self.browser.quit() raise def _prettify_html(self, html): ''' This function get the information of the train out of the html @para: html is str @return: list(dict()), attention: it's [{}] when no thing is found, and the structure of dict() is as follows: tickets_dict = { 'trainNumber':'', 'fromStation':'', 'toStation':'', 'departTime':'', 'arriveTime':'', 'period':'', 'specialSeat':'', 'oneClassSeat':'', 'twoClassSeat':'', 'advancedSoftSleeper':'', 'softSleeper':'', 'hardSleeper':'', 'motionSleeper':'', 'softSeat':'', 'hardSeat':'', 'noSeat':'', 'bookable':False, 'book_btn':None #if it's unbookable, it'll be None } ''' if (html == ''): return [{}] tickets_list = [] book_btn_list = self.browser.find_link_by_text('预订') book_btn_list_ptr = 0 soup = bs(html, 'html.parser') tr_list = soup.find('tbody', id='queryLeftTable').find_all('tr') #there are no tickets at all if (tr_list == []): return [{}] for tr in tr_list: td_table = tr.find_all('td') #when <tr> has <td> if (td_table != []): tickets_dict = { 'trainNumber': '', 'fromStation': '', 'toStation': '', 'departTime': '', 'arriveTime': '', 'period': '', 'specialSeat': '', 'oneClassSeat': '', 'twoClassSeat': '', 'advancedSoftSleeper': '', 'softSleeper': '', 'hardSleeper': '', 'motionSleeper': '', 'softSeat': '', 'hardSeat': '', 'noSeat': '', 'bookable': False, 'book_btn': None #if it's unbookable, it'll be None } #update the tickets_dict #the first <td> info_list = [td for td in td_table[0].strings] if (' ' in info_list): info_list.remove(' ') info_list.remove('查看票价') del info_list[len(info_list) - 1] #delete "当/次日到达" tickets_dict['trainNumber'] = info_list[0] tickets_dict['fromStation'] = info_list[1] tickets_dict['toStation'] = info_list[2] tickets_dict['departTime'] = info_list[3] tickets_dict['arriveTime'] = info_list[4] tickets_dict['period'] = info_list[5] #the following <td>s except the last one tickets_dict['specialSeat'] = td_table[1].string tickets_dict['oneClassSeat'] = td_table[2].string tickets_dict['twoClassSeat'] = td_table[3].string tickets_dict['advancedSoftSleeper'] = td_table[4].string tickets_dict['softSleeper'] = td_table[5].string tickets_dict['hardSleeper'] = td_table[6].string tickets_dict['motionSleeper'] = td_table[7].string tickets_dict['softSeat'] = td_table[8].string tickets_dict['hardSeat'] = td_table[9].string tickets_dict['noSeat'] = td_table[10].string if (td_table[12].find('a') != None): tickets_dict['bookable'] = True tickets_dict['book_btn'] = book_btn_list[book_btn_list_ptr] book_btn_list_ptr = book_btn_list_ptr + 1 else: tickets_dict['bookable'] = False tickets_dict['book_btn'] = None tickets_list.append(tickets_dict) del tickets_dict return tickets_list def _book(self, button, passengers_list): """ This function will book the ticket which the button belongs to for the passengers in the passengers_list. If it succeeds, it returns True @para: button is <splinter.driver.webdriver.WebDriverElement> and passengers_list is list(str) @return: bool """ try: button.click() #book_url = "https://kyfw.12306.cn/otn/confirmPassenger/initDc" #if (self.browser.url != book_url): # raise Exception("The button fails.") #we have entered the booking page #and we click all the passengers for passenger in passengers_list: #we click the last according to the structure of the webpage print(passenger) #print(self.browser.html) while (self.browser.is_element_not_present_by_text(passenger)): pass self.browser.find_by_text(passenger).last.click() #consider the case where the passenger is a student #and a window will alert, we need to cope with it if ("学生" in passenger): self.browser.find_by_id("dialog_xsertcj_ok").last.click() self.browser.find_link_by_text("提交订单").first.click() #cope with window alert again while (self.browser.is_element_not_visible_by_xpath( '//*[@id="qr_submit_id"]')): pass self.browser.find_by_id("qr_submit_id").first.click() # ============================================================================= # success_url_text = "https://kyfw.12306.cn/otn//payOrder/init" # if (success_url_text in self.browser.url): # print("book the ticket(s) successfully!") # return True # else: # raise Exception("Browser fails to load into the paying page.") # ============================================================================= print("book the ticket(s) successfully!") return True except: print("Exception is raised in the booking process.") self.browser.screenshot(name="error_of_fun_book") raise return False def get_tickets_info(self, from_station, to_station, date, is_future=False): """ This function is based on the private function: (1)_query (2)_prettify_html This function will log what the user query and the parameter date is able to be out of bookable time bound with only one day, so we set a new boolean parameter is_future to show whether the date is out of the bookable time bound @para: from_station,to_station,date are str, is_future is bool @return: list(dict()) """ d = datetime.datetime(int(date.split('-')[0]), int(date.split('-')[1]), int(date.split('-')[2])) #information goes into the query_logs self.query_logs.append({ 'from_station': from_station, 'to_station': to_station, 'date': date, 'is_future': is_future, 'query_time': str(d.today()) }) if (is_future): #we get the date minus one day d -= datetime.timedelta(days=1) date = str(d).split(' ')[0] html = self._query(from_station, to_station, date) tickets_list = self._prettify_html(html) #remember to set all tickets unbookable if it's in future if (is_future): for ticket in tickets_list: ticket['bookable'] = False ticket['book_btn'] = None return tickets_list def book_tickets_on_sale(self, tickets_dict, date, passengers_list): """ This function is based on the private function below: (1)_book This function aims to book the tickets that are in the BOOKABLE time bound, which means that the page for the tickets is shown on the site. If the tickets are not on sale or sold out, then we repeat reloading the page and let this function watch over the page until the it finds the tickets available again, so when someone else refunds the tickets we can book the tickets at once. And if the tickets have remainders, we can book it at once, too. @para: tickets_dict is dict, passengers_list is list(str),date is str the structure of the dict is as follows: tickets_dict = { 'trainNumber':'', 'fromStation':'', 'toStation':'', 'departTime':'', 'arriveTime':'', 'period':'', 'specialSeat':'', 'oneClassSeat':'', 'twoClassSeat':'', 'advancedSoftSleeper':'', 'softSleeper':'', 'hardSleeper':'', 'motionSleeper':'', 'softSeat':'', 'hardSeat':'', 'noSeat':'', 'bookable':False, 'book_btn':None #if it's unbookable, it'll be None } @return: bool, showing whether it succeeds booking the tickets """ if (tickets_dict["bookable"] == True): #now it has remainders self._book(tickets_dict["book_btn"], passengers_list) return True else: #it is sold out now, we query again to see whether it's available html = self._query(tickets_dict["fromStation"], tickets_dict["toStation"], date) tickets_list = self._prettify_html(html) trial_times = 0 while (True): #only when it's available we break out of the loop #every loop means one times to query book_btn = None trial_times += 1 print(str(trial_times) + "th tries.") for ticket in tickets_list: if (ticket["trainNumber"] == tickets_dict["trainNumber"] and ticket["departTime"] == tickets_dict["departTime"] and ticket["bookable"] == True): book_btn = ticket["book_btn"] break #if we find it bookable if (book_btn != None): self._book(book_btn, passengers_list) break #else we query again, but before query we need to sleep sleep(3) self.browser.find_link_by_text("查询").first.click() sleep(1) tickets_list = self._prettify_html(self.browser.html) return True def book_tickets_in_future(self, tickets_dict, date, passegers_list, hour=8, minute=0): """ This function is based on the private function below: (1)_book (2)book_tickets_on_sale This function aims to book the tickets that are in the UNBOOKABLE time bound, and the date only exceeds the bound by one day. So we calculate the duration between now and the time user wants us to begin snatching (tomorrow hour:minute:00 we will wake up and start checking and snatching), and we let it sleep until the time is up. Then we query the site to see whether the tickets are offered. And if they're offered, we can use the private function (2)book_tickets_on_sale to get the tickets! @para: tickets_dict is dict, passengers_list is list(str),date is str hour and minute are int the structure of the dict is as follows: tickets_dict = { 'trainNumber':'', 'fromStation':'', 'toStation':'', 'departTime':'', 'arriveTime':'', 'period':'', 'specialSeat':'', 'oneClassSeat':'', 'twoClassSeat':'', 'advancedSoftSleeper':'', 'softSleeper':'', 'hardSleeper':'', 'motionSleeper':'', 'softSeat':'', 'hardSeat':'', 'noSeat':'', 'bookable':False, 'book_btn':None #if it's unbookable, it'll be None } @return: bool, showing whether it succeeds booking the tickets """ #wait until the tickets are available snatch_time = datetime.datetime(int(date.split('-')[0]), int(date.split('-')[1]), int(date.split('-')[2]), hour, minute, 0) #the duration between now and the snatch-time(default tomorrow 8:00) duration = snatch_time - snatch_time.today() sleep(int(duration.total_seconds()) + 1) #time seems to be up #then we need to check whether the tickets are available date_in_Chinese_format = (date.split('-')[1] + '月' + date.split('-')[2] + '日') trial_times = 0 while (True): html = self._query(tickets_dict['fromStation'], tickets_dict['toStation'], date) trial_times += 1 print(str(trial_times) + 'th tries.') soup = bs(html, 'html.parser') if (date_in_Chinese_format in str(soup.find('div', id="sear-result"))): print("The tickets page is available now! we'll buy it now!") break sleep(5) #after 5s we check again #since the tickets are available, we can buy it self.book_tickets_on_sale(tickets_dict, date, passegers_list) return True def __del__(self): """ Remember to quit the browser @return: None """ self.browser.quit()
class Scrapy12306(): def __init__(self): config = ConfigParser.ConfigParser() config.readfp(codecs.open("12306.conf", "r", "utf-8")) self.url = config.get("config","url") self.username = config.get("config","username") self.password = config.get("config","password") self.bType = config.get("config","browser") #self._from = config.get("config","_from") #self._to = config.get("config","_to") self._from = u'北京' self._to = u'邯郸' self.date = config.get("config","date") print "browser :%s url:%s" % (self.bType,self.url) self.browser = Browser(self.bType) self.browser.visit(self.url) def login(self): if self.username=="" or self.password=="": print "error:username and password must not be empty" self.browser.quit() sys.exit(-1) self.browser.fill("loginUserDTO.user_name",self.username) self.browser.fill("userDTO.password",self.password) time.sleep(10) self.browser.find_by_id("loginSub").click() loginFlag = self.browser.find_by_id("link_4_myTicket") return not loginFlag.is_empty() def getTicket(self): self.browser.find_by_xpath("//a[@href='/otn/leftTicket/init']")[0].click() #self.browser.fill("leftTicketDTO.from_station_name",self._from) #self.browser.fill("leftTicketDTO.to_station_name",self._to) self.browser.cookies.add({"_jc_save_fromStation":"%u5317%u4EAC%2CBJP"}) self.browser.cookies.add({'_jc_save_toStation':'%u90AF%u90F8%2CHDP'}) #self.browser.fill("leftTicketDTO.train_date",self.date) self.browser.cookies.add({"_jc_save_fromDate":self.date}) isload = False while not isload: self.browser.reload() isload = self.browser.is_element_present_by_id("query_ticket",wait_time=10) if not isload: time.sleep(30) continue qt = self.browser.find_by_id("query_ticket") qt.click() print self.browser.cookies.all() flag = False while not flag: try: stations = self.browser.find_by_text(u"预订") station = [] for i in range(11,21): station = stations[i] flag =station.has_class("btn72") if flag: break if not flag: qt = self.browser.find_by_id("query_ticket").click() time.sleep(2) continue station.click() time.sleep(1) except Exception as e: print e.message flag = False p1 = self.browser.find_by_xpath("//label[@for='normalPassenger_0']") p2 = self.browser.find_by_xpath("//label[@for='normalPassenger_3']") print 'p1,p2:%s %s' % (p1,p2) if p1.is_empty(): p1 = self.browser.find_by_id("normalPassenger_0")[0].click() else : p1[0].click() if p2.is_empty(): p2 = self.browser.find_by_id("normalPassenger_3")[0].click() else : p2[0].click() self.browser.evaluate_script("confirm('抢到票了帅哥,订票吗')") time.sleep(15) self.browser.find_by_id("submitOrder_id").click()