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.dhdzp.com/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抓取網(wǎng)頁數(shù)據(jù)的多種方式與示例詳解
在數(shù)據(jù)科學(xué)和網(wǎng)絡(luò)爬蟲領(lǐng)域,網(wǎng)頁數(shù)據(jù)抓取是非常重要的一項(xiàng)技能,Python 是進(jìn)行網(wǎng)頁抓取的流行語言,因?yàn)樗鼡碛袕?qiáng)大的第三方庫,能夠簡化網(wǎng)頁解析和數(shù)據(jù)提取的過程,本篇文章將介紹幾種常見的網(wǎng)頁數(shù)據(jù)抓取方法,需要的朋友可以參考下2025-04-04
Python數(shù)據(jù)類型轉(zhuǎn)換詳解
本篇文章里小編給大家整理的是關(guān)于Python中常用數(shù)據(jù)類型之間的轉(zhuǎn)換相關(guān)知識點(diǎn),有需要的朋友們可以學(xué)習(xí)下,希望能夠給你帶來幫助2021-10-10
Python中.py程序在CMD控制臺以指定虛擬環(huán)境運(yùn)行
本文主要介紹了Python中.py程序在CMD控制臺以指定虛擬環(huán)境運(yùn)行,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07

