Selenium之模擬登錄鐵路12306的示例代碼
最近接觸了一些selenium模塊的相關(guān)知識,覺得還挺有意思的,于是決定親自嘗試寫一些爬蟲程序來強(qiáng)化selenium模塊(一定要多嘗試、多動手、多總結(jié))。本文主要使用python爬蟲來模擬登錄鐵路12306官網(wǎng)。這兒得吐槽一句,鐵路12306網(wǎng)站的反爬機(jī)制做的還是比較好。
話不多說,下面跟小墨一起來學(xué)習(xí)如何通過爬蟲來實(shí)現(xiàn)鐵路12306的登錄。
一、 驗(yàn)證碼破解
當(dāng)我們輸入賬號和密碼后,在點(diǎn)擊登錄按鈕之前,還需要對驗(yàn)證碼進(jìn)行操作。對驗(yàn)證碼的識別,已經(jīng)有相關(guān)的處理平臺,我們只需要借助第三方平臺即可。
1.注冊并登錄超級鷹賬號:點(diǎn)擊鏈接進(jìn)行注冊https://www.chaojiying.com/user/login/;
2.點(diǎn)擊購買題分,并進(jìn)行充值;
3.點(diǎn)擊軟件id,創(chuàng)建一個軟件Id(程序中會用到);
4.下載示例代碼(開發(fā)文檔—>選擇相應(yīng)的語言–>下載示例demo),python示例代碼如下所示:
class Chaojiying_Client(object): def __init__(self, username, password, soft_id): self.username = username password = password.encode('utf8') self.password = md5(password).hexdigest() self.soft_id = soft_id self.base_params = { 'user': self.username, 'pass2': self.password, 'softid': self.soft_id, } self.headers = { 'Connection': 'Keep-Alive', 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)', } def PostPic(self, im, codetype): """ im: 圖片字節(jié) codetype: 題目類型 參考 http://www.chaojiying.com/price.html """ params = { 'codetype': codetype, } params.update(self.base_params) files = {'userfile': ('ccc.jpg', im)} r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers) return r.json() def ReportError(self, im_id): """ im_id:報錯題目的圖片ID """ params = { 'id': im_id, } params.update(self.base_params) r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers) return r.json()
二、Selenium功能簡介
Selenium模塊和爬蟲之間的關(guān)聯(lián):
–便捷的獲取網(wǎng)站中的動態(tài)加載數(shù)據(jù)
–便捷實(shí)現(xiàn)模擬登錄
Selenium模塊的使用流程:
–環(huán)境安裝:pip install selenium
–下載瀏覽器的驅(qū)動程序(谷歌瀏覽器):
–下載路徑:http://chromedriver.storage.googleapis.com/index.html
– 驅(qū)動程序和瀏覽器的映射關(guān)系:映射鏈接
–將下載好的驅(qū)動程序放在當(dāng)前項(xiàng)目目錄下
Selenium模塊的相關(guān)方法:http://www.dbjr.com.cn/article/192259.htm
上述內(nèi)容完成后,我們就可以正式進(jìn)入正題了,是不是很期待,那就跟著小墨往下走吧。
三、模擬登錄
1. 進(jìn)入官網(wǎng)
#創(chuàng)建對象 #executable_path=path:下載好的驅(qū)動程序的路徑 bro = webdriver.Chrome(executable_path='chromedriver.exe') #12306的登錄網(wǎng)址 bro.get('https://kyfw.12306.cn/otn/resources/login.html') #窗口最大化 bro.maximize_window()
2、進(jìn)入登錄界面并獲取驗(yàn)證碼
#save_screenshot就是將當(dāng)前頁面進(jìn)行截圖且保存 bro.save_screenshot('aa.png') #確定驗(yàn)證碼圖片對應(yīng)的左上角和右下角的坐標(biāo)(裁剪的區(qū)域就確定) code_img_ele = bro.find_element_by_xpath('//*[@id="J-loginImg"]') location = code_img_ele.location # 驗(yàn)證碼圖片左上角的坐標(biāo) x,y #print('location:',location) size = code_img_ele.size #驗(yàn)證碼標(biāo)簽對應(yīng)的長和寬 #print('size:',size) #左上角和右下角坐標(biāo) rangle = ( int(location['x']), int(location['y']), int(location['x'] + size['width']), int(location['y'] + size['height'])) #至此驗(yàn)證碼圖片區(qū)域就確定下來了 i = Image.open('./aa.png') code_img_name = './code.png' #crop根據(jù)指定區(qū)域進(jìn)行圖片裁剪 frame = i.crop(rangle) frame.save(code_img_name) #將驗(yàn)證碼圖片提交給超級鷹進(jìn)行識別 chaojiying = Chaojiying_Client('########', '#######', '#######') #用戶賬號>>密碼>>軟件ID im = open('code.png', 'rb').read() #本地圖片文件路徑 來替換 a.jpg 有時WIN系統(tǒng)須要// id=chaojiying.PostPic(im, 9004)['pic_id'] #截取的驗(yàn)證碼照片以及驗(yàn)證碼的類別代號 result = chaojiying.PostPic(im, 9004)['pic_str'] #識別結(jié)果 all_list = [] #要存儲即將被點(diǎn)擊的點(diǎn)的坐標(biāo) [[x1,y1],[x2,y2]] #識別錯誤后,會返回題分,示例代碼并沒有這個,就是想讓你花錢 chaojiying.ReportError(id) if '|' in result: list_1 = result.split('|') print(list_1) count_1 = len(list_1) for i in range(count_1): xy_list = [] x = int(list_1[i].split(',')[0]) y = int(list_1[i].split(',')[1]) xy_list.append(x) xy_list.append(y) all_list.append(xy_list) else: x = int(result.split(',')[0]) y = int(result.split(',')[1]) xy_list = [] xy_list.append(x) xy_list.append(y) all_list.append(xy_list) #遍歷列表,使用動作鏈對每一個列表元素對應(yīng)的x,y指定的位置進(jìn)行點(diǎn)擊操作 for l in all_list: x = l[0] y = l[1] ActionChains(bro).move_to_element_with_offset(code_img_ele, x, y).click().perform() time.sleep(0.5)
這樣我們就實(shí)現(xiàn)了驗(yàn)證碼的識別操作。
3、輸入賬號和密碼,并點(diǎn)擊登錄按鈕
#輸入賬號和密碼 put1=bro.find_element_by_id('J-userName') #當(dāng)驗(yàn)證碼識別錯誤后,需要清空賬號重新輸入 put1.clear() #輸入賬號 put1.send_keys('########') time.sleep(1) put2=bro.find_element_by_id('J-password') put2.clear() #輸入密碼 put2.send_keys('##########') time.sleep(1) #點(diǎn)擊登錄按鈕 bro.find_element_by_id('J-login').click()
點(diǎn)擊登錄按鈕后,會出現(xiàn)如下圖所示的彈框
因此,我們需要定位到該提示框,并實(shí)現(xiàn)滑塊的向右滑動
4、滑塊滑動
#處理提示框 time.sleep(0.5) span=bro.find_element_by_xpath('//*[@id="nc_1_n1z"]') action = ActionChains(bro) #點(diǎn)擊長按指定的標(biāo)簽 action.click_and_hold(span).perform() action.drag_and_drop_by_offset(span,400,0).perform()
有的時候,當(dāng)滑塊移動后,會出現(xiàn)如下圖所示的情況:
因此,我們需要點(diǎn)擊刷新,并重新進(jìn)行滑塊的移動,所以對代碼做稍微的改動:
while True: try: info=bro.find_element_by_xpath('//*[@id="J-slide-passcode"]/div/span').text print(info) if info=='哎呀,出錯了,點(diǎn)擊刷新再來一次': #點(diǎn)擊刷新 bro.find_element_by_xpath('//*[@id="J-slide-passcode"]/div/span/a').click() time.sleep(0.2) #重新移動滑塊 span = bro.find_element_by_xpath('//*[@id="nc_1_n1z"]') action = ActionChains(bro) # 點(diǎn)擊長按指定的標(biāo)簽 action.click_and_hold(span).perform() action.drag_and_drop_by_offset(span, 400, 0).perform() time.sleep(7) except: print('ok!') break
至此,我們便實(shí)現(xiàn)了鐵路12306的登錄,如下圖所示
是不是覺得很簡單啊。
5、完整代碼
# -*- coding: utf-8 -*- #驗(yàn)證碼識別示例 import requests from hashlib import md5 class Chaojiying_Client(object): def __init__(self, username, password, soft_id): self.username = username password = password.encode('utf8') self.password = md5(password).hexdigest() self.soft_id = soft_id self.base_params = { 'user': self.username, 'pass2': self.password, 'softid': self.soft_id, } self.headers = { 'Connection': 'Keep-Alive', 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)', } def PostPic(self, im, codetype): """ im: 圖片字節(jié) codetype: 題目類型 參考 http://www.chaojiying.com/price.html """ params = { 'codetype': codetype, } params.update(self.base_params) files = {'userfile': ('ccc.jpg', im)} r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers) return r.json() def ReportError(self, im_id): """ im_id:報錯題目的圖片ID """ params = { 'id': im_id, } params.update(self.base_params) r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers) return r.json() #使用selenium打開登錄頁面 from selenium import webdriver import time from PIL import Image from selenium.webdriver import ActionChains from selenium.webdriver.support import expected_conditions as EC, wait #創(chuàng)建對象 #executable_path=path:下載好的驅(qū)動程序的路徑 bro = webdriver.Chrome(executable_path='chromedriver.exe') #12306的登錄網(wǎng)址 bro.get('https://kyfw.12306.cn/otn/resources/login.html') #窗口最大化 bro.maximize_window() #點(diǎn)擊賬號登錄 bro.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a').click() time.sleep(1) while True: try: #save_screenshot就是將當(dāng)前頁面進(jìn)行截圖且保存 bro.save_screenshot('aa.png') #確定驗(yàn)證碼圖片對應(yīng)的左上角和右下角的坐標(biāo)(裁剪的區(qū)域就確定) code_img_ele = bro.find_element_by_xpath('//*[@id="J-loginImg"]') location = code_img_ele.location # 驗(yàn)證碼圖片左上角的坐標(biāo) x,y #print('location:',location) size = code_img_ele.size #驗(yàn)證碼標(biāo)簽對應(yīng)的長和寬 #print('size:',size) #左上角和右下角坐標(biāo) rangle = ( int(location['x']), int(location['y']), int(location['x'] + size['width']), int(location['y'] + size['height'])) #至此驗(yàn)證碼圖片區(qū)域就確定下來了 i = Image.open('./aa.png') code_img_name = './code.png' #crop根據(jù)指定區(qū)域進(jìn)行圖片裁剪 frame = i.crop(rangle) frame.save(code_img_name) #將驗(yàn)證碼圖片提交給超級鷹進(jìn)行識別 chaojiying = Chaojiying_Client('#####', '#######', '######') #用戶賬號>>密碼>>軟件ID im = open('code.png', 'rb').read() #本地圖片文件路徑 來替換 a.jpg 有時WIN系統(tǒng)須要// id=chaojiying.PostPic(im, 9004)['pic_id'] #截取的驗(yàn)證碼照片以及驗(yàn)證碼的類別代號 result = chaojiying.PostPic(im, 9004)['pic_str'] #識別結(jié)果 all_list = [] #要存儲即將被點(diǎn)擊的點(diǎn)的坐標(biāo) [[x1,y1],[x2,y2]] #識別錯誤后,會返回題分,官網(wǎng)給的demo并沒有這一句,哈哈哈,坑吧,就是讓你多花錢 chaojiying.ReportError(id) if '|' in result: list_1 = result.split('|') print(list_1) count_1 = len(list_1) for i in range(count_1): xy_list = [] x = int(list_1[i].split(',')[0]) y = int(list_1[i].split(',')[1]) xy_list.append(x) xy_list.append(y) all_list.append(xy_list) else: x = int(result.split(',')[0]) y = int(result.split(',')[1]) xy_list = [] xy_list.append(x) xy_list.append(y) all_list.append(xy_list) #遍歷列表,使用動作鏈對每一個列表元素對應(yīng)的x,y指定的位置進(jìn)行點(diǎn)擊操作 for l in all_list: x = l[0] y = l[1] ActionChains(bro).move_to_element_with_offset(code_img_ele, x, y).click().perform() time.sleep(0.5) #輸入賬號和密碼 put1=bro.find_element_by_id('J-userName') #當(dāng)驗(yàn)證碼識別錯誤后,需要清空賬號重新輸入 put1.clear() put1.send_keys('username') #你的賬號 time.sleep(1) put2=bro.find_element_by_id('J-password') put2.clear() put2.send_keys('password') #你的密碼 time.sleep(1) bro.find_element_by_id('J-login').click() #處理提示框 time.sleep(3) span=bro.find_element_by_xpath('//*[@id="nc_1_n1z"]') action = ActionChains(bro) #點(diǎn)擊長按指定的標(biāo)簽 action.click_and_hold(span).perform() action.drag_and_drop_by_offset(span,400,0).perform() time.sleep(8) while True: try: info=bro.find_element_by_xpath('//*[@id="J-slide-passcode"]/div/span').text print(info) if info=='哎呀,出錯了,點(diǎn)擊刷新再來一次': bro.find_element_by_xpath('//*[@id="J-slide-passcode"]/div/span/a').click() time.sleep(0.2) span = bro.find_element_by_xpath('//*[@id="nc_1_n1z"]') action = ActionChains(bro) # 點(diǎn)擊長按指定的標(biāo)簽 action.click_and_hold(span).perform() action.drag_and_drop_by_offset(span, 400, 0).perform() time.sleep(7) except: print('ok!') break #釋放動作鏈 action.release() break except: time.sleep(3) time.sleep(12) #登錄成功 bro.find_element_by_link_text('確定').click() time.sleep(0.5) bro.find_element_by_link_text('首頁').click() #輸入起點(diǎn)、終點(diǎn)以及時間,查詢車票 start_city='北京' end_city='上海' date='2020-08-05' #選擇起點(diǎn) bro.find_element_by_xpath('//*[@id="fromStationText"]').click() time.sleep(2) #這只遍歷了熱門城市,要是想遍歷其他城市,自己寫一個循環(huán)就行 city_list=bro.find_elements_by_xpath('//*[@id="ul_list1"]/li') for city in city_list: if city.text==start_city: city.click() break time.sleep(2) #選擇終點(diǎn) bro.find_element_by_xpath('//*[@id="toStationText"]').click() for city in city_list: if city.text==end_city: city.click() break time.sleep(2) js = "$('input[id=train_date]').removeAttr('readonly')" bro.execute_script(js) dt=bro.find_element_by_id('train_date') dt.clear() dt.send_keys(date) time.sleep(2) bro.find_element_by_xpath('/html/body/div[3]/div[2]/div/div[1]/div/div[1]/ul/li[1]/a').click() time.sleep(0.5) bro.find_element_by_xpath('//*[@id="isStudentDan"]/i').click() time.sleep(2) bro.find_element_by_id('search_one').click() time.sleep(2)
到此這篇關(guān)于Selenium之模擬登錄鐵路12306的示例代碼的文章就介紹到這了,更多相關(guān)Selenium 模擬登錄12306內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python實(shí)現(xiàn)跨excel sheet復(fù)制代碼實(shí)例
這篇文章主要介紹了python實(shí)現(xiàn)跨excel sheet復(fù)制代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03Python數(shù)據(jù)庫編程之pymysql詳解
本文主要介紹了Python數(shù)據(jù)庫編程中pymysql,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05通過python實(shí)現(xiàn)隨機(jī)交換禮物程序詳解
這篇文章主要介紹了通過python實(shí)現(xiàn)隨機(jī)交換禮物程序詳解的,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-07-07pandas 數(shù)據(jù)類型轉(zhuǎn)換的實(shí)現(xiàn)
這篇文章主要介紹了pandas 數(shù)據(jù)類型轉(zhuǎn)換的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-126行Python代碼實(shí)現(xiàn)進(jìn)度條效果(Progress、tqdm、alive-progress
這篇文章主要介紹了6行Python代碼實(shí)現(xiàn)進(jìn)度條效果(Progress、tqdm、alive-progress和PySimpleGUI庫),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01python中elasticsearch_dsl模塊的使用方法
這篇文章主要介紹了python中elasticsearch_dsl模塊的使用方法,elasticsearch-dsl是基于elasticsearch-py封裝實(shí)現(xiàn)的,提供了更簡便的操作elasticsearch的方法2022-09-09在Python代碼中執(zhí)行Linux命令的詳細(xì)用法教程
在Python開發(fā)過程中,經(jīng)常需要執(zhí)行Linux系統(tǒng)命令來完成各種任務(wù),Python提供了多種方式來調(diào)用和執(zhí)行系統(tǒng)命令,本文將詳細(xì)介紹如何在Python代碼中執(zhí)行Linux命令,并結(jié)合實(shí)際案例來演示這些方法的使用,需要的朋友可以參考下2024-07-07