Selenium之模擬登錄鐵路12306的示例代碼
最近接觸了一些selenium模塊的相關(guān)知識(shí),覺得還挺有意思的,于是決定親自嘗試寫一些爬蟲程序來強(qiáng)化selenium模塊(一定要多嘗試、多動(dòng)手、多總結(jié))。本文主要使用python爬蟲來模擬登錄鐵路12306官網(wǎng)。這兒得吐槽一句,鐵路12306網(wǎng)站的反爬機(jī)制做的還是比較好。
話不多說,下面跟小墨一起來學(xué)習(xí)如何通過爬蟲來實(shí)現(xiàn)鐵路12306的登錄。
一、 驗(yàn)證碼破解
當(dāng)我們輸入賬號(hào)和密碼后,在點(diǎn)擊登錄按鈕之前,還需要對(duì)驗(yàn)證碼進(jìn)行操作。對(duì)驗(yàn)證碼的識(shí)別,已經(jīng)有相關(guān)的處理平臺(tái),我們只需要借助第三方平臺(tái)即可。
1.注冊(cè)并登錄超級(jí)鷹賬號(hào):點(diǎn)擊鏈接進(jìn)行注冊(cè)https://www.chaojiying.com/user/login/;
2.點(diǎn)擊購(gòu)買題分,并進(jìn)行充值;
3.點(diǎn)擊軟件id,創(chuàng)建一個(gè)軟件Id(程序中會(huì)用到);
4.下載示例代碼(開發(fā)文檔—>選擇相應(yīng)的語(yǔ)言–>下載示例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:報(bào)錯(cuò)題目的圖片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功能簡(jiǎn)介
Selenium模塊和爬蟲之間的關(guān)聯(lián):
–便捷的獲取網(wǎng)站中的動(dòng)態(tài)加載數(shù)據(jù)
–便捷實(shí)現(xiàn)模擬登錄
Selenium模塊的使用流程:
–環(huán)境安裝:pip install selenium
–下載瀏覽器的驅(qū)動(dòng)程序(谷歌瀏覽器):
–下載路徑:http://chromedriver.storage.googleapis.com/index.html
– 驅(qū)動(dòng)程序和瀏覽器的映射關(guān)系:映射鏈接
–將下載好的驅(qū)動(dòng)程序放在當(dāng)前項(xiàng)目目錄下
Selenium模塊的相關(guān)方法:http://chabaoo.cn/article/192259.htm
上述內(nèi)容完成后,我們就可以正式進(jìn)入正題了,是不是很期待,那就跟著小墨往下走吧。
三、模擬登錄
1. 進(jìn)入官網(wǎng)
#創(chuàng)建對(duì)象 #executable_path=path:下載好的驅(qū)動(dòng)程序的路徑 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)前頁(yè)面進(jìn)行截圖且保存 bro.save_screenshot('aa.png') #確定驗(yàn)證碼圖片對(duì)應(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)簽對(duì)應(yīng)的長(zhǎ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í)鷹進(jìn)行識(shí)別 chaojiying = Chaojiying_Client('########', '#######', '#######') #用戶賬號(hào)>>密碼>>軟件ID im = open('code.png', 'rb').read() #本地圖片文件路徑 來替換 a.jpg 有時(shí)WIN系統(tǒng)須要// id=chaojiying.PostPic(im, 9004)['pic_id'] #截取的驗(yàn)證碼照片以及驗(yàn)證碼的類別代號(hào) result = chaojiying.PostPic(im, 9004)['pic_str'] #識(shí)別結(jié)果 all_list = [] #要存儲(chǔ)即將被點(diǎn)擊的點(diǎn)的坐標(biāo) [[x1,y1],[x2,y2]] #識(shí)別錯(cuò)誤后,會(huì)返回題分,示例代碼并沒有這個(gè),就是想讓你花錢 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) #遍歷列表,使用動(dòng)作鏈對(duì)每一個(gè)列表元素對(duì)應(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)證碼的識(shí)別操作。
3、輸入賬號(hào)和密碼,并點(diǎn)擊登錄按鈕
#輸入賬號(hào)和密碼 put1=bro.find_element_by_id('J-userName') #當(dāng)驗(yàn)證碼識(shí)別錯(cuò)誤后,需要清空賬號(hào)重新輸入 put1.clear() #輸入賬號(hào) 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)擊登錄按鈕后,會(huì)出現(xiàn)如下圖所示的彈框
因此,我們需要定位到該提示框,并實(shí)現(xiàn)滑塊的向右滑動(dòng)
4、滑塊滑動(dòng)
#處理提示框 time.sleep(0.5) span=bro.find_element_by_xpath('//*[@id="nc_1_n1z"]') action = ActionChains(bro) #點(diǎn)擊長(zhǎng)按指定的標(biāo)簽 action.click_and_hold(span).perform() action.drag_and_drop_by_offset(span,400,0).perform()
有的時(shí)候,當(dāng)滑塊移動(dòng)后,會(huì)出現(xiàn)如下圖所示的情況:
因此,我們需要點(diǎn)擊刷新,并重新進(jìn)行滑塊的移動(dòng),所以對(duì)代碼做稍微的改動(dòng):
while True: try: info=bro.find_element_by_xpath('//*[@id="J-slide-passcode"]/div/span').text print(info) if info=='哎呀,出錯(cuò)了,點(diǎn)擊刷新再來一次': #點(diǎn)擊刷新 bro.find_element_by_xpath('//*[@id="J-slide-passcode"]/div/span/a').click() time.sleep(0.2) #重新移動(dòng)滑塊 span = bro.find_element_by_xpath('//*[@id="nc_1_n1z"]') action = ActionChains(bro) # 點(diǎn)擊長(zhǎng)按指定的標(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的登錄,如下圖所示
是不是覺得很簡(jiǎn)單啊。
5、完整代碼
# -*- coding: utf-8 -*- #驗(yàn)證碼識(shí)別示例 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:報(bào)錯(cuò)題目的圖片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打開登錄頁(yè)面 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)建對(duì)象 #executable_path=path:下載好的驅(qū)動(dòng)程序的路徑 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)擊賬號(hào)登錄 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)前頁(yè)面進(jìn)行截圖且保存 bro.save_screenshot('aa.png') #確定驗(yàn)證碼圖片對(duì)應(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)簽對(duì)應(yīng)的長(zhǎ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í)鷹進(jìn)行識(shí)別 chaojiying = Chaojiying_Client('#####', '#######', '######') #用戶賬號(hào)>>密碼>>軟件ID im = open('code.png', 'rb').read() #本地圖片文件路徑 來替換 a.jpg 有時(shí)WIN系統(tǒng)須要// id=chaojiying.PostPic(im, 9004)['pic_id'] #截取的驗(yàn)證碼照片以及驗(yàn)證碼的類別代號(hào) result = chaojiying.PostPic(im, 9004)['pic_str'] #識(shí)別結(jié)果 all_list = [] #要存儲(chǔ)即將被點(diǎn)擊的點(diǎn)的坐標(biāo) [[x1,y1],[x2,y2]] #識(shí)別錯(cuò)誤后,會(huì)返回題分,官網(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) #遍歷列表,使用動(dòng)作鏈對(duì)每一個(gè)列表元素對(duì)應(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) #輸入賬號(hào)和密碼 put1=bro.find_element_by_id('J-userName') #當(dāng)驗(yàn)證碼識(shí)別錯(cuò)誤后,需要清空賬號(hào)重新輸入 put1.clear() put1.send_keys('username') #你的賬號(hào) 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)擊長(zhǎng)按指定的標(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=='哎呀,出錯(cuò)了,點(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)擊長(zhǎng)按指定的標(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 #釋放動(dòng)作鏈 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('首頁(yè)').click() #輸入起點(diǎn)、終點(diǎn)以及時(shí)間,查詢車票 start_city='北京' end_city='上海' date='2020-08-05' #選擇起點(diǎn) bro.find_element_by_xpath('//*[@id="fromStationText"]').click() time.sleep(2) #這只遍歷了熱門城市,要是想遍歷其他城市,自己寫一個(gè)循環(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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python實(shí)現(xiàn)跨excel sheet復(fù)制代碼實(shí)例
這篇文章主要介紹了python實(shí)現(xiàn)跨excel sheet復(fù)制代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03Python數(shù)據(jù)庫(kù)編程之pymysql詳解
本文主要介紹了Python數(shù)據(jù)庫(kù)編程中pymysql,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05通過python實(shí)現(xiàn)隨機(jī)交換禮物程序詳解
這篇文章主要介紹了通過python實(shí)現(xiàn)隨機(jī)交換禮物程序詳解的,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07pandas 數(shù)據(jù)類型轉(zhuǎn)換的實(shí)現(xiàn)
這篇文章主要介紹了pandas 數(shù)據(jù)類型轉(zhuǎn)換的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(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庫(kù)),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01python中elasticsearch_dsl模塊的使用方法
這篇文章主要介紹了python中elasticsearch_dsl模塊的使用方法,elasticsearch-dsl是基于elasticsearch-py封裝實(shí)現(xiàn)的,提供了更簡(jiǎn)便的操作elasticsearch的方法2022-09-09Pytest測(cè)試報(bào)告工具Allure的高級(jí)用法
這篇文章介紹了Pytest測(cè)試報(bào)告工具Allure的高級(jí)用法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07在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