文章來源:http://cache.baiducontent.com/c?m=9d78d513d98216f10fb1cf395201d6160e54f0743da7924f2c88d515cc3c1a564616f4ca54356000c4b57f7075ad5e5d9ae74675207421a09ab89f3adbace12f38895723016f913164c418dfdc3026d6579b4d9fab0e94bce733e3b9a3d3c82323de1445248faacd1c4203cb1ced0961bdfbcc5f152841fbbb6c72ff2e2b7ed93e1ff619aea46f690783eb8e1c0a987b8e360cc1f873e3654cf40ea31c102647a749ba&p=8967df16d9c157c342bd9b7e0d16cf&newp=8b2a9715d9c341af409fd028445e8e231610db2151d7d61e6b82c825d7331b001c3bbfb423241206d7ce776404ac4c56eefb3c71360625a3dda5c91d9fb4c57479&user=baidu&fm=sc&query=selenium%2BphantomJS%CA%B6%B1%F0%B5%E3%B4%A5%CA%BD%D1%E9%D6%A4%C2%EB&qid=ed7b0d0f000019c4&p1=4
Python 2.7
IDE Pycharm 5.0.3
Firefox瀏覽器:47.0.1
Selenium:Selenium的介紹及使用,強烈推薦@ Eastmount的博客
PIL : Pillow-3.3.0-cp27-cp27m-win_amd64.whl PIL第三方庫的下載
win下安裝whl文件
Pytesser:依賴於PIL ,Tesseract 了解pytesser及基本使用
Tesseract:3.0.2 tesseract下載及安裝
我有個理想,就是把TMD教務系統弄崩潰,我港真的!
扯淡
我相信每個腳本都有自己的故事,我這個腳本來源於自己GRD教務系統,每次進行登錄時,即使我輸入全部正確,第一次登錄一定是登不上去的!我不知道設計人員什么想法?難道是為了反爬機制?你以為一次登不上,我tm就不爬了?我要是不高興了,信不信秒秒鍾訪問你1000+讓大家都上不去咯~咳咳,有點跑題了。 
目的
自動識別驗證碼模擬登陸,注意是自動,一鍵登錄,不是那種掃出驗證碼,然后手動輸入登錄!
首先來代碼實現吧!
# -*- coding: utf-8 -*- #Author:哈士奇說喵 from selenium import webdriver import os import pytesser import sys,time from PIL import Image,ImageEnhance #shift+tab多行縮進(左) reload(sys) PostUrl = "http://yjsymis.hrbeu.edu.cn/gsmis/indexAction.do" driver=webdriver.Firefox() driver.get(PostUrl) i=0 while 1:#sb登錄系統,即使輸對所有消息還是登不進去的,需要登錄兩次及以上 i=i+1 try: elem_user = driver.find_element_by_name('id') elem_psw = driver.find_element_by_name('password') elem_code = driver.find_element_by_name('checkcode') except: break #-------------------對驗證碼進行區域截圖,好吧,這方法有點low------------------ driver.get_screenshot_as_file('C:\Users\MrLevo\image1.jpg')#比較好理解 im =Image.open('C:\Users\MrLevo\image1.jpg') box = (516,417,564,437) #設置要裁剪的區域 region = im.crop(box) #此時,region是一個新的圖像對象。 #region.show()#顯示的話就會被占用,所以要注釋掉 region.save("e:/image_code.jpg") #------------------------------------------------------------------- #--------------ImageGrab.grab()直接可以區域截圖,但是有bug,截圖不全------- ''' bbox = (780, 0, 1020, 800) img = ImageGrab.grab() img.save("E:\image_code.jpg") img.show() ''' #-------------------------手動輸入驗證碼:適用范圍更廣,但不夠方便------------------------------ ''' response = opener.open(CaptchaUrl) picture = response.read() with open('e:/image.jpg', 'wb') as local: local.write(picture) # 保存驗證碼到本地 #------------對於不能用pytesser+ocr進行識別,手動打開圖片手動輸入-------- # 打開保存的驗證碼圖片 輸入 #SecretCode = raw_input('please enter the code: ') #---------------------------------------------------------------------- ''' #--------------------圖片增強+自動識別簡單驗證碼----------------------------- #time.sleep(3)防止由於網速,可能圖片還沒保存好,就開始識別 def image_file_to_string(file): cwd = os.getcwd() try : os.chdir("C:\Users\MrLevo\Anaconda2\Lib") return pytesser.image_file_to_string(file) finally: os.chdir(cwd) im=Image.open("E:\\image_code.jpg") imgry = im.convert('L')#圖像加強,二值化 sharpness =ImageEnhance.Contrast(imgry)#對比度增強 sharp_img = sharpness.enhance(2.0) sharp_img.save("E:\\image_code.jpg") #http://www.cnblogs.com/txw1958/archive/2012/02/21/2361330.html #imgry.show()#這是分布測試時候用的,整個程序使用需要注釋掉 #imgry.save("E:\\image_code.jpg") code= pytesser.image_file_to_string("E:\\image_code.jpg")#code即為識別出的圖片數字str類型 print code #打印code觀察是否識別正確 #---------------------------------------------------------------------- if i <= 2: # 根據自己登錄特性,我這里是驗證碼失敗一次,重填所有,失敗兩次,重填驗證碼 elem_user.send_keys('S315080092') elem_psw.send_keys('xxxxxxxxxx') elem_code.send_keys(code) click_login = driver.find_element_by_xpath("//img[@src='main_images/images/loginbutton.gif']") click_login.click() #time.sleep(5)#搜索結果頁面停留片刻 #driver.save_screenshot('C:\Users\MrLevo\image.jpg') #driver.close() #driver.quit()
第一次放動圖,心理還有點小激動~

遇到問題及解決方法
1:驗證碼取得問題,因為每次刷新之后驗證碼動態刷新,所以如果不采用cookie的話(我還不太會用cookie),根本捉不到元素,這個我在下篇文章中采用cookie來登錄的,但不是調用瀏覽器,這個跑遠了,下次說。
1:解決方案:用了driver.get_screenshot_as_file方法,機智的進行全截圖,然后采用PIL中的crop進行再截圖操作,可能有人會說,為什么不采用ImageGrab.grab()函數來做,好吧,因為這個函數在win10上盡然!截不了全圖!!自己試了才知道,btw,我的分辨率1920x1080,難道和分辨率有關?反正這個我截了好久都沒有成功,到最后才想到,截全部看看,結果,tmd只有一半,我說怎么都找不到要截圖的部分!
2:驗證碼驗證錯誤率高問題
2:解決方案,采用PIL強大的圖像處理功能,我先將圖片二值化,本來是藍色字體的,,然后再進行對比度強化來銳化圖片,然后再調用Tesseract.exe進行處理,提高的識別精度不是一點兩點:看圖比較,左1是用cookie抓的原圖,右邊是全景截圖,再定位截圖,再進行二值化和銳化處理的圖,本來我想着用matlab做圖像識別的,但是想想還要調用,感覺有點麻煩。。。

3:調用Tesseract.exe問題
3:解決方案因為程序執行圖像識別需要調用Tesseract.exe,所以必須把路徑切到有這個exe的路徑下,剛開始,以為和包依賴,結果根本沒有識別出任何圖!折騰一個多小時才寫好驗證碼識別的問題—-單獨測試的確很重要,記一筆! 
4:登錄失敗問題–mdzz學校教務系統二次驗證
4:解決方案,寫了一個while循環,把主程序很大部分都扔進去了,目的也很明確,如果第一次登錄失敗,再重復進行登錄,注意采用try試探元素是否仍然存在,except來拋出break結束循環,因為登錄成功后,比如說driver.find_element_by_name('id')是不存在的!所以當這個元素在登陸后的界面找不到時,那就說明登錄成功,ok,跳出循環,進行下一步操作。
5:明明圖片已截取,為什么沒有識別
5:解決方案,這個我真的沒想到,我一直以為可能因為save時候還沒下載好,導致庫中沒有這張圖,那就不能識別,但是我用time.sleep函數讓它停下來緩緩,還是不行,我就很無語了,想了半天,可能是因為圖片被占用!因為我有一個img.show()函數,為了檢測有沒有截取到標准的圖,然后show之后這個圖像就被占用了!就像你在編輯word時候,是無法刪除word文檔一樣!果然在注釋掉show之后,一切可行,真是差錯查了小半天啊!! 
6:元素一切就位,為什么不執行操作
6:解決方案,這個有點腦殘了,不過的確是我遇到的,還是記上一筆,然后罵自己一遍sb,沒有click()你讓它怎么處理!!!就像用cookie登錄時候還有個ENTRY呢!
7:兩次驗證失敗后,用戶名重復累加
7:解決方案,直接加了個變量,計數循環次數,觀察到只要超過兩次沒有登錄上,就會累加登錄名和用戶密碼,直接寫了個if進行判斷,完事!
8:im.crop(box)裁剪區域選擇困難症
8:解決方案,多試幾次,反正我是試出來的。。。。當然,你點擊圖片進行審查元素時候,可以看到圖片大小,那么,你就可以知道橫縱坐標差值多少,但是大范圍區域還得自己試,如有更好的辦法,請告知,以下為我截圖實驗次數,次數30+ 
9:導入不了Image,ImageEnhance
9:解決方案,因為PIL用的是第三方庫,所以,采用的導入方式是這樣的,多看看官方文檔就可以,官方描述如下 Usefrom PIL import Imageinstead ofimport Image.
10:找不到應該鍵入的元素
10:這個問題,請單擊要輸入的空白處右鍵,審查元素,就可以看到,然后根據driver.find_element_by_各種方法來定位元素,如果輸入進行了隱藏,在當前頁面找不到怎么辦,就像如下圖,需要先點擊我的圖書館,才能看到輸入的賬戶和密碼,那么先找我的圖書館的元素,進行click操作,之后再找元素,一句話,把自己想成瀏覽器,阿不,把python想成瀏覽器。。。。。 
上圖的代碼我也放上,大同小異,比有驗證碼的簡單,但是多了一個click操作。
# -*- coding: utf-8 -*- #Author:哈士奇說喵 from selenium import webdriver import time import sys #shift+tab多行縮進(左) reload(sys) PostUrl = "http://lib.hrbeu.edu.cn/#" driver=webdriver.Firefox() driver.get(PostUrl) elem_user = driver.find_element_by_name('number') elem_psw = driver.find_element_by_name('passwd') #選擇我的圖書館,點擊后才能看到輸入賬號密碼 click_first = driver.find_element_by_xpath("//ul[@id='imgmenu']/li[4]") click_first.click() elem_user.send_keys('S315080092') elem_psw.send_keys('xxxxxxxx') #點擊登錄 click_second = driver.find_element_by_name('submit') click_second.click() time.sleep(5) #登陸后選擇 click_third = driver.find_element_by_xpath("//*[@id='mainbox']/div/div/ul/li/a") click_third.click() time.sleep(5)#搜索結果頁面停留片刻 #driver.save_screenshot('C:\Users\MrLevo\image.jpg') driver.close() driver.quit()
最后
(雖然我知道以后肯定會再補充):斷斷續續差不多兩天時間來實現這個操作,雖然對大家來說應該不算難,但是對自己還是有蠻大提升的,對selenium有了基本的概念和操作,對PIL也進行了使用,還有ocr的調用,雖然調用firefox來執行操作表面上看起來很酷炫,但是執行效率和占用內存是很大的內傷,但作為可視化的模擬瀏覽器登錄,這點做的還是十分絢麗的。
話說今天登了圖書館才知道,我tm過期書好幾本了,好幾天了,,,,看來得寫個一鍵續期和查詢過期圖書的小工具了,so,又有動力了!
so peace out,guys,and good night! 
