使用selenium 和圖片驗證碼識別 對12306的模擬登陸+12306查詢車次

 首先總結坑:

一、關於瀏覽器分辨率有關的截圖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! 有用 

 

 

 

 

其中的URL:

 

 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"

 

此處headers 和cookies 本身獲取,記得加!這裏確定會失效

 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()
相關文章
相關標籤/搜索