文章目錄
- 前言:
- 1.進入12306界面
- 2.進入登錄界面
- 3. 選擇賬號登陸
- 4.用戶名的輸入
- 5.用戶密碼的輸入
- 6.驗證碼的識別
- 7.滑塊驗證碼的通過
- **后記:**
前言:
感覺12306自動化登錄是所有學習爬蟲愛好者都必須經過的一道練習題,但是由于12306的版本更新,很多之前的自動化登錄代碼或多或少有些紕漏,所以我寫了2021年最新的12306自動化登錄,希望對你會有所啟發,
需要匯入的庫如下:
from selenium import webdriver
from selenium.webdriver import ActionChains
import chaojiying
import base64
import re
from lxml import etree
from time import sleep
1.進入12306界面
言不多說,直接進入正題,對于12306自動化登錄,首先我們需要進入12306的官網首頁,即如下圖片

實作程序如下
url='https://www.12306.cn/index/'
bro=webdriver.Chrome(executable_path='輸入自己電腦的webdriver的絕對位置即可')
bro.get(url=url)
2.進入登錄界面
我們在這個圖片里面的右上角可以看到登錄與注冊兩個選項,我們需要選擇登錄這一選項,從而進入他的登陸頁面,具體代碼實作如下:
bro.find_element_by_xpath('//*[@id="J-header-login"]/a[1]').click()
代碼中我們采用webdriver的find系列,通過xpath決議從而找到‘登錄’的位置,實作程序如下:
按照圖片里面數字的順序,先左擊第一個箭頭所指的位置,然后左擊第二個箭頭所指的位置,在之后,我們需要在第三個箭頭所指的位置右擊,出來選項框之后,在copy那一欄里面就可以找到copy xpath,從而可以得到到‘登錄’的xpath決議
3. 選擇賬號登陸
進入登錄頁面之后,我們會發現是二維碼登錄,我們不采用二維碼登錄,我們使用的是賬號登錄,所以我們需要點擊賬號登錄,從而進入他的賬號登錄頁面, 具體代碼如下:
bro.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a').click() # 點擊賬號登錄
具體圖片如下:

同理,也是按照圖片里面數字的順序,先左擊第一個箭頭所指的位置,然后左擊第二個箭頭所指的位置,在之后,我們需要在第三個箭頭所指的位置右擊,出來選項框之后,在copy那一欄里面就可以找到copy xpath,從而可以得到到‘賬號登錄’的xpath決議
從這個賬號登錄頁面來看,我們需要填入用戶名,用戶密碼以及需要識別驗證碼圖片,接下來我們分步操作,分別完成這三項任務
4.用戶名的輸入
首先是用戶名的輸入,我們需要先定位到用戶名這一欄,然后輸入我們的用戶名即可,具體代碼如下:
bro.find_element_by_xpath('//*[@id="J-userName"]').send_keys('******賬號') # 輸入賬號
這個代碼前面半段可以不用說,就是為了定位到用戶名這一欄,而后面的send_keys的作用是將內容輸入到我們定位好的瀏覽器的文本框里
具體操作流程如下:

這個圖片操作流程前面已經多次重復了,這次就不講了
5.用戶密碼的輸入
然后是用戶密碼的輸入,其實和用戶名的輸入步驟一模一樣
代碼如下:
bro.find_element_by_xpath('//*[@id="J-password"]').send_keys('****自己的賬戶密碼即可') # 輸入密碼
圖片如下:

6.驗證碼的識別
最后是驗證碼的識別,驗證碼的識別我采用的是超級鷹第三方軟體識別,可能會有其他更好更快的識別方式,這里為了簡便,我用的是自己最熟悉的超級鷹識別,
準備作業:
- 再寫這個代碼之前呢,我們需要做一些準備作業,就是將超級鷹的py檔案封裝到一個包里面,這樣我們就可以直接呼叫包,而不用將超級鷹的模塊代碼全部在復制一遍,當然,如果你不想單獨放一個包,全部復制一遍也是可以的,只不過這樣代碼會顯得比較亂,
將超級鷹模塊封裝到一個包里面,其實也很簡單,就是在pycharm里面新建一個包,即python package,然后將超級鷹的模塊代碼復制到這個包下面就可以了,完成之后,其實就是這樣子

有個最重要的一點,就是在封裝之后呢,需要按照圖示如下操作

這樣pycharm就可以呼叫我們自己設定的包了,如果沒有這個操作的話,前面我所說的匯入的庫里面import chaojiying這個陳述句就會報錯,所以這個圖片一定要執行哦
實作原理:
完成準備作業之后呢,我們來解釋一下如何讓第三方軟體去識別驗證碼?

其實原理就是我們將驗證碼下載下來保存到指定的位置上,在保存之后,我們將保存的圖片資訊傳遞給第三方軟體,在他識別之后呢?他會回傳給我們x,y坐標,這些x,y坐標就是圖片需要點擊的x,y坐標,有一點需要注意,這些x,y是相對坐標,是相對于圖片左上角(0,0)坐標而言的
最后一個知識點:
在理解這份代碼之前,還有一個知識點也需要講,就是我們在定位到驗證碼圖片的時候,會有這樣一段亂碼
<img id="J-loginImg" `class="imgCode" alt="" src="data:image/jpg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/2wB........"
這個亂碼太長了,后面的我就用省略號代替了
其實第一眼見到這個亂碼我也很懵逼,查詢之后才知道他就是將這個圖片的資訊以base64的編碼格式直接保存到這個html中,這樣在這個html打開圖片的時候,就不用再動態加載了,然后我們繼續看,在這個src屬性里面,‘data:image/jpg;base64,’這些符號只是告訴我們這個圖片的格式為jpg,他是采用了base64編碼保存的,所以其實他并不是圖片資訊的二進制轉換成的base64編碼,了解這些之后,我們就只需要將base64編碼的資料解碼,然后以二進制的格式保存,這樣就可以得到圖片原來的樣子了
要使用base64解碼,需要用到庫為:
import base64
需要用到的指令為:
base64.b64decode()
ok,接下來我們就先將這個圖片保存到本地,具體代碼如下
page = bro.page_source
# 獲得瀏覽器此時的html資訊
tree = etree.HTML(page)
pic_url = tree.xpath('//*[@id="J-loginImg"]/@src')[0]
# 通過xpath決議,將編碼后的圖片資訊提取出來,保存到pic_url中
pic_url3 = re.sub('data:image/jpg;base64,', '', pic_url1)
# 使用正則的替換函式,將'data:image/jpg;base64,'替換成啥都沒有,相當于洗掉這些內容,至此,我們得到了圖片的base64編碼的所有字符
pic = base64.b64decode(pic_url3)
#然后將字符進行解碼
with open('code.jpg', 'wb') as fp:
fp.write(pic)
# 將解碼后的字符以code的檔案名保存到當前檔案夾中,保存格式為二進制
ok,現在我們已經把圖片保存下來了,接下來就只需要將圖片接入第三方軟體中,讓他幫我們去識別,我們只是要等著就好了,具體代碼如下:
chaojiying1 = chaojiying.Chaojiying_Client('自己注冊的用戶名', '用戶名對應的密碼', '自己注冊的軟體ID')
# 用戶中心>>軟體ID 生成一個替換 96001
im = open('./code.jpg', 'rb').read()
# 本地圖片檔案路徑 來替換 code.jpg 有時WIN系統須要//
xy = chaojiying1.PostPic(im, 9004)['pic_str']
#9004是我們發送的驗證碼的格式,然后這個指令的回傳值是一個字典,在鍵為['pic_str']的值的時候,保存地視回傳的需要點擊的坐標
我們獲得坐標之后呢,就要想辦法分別獲取每個點的x,y,上面超級鷹驗證碼識別可以看到他回傳形式是x1,y1|x2,y2|x3,y3這樣子的,所以我們可以先以’|‘符號來切片,獲得各個點的串列的值,然后對于串列,我們直接使用for in回圈,在使用’,'來切片獲得對應點的x,y的坐標值,對于每一個坐標值,我們直接先定位到圖片上,然后使用指令
action.move_to_element_with_offset(目標元素, x, y).click().perform()
指令中,目標元素就是我們圖片的xpath定位元素,x,y為我們獲得的x,y的坐標值,這個指令會將滑鼠移動到舉例定位元素x方向有x的偏移量,y方向有y的偏移量,然后點擊執行
具體代碼如下:
xy = xy.split(sep='|')
# 通過使用符號'|'來進行劈分,將各個點保存在設定的xy串列里面
for i in xy:
cl = bro.find_element_by_xpath('//*[@id="J-loginImg"]')
# 需要先定位到圖片地址,cl其實就是click的簡寫,我就圖個簡單
action.move_to_element(cl).perform() # ——滑鼠移動到某個元素
# 將滑鼠移動dao二維碼圖片中
xy1 = (i.split(sep=','))
x=int(xy1[0])
y=int(xy1[1])
# 分別獲取x,y的值
action.move_to_element_with_offset(cl, x, y).click().perform()
# 就是通過剛才獲得的x,y的值點擊相應的位置
其實代碼里面將滑鼠移動到某個元素處,并不是我們所見的滑鼠箭頭就移動過去了,而是他就會定位到這個坐標處,滑鼠其實壓根沒動
至此,相應的驗證碼識別即告一段落,接下來我們需要點擊登錄,其實點擊登錄特別簡單,代碼如下
bro.find_element_by_xpath('//*[@id="J-login"]').click()
ok,這樣一來我們就相當于完成了驗證碼識別以及后續的點擊登錄操作,但是在運行程序中,你會發現有時候這個第三方軟體并不能特別準確的識別驗證碼,有時也會出錯,或者在圖片保存的時候,有時也會出現圖片沒有正確保存的情況,對于這種情況,我們就想設定一個回圈,將這個操作放到回圈里面,只有驗證碼正確識別之后,我們才給它進行下一步
然后我們會發現,在他驗證成功之后呢,還會出現一個滑塊驗證,那我們就可以檢測在我們識別二維碼點擊登錄之后,會不會出現滑塊驗證,然后我們定位到滑塊這里,然后我們會發現在二維碼識別之前和識別之后,這個滑塊代碼其實一直都在html中,只不過沒有正確識別之前,里面的屬性display的值為none,而正確識別之后呢,display屬性就沒了,所以其實我們只需要判斷這個里面的display屬性值是不是none,我們就可以判斷有沒有正確識別成功了

第一張圖片是驗證碼正確驗證之后滑塊代碼情況,第二張圖片是正確驗證之前的滑塊代碼情況
然后我們需要在一個回圈里面不停的去判斷,然后去執行,代碼如下
while(True):
t2 = tree.xpath('//*[@id="login_slide_box"]/@style')[0]
# 獲取到滑塊驗證的style的屬性值,因為我們所講的display在style屬性中,所以需要這樣判斷
t=re.search(‘none’,t2)
# 使用正則搜索,判斷none是否在style屬性中,注意回傳值不是str,所以我們需要強制轉換
t=str(t)
action = ActionChains(bro)
if t!='None':
chaojiying1 = chaojiying.Chaojiying_Client('*****用戶名', '***用戶密碼', '軟體id') # 用戶中心>>軟體ID 生成一個替換 96001
im = open('./code.jpg', 'rb').read() # 本地圖片檔案路徑 來替換 a.jpg 有時WIN系統須要//
xy = chaojiying1.PostPic(im, 9004)['pic_str']
try:
print(xy)
xy = (xy.split(sep='|'))
for i in xy:
cl = bro.find_element_by_xpath('//*[@id="J-loginImg"]')
action.move_to_element(cl).perform() # ——滑鼠移動到某個元素
xy1 = (i.split(sep=','))
x=int(xy1[0])
y=int(xy1[1])
action.move_to_element_with_offset(cl, x, y).click().perform()
bro.find_element_by_xpath('//*[@id="J-login"]').click()
except ValueError:
print('驗證失敗,正在重新驗證')
# 我們在這里使用try expect是因為有時候,圖片出錯導致沒有辦法識別處我們需要點的坐標,會報錯,我們將錯誤輸出一下,然后讓他重新驗證就好了,不然錯誤會導致程式無法運行下去
這個代碼其他部分上面已經講過,所以這邊不在贅復
7.滑塊驗證碼的通過
在執行完這些之后呢,我們只需要完成最后一步,進行滑塊碼驗證,首先我們需要用到一下指令
action.click_and_hold(drag1).perform()
# 這個其實就是長按點擊目標元素
action.move_to_element_with_offset(drag1, 400, 0).perform()
# 這個其實就是拖動目標元素相對偏移量x,y
action.release().perform()
# 這個其實就是釋放剛才長按的滑鼠
其中呢,perform都表示執行的意思,然后action其實就是我之前的
action = ActionChains(bro) 即動作連
所以要完成滑塊碼驗證,我們需要先定位到滑塊碼位置處,然后長按點擊滑塊碼位置處,然后拖動滑塊碼位置進行偏移量,最后釋放長按的滑鼠
具體代碼如下:
drag = bro.find_element_by_xpath('//*[contains(@class,"nc_iconfont btn_slid")]')
# 這個就是定位到滑塊出,并且賦值給drag
action.click_and_hold(drag).perform()
# 這個就是長按滑塊的意思
action.move_to_element_with_offset(drag, 400, 0).perform()
# 這個就是拖動滑塊的意思
action.release().perform()
# 這個就是釋放滑塊
在完成這些之后呢,12306的登錄程式就已經完成了,下面看我詳細代碼
#作業人:zhuangzhou
#作業時間:2021/2/20 12:32
from selenium import webdriver
from selenium.webdriver import ActionChains
import chaojiying
import base64
import re
from lxml import etree
from time import sleep
url='https://www.12306.cn/index/'
bro=webdriver.Chrome(executable_path='***相對地址')
bro.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
"""
})
#這段也特別重要,是為了讓webdriver規避被檢測的風險
bro.get(url=url)
bro.maximize_window()
bro.find_element_by_xpath('//*[@id="J-header-login"]/a[1]').click()
bro.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a').click()
bro.find_element_by_xpath('//*[@id="J-userName"]').send_keys('****用戶名')
bro.find_element_by_xpath('//*[@id="J-password"]').send_keys('***用戶密碼')
gd="window.scrollTo(0,document.body.scrollHeight=500)"
# '''用于設定滑鼠滾動500像素點,'''
bro.execute_script(gd)
while(True):
page = bro.page_source
tree = etree.HTML(page)
pic_url = tree.xpath('//*[@id="J-loginImg"]/@src')[0]
pic_url3 = re.sub('data:image/jpg;base64,', '', pic_url)
pic = base64.b64decode(pic_url3)
with open('code.jpg', 'wb') as fp:
fp.write(pic)
t2 = tree.xpath('//*[@id="login_slide_box"]/@style')[0]
t=re.search('display',t2)
t=str(t)
action = ActionChains(bro)
if t!='None':
chaojiying1 = chaojiying.Chaojiying_Client('***用戶名', '***用戶密碼', '軟體ID') # 用戶中心>>軟體ID 生成一個替換 96001
im = open('./code.jpg', 'rb').read() # 本地圖片檔案路徑 來替換 a.jpg 有時WIN系統須要//
xy = chaojiying1.PostPic(im, 9004)['pic_str']
try:
xy = (xy.split(sep='|'))
for i in xy:
cl = bro.find_element_by_xpath('//*[@id="J-loginImg"]')
action.move_to_element(cl).perform() # ——滑鼠移動到某個元素
xy1 = (i.split(sep=','))
x=int(xy1[0])
y=int(xy1[1])
action.move_to_element_with_offset(cl, x, y).click().perform()
sleep(5)
bro.find_element_by_xpath('//*[@id="J-login"]').click()
sleep(5)
except ValueError:
print('驗證失敗,在重新驗證')
else:
drag = bro.find_element_by_xpath('//*[contains(@class,"nc_iconfont btn_slid")]')
sleep(2)
action.move_to_element(drag).perform()
sleep(1)
action.click_and_hold(drag).perform()
sleep(1)
action.move_to_element_with_offset(drag, 400, 0).perform()
sleep(1)
action.release().perform()
break
后記:
至此,自動化登錄程式就完成了,希望本文對大家有用,如果可以,一鍵三聯哦
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/263484.html
標籤:python
上一篇:SpringBoot的配置【組態檔、加載順序、配置原理】(超詳細)
下一篇:串口通信write函式執行時間長
