1. 程式人生 > 實用技巧 >4、python+selenium實現12306模擬登入

4、python+selenium實現12306模擬登入

簡介:

這裡是利用了selenium+圖片識別驗證,來實現12306的模擬登入,中間也參考了好幾個專案,實現了這個小demo,中間也遇到了很多的坑,主要難點在於圖片識別和滑動驗證這兩個方面,圖片識別是利用超級鷹的服務進行驗證識別的,其次一個難點就是在賬戶密碼和圖片識別都過了以後的滑動驗證,因為12306網站做了反爬,利用selenium滑動時,會報錯,提示你一直重新整理,這裡也是更改了滑動框。

技術棧:

python、selenium、圖片驗證、滑動驗證

思路:

提前臥槽,12306網站的併發真的牛逼。

在模擬登入的時候,第一個難點就是圖片驗證,這裡不會底層的演算法,只能通過圖片識別平臺的api介面服務進行解密,返回驗證座標以後,通過selenium的點選動能,進行點選,在這裡提前說明一下,網上有很多專案在例項化瀏覽器時,需要調整桌面解析度,然後最大化視窗,這樣截圖才不會出現截不全的情況,我這邊是比較省事的,直接用xpath定位到驗證碼的png檔案。直接寫入到本地,然後傳到圖片識別平臺進行識別。

裡面涉及了一些selenium的方法,我基本上都是現查現用,比如按住滑鼠不放、按左鍵什麼的。

具體的程式碼和註解貼在下面,

fromseleniumimportwebdriver
fromhashlibimportmd5
importrequests
importtime
fromselenium.webdriverimportActionChains

#這個類是超級鷹平臺寫的呼叫服務的介面程式碼,也是比較容易看懂的
classChaojiying_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;MSIE8.0;WindowsNT5.1;Trident/4.0)',
}

defPostPic(self,im,codetype):
"""
im:圖片位元組
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)
returnr.json()

defReportError(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)
returnr.json()

#這裡進入模擬登入的主程式

#例項化瀏覽器,並且最大化。然後請求12306主網站,我這裡是從首頁請求的,大家可以直接從登陸頁面請求
browser=webdriver.Chrome()
browser.maximize_window()
browser.get('http://12306.cn/')
time.sleep(5)
#因為是從首頁請求的,所以下面有兩個點選的動作,都是為了點進登陸頁面
browser.find_element_by_xpath('//*[@id="J-header-login"]/a[1]').click()
time.sleep(0.3)
#這裡比較重要了,這裡就是利用這個程式碼,來更改selenium中的滑動功能,讓網站不報錯
script='Object.defineProperty(navigator,"webdriver",{get:()=>undefined,});'
browser.execute_script(script)
time.sleep(1)
#這裡進入帳號登入
browser.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a').click()
time.sleep(0.3)
#這裡直接定位驗證碼的png檔案,然後儲存
img=browser.find_element_by_xpath('//*[@id="J-loginImg"]')
img.screenshot('cde.png')
#呼叫超級鷹的引數
chaojiying=Chaojiying_Client('使用者名稱','密碼','ID')#這個在超級鷹的例項程式碼中有解釋
im=open('../12306/cde.png','rb').read()
#注意,這裡返回的是一個字典格式,所以直接取要用的key,來返回座標
result=chaojiying.PostPic(im,9004)['pic_str']
print(result)
#這裡就是處理超級鷹返回座標的方法了
all_list=[]
#通過判斷超級鷹返回座標的格式進行座標處理,
#返回的座標有兩種形式,一種是以|隔開的,一種是用,隔開的,對應下面兩種處理方式
#處理好的座標存入list
if'|'inresult:
list=result.split('|')
foriinrange(len(list)):
x_y=[]
x=int(list[i].split(',')[0])
y=int(list[i].split(',')[1])
x_y.append(x)
x_y.append(y)
all_list.append(x_y)
else:
x_y=[]
x=int(result.split(',')[0])
y=int(result.split(',')[1])
x_y.append(x)
x_y.append(y)
all_list.append(x_y)
print(all_list)

#處理好的座標進行迴圈,並帶入selenium進行點選點選
forlinall_list:
x=l[0]
y=l[1]
ActionChains(browser).move_to_element_with_offset(
img,x,y).click().perform()
time.sleep(0.5)
#圖片點選好以後,向表單內傳送賬戶密碼
browser.find_element_by_xpath('//*[@id="J-userName"]').send_keys('賬號')
browser.find_element_by_xpath('//*[@id="J-password"]').send_keys('密碼')
#進行點選登入按鈕
browser.find_element_by_xpath('//*[@id="J-login"]').click()
time.sleep(2)
#下面就是滑動模組了
#上面已經更改過selenium的滑動模組,所以這裡就可以直接定位到按鈕的位置,進行點選滑動
span=browser.find_element_by_xpath('//*[@id="nc_1_n1z"]')
action=ActionChains(browser)
#這裡是selenium的方法,按住點選不放
action.click_and_hold(span)
#下面就是滑動了
action.drag_and_drop_by_offset(span,400,0).perform()
#這裡加了個迴圈,就是滑動不行,一直重新整理繼續滑動,直到成功
#其實這裡也只是為了保險起見,因為上面改了滑動框,基本上都會成功
whileTrue:
try:
info=browser.find_element_by_xpath('//*[@id="J-slide-passcode"]/div/span').text
print(info)
ifinfo=='哎呀,出錯了,點選重新整理再來一次':
#點選重新整理
browser.find_element_by_xpath('//*[@id="J-slide-passcode"]/div/span/a').click()
time.sleep(0.2)
#重新移動滑塊
span=browser.find_element_by_xpath('//*[@id="nc_1_n1z"]')
action=ActionChains(browser)
#點選長按指定的標籤
action.click_and_hold(span).perform()
action.drag_and_drop_by_offset(span,400,0).perform()
time.sleep(5)
except:
print('ok!')
break
#完成後,鬆開滑鼠
action.release()

time.sleep(5)
#退出
browser.quit()

最後想說的是

實現搶票的事,這個我還暫時沒想好怎麼去做

平時工作比較忙

所以以後實現這個功能吧

拜拜~