由於有一個課程要求進行調查數據的統計,並且小組裏選用的是問卷星爲平臺,問題的形式比較單一,都爲單選或多選,因而想到了用python實現一個腳原本代替小組裏你們的手動填寫。。css
大致上使用的就是python+Selenium+PIL+Tesseracthtml
Selenium 是一種瀏覽器自動化測試框架,經過它檢索html與css代碼就能夠輕鬆地找到想要的單選框、複選框、提交鍵等等,而後即可以自動化地實現點擊事件。但在這個過程當中,仍是有不少細節須要注意的。python
例如我使用的firefox瀏覽器須要下載一個調試驅動插件 -> "geckodriver" 。git
在最後提交數據的時候使用click()函數沒有起到跳轉頁面的做用,最後是使用send_keys(Keys.ENTER),也就是按Enter鍵才能實現。猜想是資料中說起的click只是觸發事件的方式的其中一種。github
PIL (Python Image Library)則是python的一個圖形處理庫,在一段時間內提交的次數過多時,網站便會要求輸入驗證碼,這時候就要經過Selenium截取屏幕圖片而後經過PIL進行進一步的截取和優化圖片的效果。由於驗證碼當中可能會有干擾線、拉伸變形,這時候就要經過處理才能更好地判斷出當中的數據。web
Tesseract 是一款由HP實驗室開發由Google維護的開源的光學字符識別引擎,PIL處理事後的圖片即是經過tesseract來與從github上已有的訓練數據進行匹配。算法
1 # coding: utf-8 2 3 from selenium import webdriver 4 from selenium.webdriver.common.by import By 5 from selenium.webdriver.common.keys import Keys 6 from selenium.webdriver.support.ui import Select 7 from selenium.webdriver.common.action_chains import ActionChains 8 from selenium.common.exceptions import NoAlertPresentException 9 from PIL import Image,ImageEnhance 10 import random,os,time,pytesseract 11 12 bs = webdriver.Firefox(executable_path="geckodriver") 13 bs.set_window_size(600,400) 14 15 def func(): 16 bs.get('https://www.wjx.cn/m/17854971.aspx/') 17 bs.find_elements_by_class_name("ui-radio")[0].click() 18 bs.find_elements_by_class_name("ui-checkbox")[1].click() 19 bs.find_elements_by_class_name("ui-radio")[2].click() 20 bs.find_elements_by_class_name("ui-checkbox")[4].click() 21 bs.find_elements_by_class_name("ui-checkbox")[5].click() 22 bs.find_elements_by_class_name("ui-checkbox")[8].click() 23 bs.find_elements_by_class_name("ui-checkbox")[11].click() 24 bs.find_elements_by_class_name("ui-radio")[6].click() 25 bs.find_elements_by_class_name("ui-checkbox")[random.randint(14, 17)].click() 26 try: 27 bs.find_element_by_id("yucinput").click() 28 time.sleep(2) 29 bs.get_screenshot_as_file('D://python_project//wholepage.png') 30 im = Image.open("D://python_project//wholepage.png") 31 box = (160, 180, 409, 308) 32 region = im.crop(box) 33 region.save("D://python_project//testwholepage.png") 34 im = Image.open("D://python_project//testwholepage.png") 35 im = im.convert("L") 36 threshold = 55 37 pixdata = im.load() 38 w, h = im.size 39 for y in range(h): 40 for x in range(w): 41 if pixdata[x, y] < threshold: pixdata[x, y] = 0 else: pixdata[x, y] = 255 for y in range(1, h - 1): for x in range(1, w - 1): count = 0 if pixdata[x, y - 1] > 245: 42 count = count + 1 43 if pixdata[x, y + 1] > 245: 44 count = count + 1 45 if pixdata[x - 1, y] > 245: 46 count = count + 1 47 if pixdata[x + 1, y] > 245: 48 count = count + 1 49 if count > 2: 50 pixdata[x, y] = 255 51 52 im.save("D://python_project//newMethod.png") 53 img = Image.open("D://python_project//newMethod.png") 54 code = pytesseract.image_to_string(img, "eng") 55 newCode = '' 56 for c in code: 57 if(c.isalnum()): 58 newCode += c 59 print(newCode) 60 bs.find_element_by_id("yucinput").send_keys(newCode) 61 except Exception: 62 print("other_func()") 63 finally: 64 bs.find_element_by_id("ctlNext").send_keys(Keys.ENTER) 65 66 def func2(): 67 bs.get('https://www.wjx.cn/m/17854971.aspx/') 68 bs.find_elements_by_class_name("ui-radio")[random.randint(0, 1)].click() 69 bs.find_elements_by_class_name("ui-checkbox")[random.randint(0, 2)].click() 70 bs.find_elements_by_class_name("ui-radio")[random.randint(2, 4)].click() 71 bs.find_elements_by_class_name("ui-checkbox")[random.randint(3, 6)].click() 72 bs.find_elements_by_class_name("ui-checkbox")[random.randint(7, 10)].click() 73 bs.find_elements_by_class_name("ui-checkbox")[random.randint(11, 13)].click() 74 bs.find_elements_by_class_name("ui-radio")[random.randint(5, 7)].click() 75 bs.find_elements_by_class_name("ui-checkbox")[random.randint(14, 17)].click() 76 bs.find_element_by_id("ctlNext").send_keys(Keys.ENTER) 77 78 ''' def check(css): 79 80 s = bs.find_elements_by_css_selector(css_selector=css). 81 if(len(s) == 0): 82 func2() 83 elif len(s) == 1: 84 func() ''' 85 86 while True: 87 try: 88 '''check("#yucinput")''' 89 func() 90 except Exception: 91 t = bs.switch_to_alert() 92 print(t.text) 93 t.accept() 94 time.sleep(2)
兩天趕出來的代碼。。很是混亂,最後仍是能夠跑起來。不過tesseract的準確率有點感人,大概是十個裏面對上四個就不錯了。可是自動化處理起來的效率畢竟仍是高於人工輸入的。最主要的緣由我想仍是在驗證碼圖片方面處理得不夠好,裏面圖片處理首先是轉成灰度圖而後二值化而後對干擾線進行處理。而數據的輸入能夠採起random.randint(x,y) 就可讓數據平均顯示。瀏覽器
這是處理前框架
這是處理後dom
這已是比較理想的狀況 干擾線並無太多與字體重疊在一塊兒
還有一處地方就是我是把py文件放在tesseract的安裝目錄下才可以運行起來,可是我已經添加了tesseract環境變量。這裏仍是搞不懂的,還有具體圖像優化的算法 仍是要再學習的。還有問卷星網站是必定時間內太多提交纔會要求輸入驗證碼(固然,其實這個也能夠設置爲每次提交都要輸入驗證碼),因此就要使用異常的作區別對待,異常的使用不太熟,也是恰好運行起來了。。還要學習學習。無論這樣使用異常處理是否正確,不過也很是有用地幫助我理解異常這一律唸了。
經過這兩天的調試,最明顯體會到的就是python做爲一門腳本語言,真的很是神奇與方便。大量的現存庫能夠幫助人們在短期裏作出同樣東西來。
參考資料:
Python+Selenium+PIL+Tesseract真正自動識別驗證碼進行一鍵登陸
http://www.51testing.com/html/64/272264-200302.htmls
Selenium.click 不等於手動單擊