1. 程式人生 > >Python 爬驗證碼

Python 爬驗證碼

元素定位 path -a 時間 地址 url 並且 腳本 驗證

主要實現功能:
- 登陸網頁
- 動態等待網頁載入
- 驗證碼下載

非常早就有一個想法,就是自己主動依照腳本運行一個功能。節省大量的人力——個人比較懶。花了幾天寫了寫,本著想完成驗證碼的識別,從根本上解決這個問題,僅僅是難度太高,識別的準確率又太低。計劃再次告一段落。
希望這次經歷能夠與大家進行分享和交流。

註:代碼中的 username與password都是無效的!


Python打開瀏覽器

相比與自帶的urllib2模塊,操作比較麻煩。針對於一部分網頁還須要對cookie進行保存,非常不方便。於是。我這裏使用的是Python2.7下的selenium模塊進行網頁上的操作。

測試網頁:http://graduate.buct.edu.cn


打開網頁:(需下載chromedriver)
為了支持中文字符輸出,我們須要調用sys模塊。把默認編碼改為 UTF-8

from selenium.webdriver.support.ui import Select, WebDriverWait
from selenium import webdriver
from selenium import common
from PIL import Image
import pytesser
import sys

reload(sys)
sys.setdefaultencoding(‘utf8‘
) broswer = webdriver.Chrome() broswer.maximize_window() username = ‘test‘ password = ‘test‘ url = ‘http://graduate.buct.edu.cn‘ broswer.get(url)

等待網頁載入完成

使用的是selenium中的WebDriverWait。上面的代碼中已經載入

url = ‘http://graduate.buct.edu.cn‘
broswer.get(url)
wait = WebDriverWait(webdriver,5) #設置超時時間5s
# 在這裏輸入表單填寫並載入的代碼
elm = wait.until(lambda webdriver: broswer.find_element_by_xpath(xpathMenuCheck))

元素定位、字符輸入

接下來我們須要進行登錄操作:這裏我使用的是Chrome,右鍵選擇須要進行填寫內容的部分,選擇檢查,會自己主動轉跳到 F12下的開發人員模式(全程須要這個功能來找到相關的資源)。

技術分享

以下的UserRole部分就是和“教師端”選擇有關的部分
技術分享
這裏我們看到有一個value = “1”,考慮到下拉框的屬性,我們僅僅要想辦法把這個value賦值給UserRole就好了。
這裏使用的是通過selenium的Select模塊來進行選擇,定位控件使用 find_element_by_**,能一一相應,非常方便。

select = Select(broswer.find_element_by_id(‘UserRole‘))
select.select_by_value(‘2‘)
name = broswer.find_element_by_id(‘username‘)
name.send_keys(username)
pswd = broswer.find_element_by_id(‘password‘)
pswd.send_keys(password)
btnlg = broswer.find_element_by_id(‘btnLogin‘)
btnlg.click()

這是用腳本自己主動填充完的效果,之後就會轉跳到下一頁。
技術分享


這裏,我須要的是功能是自己主動對學術報告進行報名
技術分享

對須要已有的報告右鍵就可以發現和這個活動有關的消息,因如今沒有報告,所以僅僅顯示了標題。但對於後面的有效報告識別有類似的地方。
技術分享

對於元素的定位,我優先選擇了 xpath。依據測試。能夠唯一定位一個元素的位置,非常好用。

//*[@id="dgData00"]/tbody/tr/td[2]  (前面是xpath)

技術分享


爬取信息

接下來我們要進行的步驟是爬取現有的有效報告:

# 尋找有效報告
flag = 1
count = 2
count_valid = 0
while flag:
    try:
        category = broswer.find_element_by_xpath(‘//*[@id="dgData00"]/tbody/tr[‘ + str(count) + ‘]/td[1]‘).text
        count += 1
    except common.exceptions.NoSuchElementException:
        break

# 獲取報告信息
flag = 1
for currentLecture in range(2, count):
    # 類別
    category = broswer.find_element_by_xpath(‘//*[@id="dgData00"]/tbody/tr[‘ + str(currentLecture) + ‘]/td[1]‘).text
    # 名稱
    name = broswer.find_element_by_xpath(‘//*[@id="dgData00"]/tbody/tr[‘ + str(currentLecture) + ‘]/td[2]‘).text
    # 單位
    unitsPublish = broswer.find_element_by_xpath(‘//*[@id="dgData00"]/tbody/tr[‘ + str(currentLecture) + ‘]/td[3]‘).text
    # 開始時間
    startTime = broswer.find_element_by_xpath(‘//*[@id="dgData00"]/tbody/tr[‘ + str(currentLecture) + ‘]/td[4]‘).text
    # 截止時間
    endTime = broswer.find_element_by_xpath(‘//*[@id="dgData00"]/tbody/tr[‘ + str(currentLecture) + ‘]/td[5]‘).text

爬取驗證碼

技術分享

對網頁中的驗證碼進行元素審查後,我們發現了當中的一個一個鏈接,是 IdentifyingCode.apsx。後面我們就對這個頁面進行載入,並批量獲取驗證碼。

技術分享

爬取的思路是用selenium截取當前頁面(僅顯示部分)。並保存到本地——須要翻頁並截取特定位置的請研究:broswer.set_window_position(**)相關函數;然後人工進行驗證碼的定位,通過PIL模塊進行截取並保存。
最後調用谷歌在Python下的pytesser進行字符識別,但這個站點的驗證碼有非常多的幹擾,外加字符旋轉,僅僅能識別當中的一部分字符。

# 獲取驗證碼並驗證(僅僅一幅)
authCodeURL = broswer.find_element_by_xpath(‘//*[@id="Table2"]/tbody/tr[2]/td/p/img‘).get_attribute(‘src‘)  # 獲取驗證碼地址
broswer.get(authCodeURL)
broswer.save_screenshot(‘text.png‘)
rangle = (0, 0, 64, 28)
i = Image.open(‘text.png‘)
frame4 = i.crop(rangle)
frame4.save(‘authcode.png‘)
qq = Image.open(‘authcode.png‘)
text = pytesser.image_to_string(qq).strip()
# 批量獲取驗證碼
authCodeURL = broswer.find_element_by_xpath(‘//*[@id="Table2"]/tbody/tr[2]/td/p/img‘).get_attribute(‘src‘)  # 獲取驗證碼地址
# 獲取學習樣本
for count in range(10):
    broswer.get(authCodeURL)
    broswer.save_screenshot(‘text.png‘)
    rangle = (1, 1, 62, 27)
    i = Image.open(‘text.png‘)
    frame4 = i.crop(rangle)
    frame4.save(‘authcode‘ + str(count) + ‘.png‘)
    print ‘count:‘ + str(count)
    broswer.refresh()
broswer.quit()

技術分享

一部分驗證碼原圖:
技術分享 技術分享 技術分享 技術分享

從上面的驗證碼看出。字符是帶旋轉的,並且由於旋轉造成的重疊對於興許的識別也有非常大的影響。我曾嘗試過使用神經網絡進行訓練。但因沒有進行特征向量的提取。準確率低得離譜。


這個是一位作者實踐後的心得:
http://www.cnblogs.com/sweetwxh/p/captcha_recognize.html

看了之後我變得清醒。決定不再繼續識別驗證碼了。但這個經驗非常實用,以後就能夠拿來爬各種數據了

Python 爬驗證碼