1. 程式人生 > 程式設計 >Selenium之模擬登入鐵路12306的示例程式碼

Selenium之模擬登入鐵路12306的示例程式碼

最近接觸了一些selenium模組的相關知識,覺得還挺有意思的,於是決定親自嘗試寫一些爬蟲程式來強化selenium模組(一定要多嘗試、多動手、多總結)。本文主要使用python爬蟲來模擬登入鐵路12306官網。這兒得吐槽一句,鐵路12306網站的反爬機制做的還是比較好。

話不多說,下面跟小墨一起來學習如何通過爬蟲來實現鐵路12306的登入。

一、 驗證碼破解

當我們輸入賬號和密碼後,在點選登入按鈕之前,還需要對驗證碼進行操作。對驗證碼的識別,已經有相關的處理平臺,我們只需要藉助第三方平臺即可。

1.註冊並登入超級鷹賬號:點選連結進行註冊https://www.chaojiying.com/user/login/;

2.點選購買題分,並進行充值;
3.點選軟體id,建立一個軟體Id(程式中會用到);
4.下載示例程式碼(開發文件—>選擇相應的語言–>下載示例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: 圖片位元組
  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',headers=self.headers)
  return r.json()

二、Selenium功能簡介

Selenium模組和爬蟲之間的關聯:
–便捷的獲取網站中的動態載入資料
–便捷實現模擬登入

Selenium模組的使用流程:
–環境安裝:pip install selenium
–下載瀏覽器的驅動程式(谷歌瀏覽器):
–下載路徑:http://chromedriver.storage.googleapis.com/index.html
– 驅動程式和瀏覽器的對映關係:對映連結
–將下載好的驅動程式放在當前專案目錄下

Selenium模組的相關方法:https://www.jb51.net/article/192259.htm

上述內容完成後,我們就可以正式進入正題了,是不是很期待,那就跟著小墨往下走吧。

三、模擬登入

1. 進入官網

#建立物件
#executable_path=path:下載好的驅動程式的路徑
bro = webdriver.Chrome(executable_path='chromedriver.exe')
#12306的登入網址
bro.get('https://kyfw.12306.cn/otn/resources/login.html')
#視窗最大化
bro.maximize_window()

2、進入登入介面並獲取驗證碼

#save_screenshot就是將當前頁面進行截圖且儲存
bro.save_screenshot('aa.png')
#確定驗證碼圖片對應的左上角和右下角的座標(裁剪的區域就確定)
code_img_ele = bro.find_element_by_xpath('//*[@id="J-loginImg"]')
location = code_img_ele.location # 驗證碼圖片左上角的座標 x,y
#print('location:',location)
size = code_img_ele.size #驗證碼標籤對應的長和寬
#print('size:',size)
#左上角和右下角座標
rangle = (
int(location['x']),int(location['y']),int(location['x'] + size['width']),int(location['y'] + size['height']))
#至此驗證碼圖片區域就確定下來了
i = Image.open('./aa.png')
code_img_name = './code.png'
#crop根據指定區域進行圖片裁剪
frame = i.crop(rangle)
frame.save(code_img_name)
#將驗證碼圖片提交給超級鷹進行識別
chaojiying = Chaojiying_Client('########','#######','#######')	#使用者賬號>>密碼>>軟體ID 
im = open('code.png','rb').read()									#本地圖片檔案路徑 來替換 a.jpg 有時WIN系統須要//
id=chaojiying.PostPic(im,9004)['pic_id']       #擷取的驗證碼照片以及驗證碼的類別代號
result = chaojiying.PostPic(im,9004)['pic_str']     #識別結果
all_list = [] #要儲存即將被點選的點的座標 [[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)
#遍歷列表,使用動作鏈對每一個列表元素對應的x,y指定的位置進行點選操作
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)

這樣我們就實現了驗證碼的識別操作。

3、輸入賬號和密碼,並點選登入按鈕

#輸入賬號和密碼
 put1=bro.find_element_by_id('J-userName')
 #當驗證碼識別錯誤後,需要清空賬號重新輸入
 put1.clear()
 #輸入賬號
 put1.send_keys('########')
 time.sleep(1)
 put2=bro.find_element_by_id('J-password')
 put2.clear()
 #輸入密碼
 put2.send_keys('##########')
 time.sleep(1)
 #點選登入按鈕
 bro.find_element_by_id('J-login').click()

點選登入按鈕後,會出現如下圖所示的彈框

Selenium之模擬登入鐵路12306的示例程式碼

因此,我們需要定位到該提示框,並實現滑塊的向右滑動

4、滑塊滑動

#處理提示框
time.sleep(0.5)
span=bro.find_element_by_xpath('//*[@id="nc_1_n1z"]')
action = ActionChains(bro)
#點選長按指定的標籤
action.click_and_hold(span).perform()
action.drag_and_drop_by_offset(span,400,0).perform()

有的時候,當滑塊移動後,會出現如下圖所示的情況:

Selenium之模擬登入鐵路12306的示例程式碼

因此,我們需要點選重新整理,並重新進行滑塊的移動,所以對程式碼做稍微的改動:

while True:
  try:
   info=bro.find_element_by_xpath('//*[@id="J-slide-passcode"]/div/span').text
   print(info)
   if info=='哎呀,出錯了,點選重新整理再來一次':
   	 #點選重新整理
    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)
    # 點選長按指定的標籤
    action.click_and_hold(span).perform()
    action.drag_and_drop_by_offset(span,0).perform()
    time.sleep(7)
  except:
   print('ok!')
   break

至此,我們便實現了鐵路12306的登入,如下圖所示

Selenium之模擬登入鐵路12306的示例程式碼

是不是覺得很簡單啊。

5、完整程式碼

# -*- coding: utf-8 -*-

#驗證碼識別示例
import requests
from hashlib import md5
class Chaojiying_Client(object):
 def __init__(self,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

#建立物件
#executable_path=path:下載好的驅動程式的路徑
bro = webdriver.Chrome(executable_path='chromedriver.exe')
#12306的登入網址
bro.get('https://kyfw.12306.cn/otn/resources/login.html')
#視窗最大化
bro.maximize_window()
#點選賬號登入
bro.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a').click()
time.sleep(1)
while True:
 try:
  #save_screenshot就是將當前頁面進行截圖且儲存
  bro.save_screenshot('aa.png')
  #確定驗證碼圖片對應的左上角和右下角的座標(裁剪的區域就確定)
  code_img_ele = bro.find_element_by_xpath('//*[@id="J-loginImg"]')
  location = code_img_ele.location # 驗證碼圖片左上角的座標 x,y
  #print('location:',location)
  size = code_img_ele.size #驗證碼標籤對應的長和寬
  #print('size:',size)
  #左上角和右下角座標
  rangle = (
  int(location['x']),int(location['y'] + size['height']))
  #至此驗證碼圖片區域就確定下來了
  i = Image.open('./aa.png')
  code_img_name = './code.png'
  #crop根據指定區域進行圖片裁剪
  frame = i.crop(rangle)
  frame.save(code_img_name)
  #將驗證碼圖片提交給超級鷹進行識別
  chaojiying = Chaojiying_Client('#####','######')	#使用者賬號>>密碼>>軟體ID
  im = open('code.png','rb').read()									#本地圖片檔案路徑 來替換 a.jpg 有時WIN系統須要//
  id=chaojiying.PostPic(im,9004)['pic_id']       #擷取的驗證碼照片以及驗證碼的類別代號
  result = chaojiying.PostPic(im,9004)['pic_str']     #識別結果
  all_list = [] #要儲存即將被點選的點的座標 [[x1,y2]]
  #識別錯誤後,會返回題分,官網給的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)
  #遍歷列表,使用動作鏈對每一個列表元素對應的x,y指定的位置進行點選操作
  for l in all_list:
   x = l[0]
   y = l[1]
   ActionChains(bro).move_to_element_with_offset(code_img_ele,y).click().perform()
   time.sleep(0.5)
  #輸入賬號和密碼
  put1=bro.find_element_by_id('J-userName')
  #當驗證碼識別錯誤後,需要清空賬號重新輸入
  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)
  #點選長按指定的標籤
  action.click_and_hold(span).perform()
  action.drag_and_drop_by_offset(span,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=='哎呀,出錯了,點選重新整理再來一次':
     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)
     # 點選長按指定的標籤
     action.click_and_hold(span).perform()
     action.drag_and_drop_by_offset(span,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()
#輸入起點、終點以及時間,查詢車票
start_city='北京'
end_city='上海'
date='2020-08-05'
#選擇起點
bro.find_element_by_xpath('//*[@id="fromStationText"]').click()
time.sleep(2)
#這隻遍歷了熱門城市,要是想遍歷其他城市,自己寫一個迴圈就行
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)
#選擇終點
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)

到此這篇關於Selenium之模擬登入鐵路12306的示例程式碼的文章就介紹到這了,更多相關Selenium 模擬登入12306內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!