一、關於瀏覽器分辨率有關的截圖git
二、關於瀏覽器位置點擊(分辨率)web
三、注意當前時間的 請求 URL 的cookie 值!!ajax
一、首先分析12306 登陸界面chrome
二、將頁面截取爲圖片json
三、取得圖片的位置 經過 先打開圖片Image.open(), crop(左,上,右,下)-->用.save('文件名')存此圖片瀏覽器
四、使用超級鷹下載的示例模塊(記得傳入9004)服務器
五、超級鷹的結果用循環點擊(此處顯式等待 每0.5s檢查一次,設定時間)cookie
ActionChains(driver) 使用動做鏈操做鼠標去移動點擊,執行curl
六、登陸成功--驗證成功函數
七、移動到查詢頁面
八、去查 ajax出來的 copy 將其url 打開 (工具網站:https://curl.trillworks.com/)能夠看到cookie值,通常此操做和日期有關若是當前時間已經沒有車次,會致使過時!
必定要及時修改
九、找到中文對應的英文連接
(js)的URL!!
作一箇中文英文互相轉換的模塊
十、分析ajax的 url打開的數據 在這裏面能夠經過 選取字典索引值找到 這裏是js格式 因此使用 json.loads( 返回.text)[' 索引']
十一、分析裏面要取的數據 的位置 經過遍歷選取
十二、是否 有票!大坑!!! 記得索引位置,有部分車次的索引位置徹底相反!!!我暈,暫時沒想到怎麼搞
1三、isdigit()函數判斷其中有數字或特殊符號則爲ture! 有用
1 class API_URL(object): 2 3 # 下載驗證碼的URL 4 GET_YZM_URL = "https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand&" 5 # 校驗驗證碼的URL(post) 6 CHECK_YZM_URL = "https://kyfw.12306.cn/passport/captcha/captcha-check" 7 # 登陸首頁的URL get 8 Login_URL_1 = "https://kyfw.12306.cn/otn/login/init" 9 Login_URL_2 = "https://kyfw.12306.cn/otn/login/init#" 10 # 車票站點查詢的URL 11 SELECT_URL = "https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9150"
1 headers = { 2 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36' 3 } 4 cookies = { 5 '_uab_collina': '159401687279425123588472', 6 'JSESSIONID': '15006E403A3D220629819AD7CBBDC853', 7 'tk': 'GeK-NUkoQ0CpE04s8roM0QwonK0LuKPFBGo4CQubs1s0', 8 'BIGipServerotn': '619708938.50210.0000', 9 'RAIL_EXPIRATION': '1594209286751', 10 'RAIL_DEVICEID': 'XFErASnds56Lfkayxga7TQCa8eqhX3uplkHzXHt27hvD9IXlmSarYXr_dNF2LHYODwopchRRbJVaDwgVmxySz91dqk0_u2RqSsUyobeiBCBaSOyM-3V8R1V4U8pRsbNOlewj8vgv5A1pHtWi-zvUXq0kfvQdEdO1', 11 'BIGipServerpool_passport': '216859146.50215.0000', 12 'route': '9036359bb8a8a461c164a04f8f50b252', 13 'ten_key': '1gJOinE9bHcaIId53q5LyxGn2Y/Z4ERq', 14 'ten_js_key': '1gJOinE9bHcaIId53q5LyxGn2Y%2FZ4ERq', 15 '_jc_save_toDate': '2020-07-06', 16 '_jc_save_wfdc_flag': 'dc', 17 'current_captcha_type': 'Z', 18 '_jc_save_fromStation': '%u5317%u4EAC%2CBJP', 19 '_jc_save_toStation': '%u4E0A%u6D77%2CSHH', 20 'uKey': '1963dac98c2756cd1312380545a9b8cefb73be533c5ed6aca3704252393a480f', 21 '_jc_save_fromDate': '2020-07-15', 22 }
1 # 登陸模塊 2 def login(self): 3 4 5 # IP : port 6 proxy = '110.243.16.20 : 9999' 7 8 # 設置代理IP 9 chrome_options = webdriver.ChromeOptions() 10 # 代理服務器n 11 chrome_options.add_argument('--proxy-server = %s'%proxy) 12 13 14 driver = webdriver.Chrome(chrome_options=chrome_options) 15 # 請求 16 driver.get(API_URL.Login_URL_1) 17 18 driver.maximize_window() 19 time.sleep(2) 20 21 driver.find_element_by_xpath('//*[@id="username"]').send_keys(self.user_name) 22 time.sleep(2) 23 driver.find_element_by_xpath('//*[@id="password"]').send_keys(self.password) 24 time.sleep(2) 25 26 # 思路!截屏獲取驗證碼 27 28 # 獲取圖片所在位置 29 copy_img = driver.find_element_by_xpath('//*[@id="loginForm"]/div/ul[2]/li[4]/div/div/div[3]/img') 30 # 圖片的左上角位置 31 location = copy_img.location 32 print(location) 33 size = copy_img.size 34 print(size) 35 time.sleep(2) 36 # 要截取的座標大小 !!!!重坑警告!!! 在這裏困很久 打開的默認瀏覽器分辨率毫無問題 37 # 可是可是!!其實須要 *1.50 才能正確取到驗證碼截圖 38 location_code=(int(location['x']*1.50), int(location['y']*1.50), int(location['x']+size['width'])*1.50, int(location['y']+size['height'])*1.50) 39 print(location_code) 40 # 定位完後截屏 41 driver.save_screenshot("screen.png") 42 i = Image.open("screen.png") 43 44 # 在此要元組類型 (left, upper, right, lower)-tuple 45 # (左上右下) 46 ver_code_img = i.crop(location_code) 47 ver_code_img.save("驗證碼.png") 48 # 自動識別 49 result_cjy = user_cjy("驗證碼.png") 50 print(result_cjy) 51 52 result_cjy = result_cjy.get('pic_str').split('|') 53 # 遍歷 列表['247,67', '105,138']將其取出 全部都用 , 分隔 54 points = [[int(number) for number in numbers.split(',')] for numbers in result_cjy] 55 print(points) # 此處獲取到二維列表!!! 56 57 for point in points: 58 # 顯示等待,定位圖片對象 59 element = WebDriverWait(driver, 20).until( 60 EC.presence_of_element_located((By.CLASS_NAME, "touclick-image"))) 61 # 模擬點擊 !!!!此處模擬點擊又有 坑 由於剛剛放大截取1.5 因此這裏縮小點擊0.6 62 ActionChains(driver).move_to_element_with_offset(element,point[0]*0.66,point[1]*0.66).click().perform() # perform(發送進行執行) 63 time.sleep(2) 64 time.sleep(5) 65 driver.find_element_by_xpath('//*[@id="loginSub"]').click() 66 time.sleep(5) 67 if driver.current_url not in [API_URL.Login_URL_1,API_URL.Login_URL_2]: 68 print("登陸成功!") 69 else: 70 print("登陸失敗,請重試!")
1 # 查詢火車餘票模塊 2 def select(self): 3 # 請求站點轉換 js 4 req = requests.get(API_URL.SELECT_URL) 5 6 self.station_data = req.text.lstrip("var station_names ='").rstrip("'").split('@') 7 # print(self.station_data) 8 9 time_now = input("請輸入日期(格式:2020-07-06):") 10 from_station = self.get_station(input("請輸入出發地:")) 11 to_station = self.get_station(input("請輸入目的地:")) 12 # 注意 必定要知道什麼站到什麼站是由車次的 若是搜尋過程當中沒有對應車 是報錯 13 url = "https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date={}&leftTicketDTO.from_station={}&leftTicketDTO.to_station={}&purpose_codes=ADULT".format(time_now,from_station,to_station) 14 print(url) 15 16 req_2 = requests.get(url,headers=headers,cookies=cookies) 17 req_2.encoding='utf-8' 18 # print(req_2.text) 19 20 result = json.loads(req_2.text)['data']['result'] 21 # print(result) 22 23 # 是否有座?? 此處的第一個元素 我取尋找 請求的url 中的位置每一個位置不一樣!!大坑!! 24 data_seats = [(32,'商務座'),(31,'一等座'),(30,'二等座'),(29,'高級軟臥'),(28,'一等臥'),(27,'動臥'),(26,'二等臥'),(25,'軟座'),(24,'硬座'),(23,'無座')] 25 for item in result: 26 item = item.split("|") 27 dict_item = { 28 '編號':item[2], '車次':item[3], '出發地':self.get_station_CN(item[4]), '目的地':self.get_station_CN(item[5]), '出發站':self.get_station_CN(item[6]), '終點站':self.get_station_CN(item[7]), '出發時間':item[8], '抵達時間':item[9], '總耗時': str(int(item[10][:item[10].index(':')]))+'小時'+str(int(item[10][item[10].index(':')+1:]))+'分鐘', 29 '商務座': "", 30 '一等座': "", 31 '二等座': "", 32 '高級軟臥': "", 33 '一等臥': "", 34 '動臥': "", 35 '二等臥': "", 36 '軟座': "", 37 '硬座': "", 38 '無座': "" 39 } 40 for index in range(10): 41 # 42 if item[data_seats[index][0]] == '有' or item[data_seats[index][0]].isdigit(): # isdigit()函數判斷其中有數字或特殊符號則爲ture 43 dict_item[data_seats[index][1]]=item[data_seats[index][0]] 44 else: 45 del dict_item[data_seats[index][1]] 46 47 print(dict_item)
1 # 車站的英文縮寫函數!(中文轉英文) 2 def get_station(self, city): 3 for item in self.station_data: 4 if city in item: 5 return item.split('|')[2] 6 7 # 車站的中文縮寫函數! 8 def get_station_CN(self, city_CN): 9 for item in self.station_data: 10 if city_CN in item: 11 return item.split('|')[1]
1 def __init__(self, user_name, password): 2 self.user_name = user_name 3 self.password = password 4 self.station_data = ''
1 if __name__ == '__main__': 2 # username = input("請輸入用戶名:") 3 # password = input("請輸入密碼:") 4 user = UserPass("username", "password") 5 # user.login() 6 user.select()