Python實(shí)戰(zhàn)案例,cv2模塊,Python識(shí)別圖形驗(yàn)證碼實(shí)現(xiàn)自動(dòng)登陸!
首先尋找測(cè)試網(wǎng)站,網(wǎng)站選的是如云閣小說網(wǎng),小網(wǎng)站不怕被封。他們的驗(yàn)證碼一般如下:
Python騰訊大牛直播預(yù)約:

1. 灰度處理 把彩色驗(yàn)證碼圖片轉(zhuǎn)為灰色的圖片。
import cv2
image = cv2.imread('1.jpeg', 0)
cv2.imwrite('1.jpg', image)
2. 二值化處理 將圖片處理為只有黑白兩色的圖片,這里發(fā)現(xiàn)干擾線沒有了,這就意味著我們只需要處理干擾點(diǎn)即可。
import cv2
image = cv2.imread('1.jpeg', 0)
ret, image = cv2.threshold(image, 100, 255, 1)
height, width = image.shape
new_image = image[0:height, 0:150]
cv2.imwrite('1.jpg', new_image)
3. 降噪處理 去除小黑點(diǎn),也就是孤立的黑色像素點(diǎn)。
點(diǎn)降噪原理就是檢測(cè)黑色點(diǎn)相鄰的8個(gè)點(diǎn),判斷8個(gè)點(diǎn)的顏色情況。如果全是白點(diǎn),那么就認(rèn)為這個(gè)點(diǎn)是白色的,做黑點(diǎn)變白點(diǎn)處理。如⑤點(diǎn)處,以田字格來看,相鄰共有8個(gè)區(qū)域。
①②③點(diǎn)坐標(biāo)如下圖,同理可知④⑤⑥⑦⑧⑨點(diǎn)坐標(biāo)情況
降噪代碼如下:
import cv2
import numpy as np
from PIL import Image
def inverse_color(image, col_range):
# 讀取圖片,0意味著圖片變?yōu)榛叶葓D
image = cv2.imread(image, 0)
# 圖片二值化,100為設(shè)置閥值,255為最大閥值,1為閥值類型,當(dāng)前點(diǎn)值大于閥值,設(shè)置為0,否則設(shè)置為255。ret是return value縮寫,代表當(dāng)前的閥值
ret, image = cv2.threshold(image, 110, 255, 1)
# 圖片的高度和寬度
height, width = image.shape
# 圖片反色處理,原因:上面的處理只能生成白字黑底的圖片,而我們需要的是黑字白底的圖片
img2 = image.copy()
for i in range(height):
for j in range(width):
img2[i, j] = (255 - image[i, j])
img = np.array(img2)
# 對(duì)處理后的圖片做截取
height, width = img.shape
new_image = img[0:height, col_range[0]:col_range[1]]
cv2.imwrite('handle_one.png', new_image)
image = Image.open('handle_one.png')
return image
def clear_noise(img):
# 圖片降噪處理
x, y = img.width, img.height
for i in range(x):
for j in range(y):
if sum_9_region(img, i, j) < 2:
# 改變像素點(diǎn)顏色,白色
img.putpixel((i, j), 255)
img = np.array(img)
cv2.imwrite('handle_two.png', img)
img = Image.open('handle_two.png')
return img
def sum_9_region(img, x, y):
"""
田字格
"""
# 獲取當(dāng)前像素點(diǎn)的顏色值
cur_pixel = img.getpixel((x, y))
width = img.width
height = img.height
if cur_pixel == 255: # 如果當(dāng)前點(diǎn)為白色區(qū)域,則不統(tǒng)計(jì)鄰域值
return 10
if y == 0: # 第一行
if x == 0: # 左上頂點(diǎn),4鄰域
# 中心點(diǎn)旁邊3個(gè)點(diǎn)
sum_1 = cur_pixel + img.getpixel((x, y + 1)) + img.getpixel((x + 1, y)) + img.getpixel((x + 1, y + 1))
return 4 - sum_1 / 255
elif x == width - 1: # 右上頂點(diǎn)
sum_2 = cur_pixel + img.getpixel((x, y + 1)) + img.getpixel((x - 1, y)) + img.getpixel((x - 1, y + 1))
return 4 - sum_2 / 255
else: # 最上非頂點(diǎn),6鄰域
sum_3 = img.getpixel((x - 1, y)) + img.getpixel((x - 1, y + 1)) + cur_pixel + img.getpixel((x, y + 1)) + img.getpixel((x + 1, y)) + img.getpixel((x + 1, y + 1))
return 6 - sum_3 / 255
elif y == height - 1: # 最下面一行
if x == 0: # 左下頂點(diǎn)
# 中心點(diǎn)旁邊3個(gè)點(diǎn)
sum_4 = cur_pixel + img.getpixel((x + 1, y)) + img.getpixel((x + 1, y - 1)) + img.getpixel((x, y - 1))
return 4 - sum_4 / 255
elif x == width - 1: # 右下頂點(diǎn)
sum_5 = cur_pixel + img.getpixel((x, y - 1)) + img.getpixel((x - 1, y)) + img.getpixel((x - 1, y - 1))
return 4 - sum_5 / 255
else: # 最下非頂點(diǎn),6鄰域
sum_6 = cur_pixel + img.getpixel((x - 1, y)) + img.getpixel((x + 1, y)) + img.getpixel((x, y - 1)) + img.getpixel((x - 1, y - 1)) + img.getpixel((x + 1, y - 1))
return 6 - sum_6 / 255
else: # y不在邊界
if x == 0: # 左邊非頂點(diǎn)
sum_7 = img.getpixel((x, y - 1)) + cur_pixel + img.getpixel((x, y + 1)) + img.getpixel((x + 1, y - 1)) + img.getpixel((x + 1, y)) + img.getpixel((x + 1, y + 1))
return 6 - sum_7 / 255
elif x == width - 1: # 右邊非頂點(diǎn)
sum_8 = img.getpixel((x, y - 1)) + cur_pixel + img.getpixel((x, y + 1)) + img.getpixel((x - 1, y - 1)) + img.getpixel((x - 1, y)) + img.getpixel((x - 1, y + 1))
return 6 - sum_8 / 255
else: # 具備9領(lǐng)域條件的
sum_9 = img.getpixel((x - 1, y - 1)) + img.getpixel((x - 1, y)) + img.getpixel((x - 1, y + 1)) + img.getpixel((x, y - 1)) + cur_pixel + img.getpixel((x, y + 1)) + img.getpixel((x + 1, y - 1)) + img.getpixel((x + 1, y)) + img.getpixel((x + 1, y + 1))
return 9 - sum_9 / 255
def main():
img = '1.jpeg'
img = inverse_color(img, (0, 160))
clear_noise(img)
if __name__ == '__main__':
main()
解決最大的問題后,接下來就是實(shí)現(xiàn)自動(dòng)登陸。首先使用selenium自動(dòng)點(diǎn)擊登陸按鈕。
到登陸界面后,利用selenium自動(dòng)輸入用戶名,密碼,對(duì)驗(yàn)證碼區(qū)域進(jìn)行截圖。而后對(duì)驗(yàn)證碼截圖進(jìn)行處理,最后成功獲取驗(yàn)證碼。
這里為什么是截圖呢,原因是驗(yàn)證碼圖片一直在變化。比如說我現(xiàn)在復(fù)制這個(gè)8863驗(yàn)證碼的圖片鏈接,在新的標(biāo)簽頁打開,會(huì)發(fā)現(xiàn)驗(yàn)證碼改變了,不是8863,而是另外一張驗(yàn)證碼圖片。那么我們通過獲取當(dāng)前頁面的驗(yàn)證碼鏈接,從而來獲取驗(yàn)證碼圖片,這種方法肯定是不可行的。
通過查閱相關(guān)資料,知道了帶cookies訪問驗(yàn)證碼鏈接頁面,能夠成功解決這個(gè)問題。不過由于相關(guān)的庫(kù)沒導(dǎo)入成功,也就放棄了。等下回做驗(yàn)證碼機(jī)器學(xué)習(xí)的時(shí)候,再給予解決。
登陸成功
自動(dòng)登陸代碼如下:
import re
import cv2
import time
import numpy as np
import pytesseract
from PIL import Image
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
USER = '你的用戶名'
PASSWORD = '你的密碼'
browser = webdriver.Chrome()
wait = WebDriverWait(browser, 20)
def inverse_color(image, col_range):...
def clear_noise(img):...
def sum_9_region(img, x, y):...
def auto_login():
"""
實(shí)現(xiàn)網(wǎng)頁自動(dòng)登陸
"""
url = 'http://www.quanben9.com/'
browser.get(url)
# 查找登陸按鈕并點(diǎn)擊
button = browser.find_element_by_css_selector('#top1 > div > a:nth-child(3)')
button.click()
# 查找用戶名輸入框并輸入用戶名
input_first = browser.find_element_by_name('username')
input_first.send_keys(USER)
# 查找密碼輸入框并輸入密碼
input_second = browser.find_element_by_name('password')
input_second.send_keys(PASSWORD)
# 獲取瀏覽器截圖后,手動(dòng)定位驗(yàn)證碼位置,獲得驗(yàn)證碼截圖
browser.save_screenshot('Login_page.png')
photo = Image.open('login_page.png')
box = (1210, 710, 1360, 755)
photo.crop(box).save('Verification.png')
# 對(duì)驗(yàn)證碼進(jìn)行灰度,二值化處理,而后降噪處理
handle_verification_code('Verification.png')
# 對(duì)處理后的驗(yàn)證碼圖片進(jìn)行識(shí)別
image = Image.open('handle_two.png')
image.show()
result = pytesseract.image_to_string(image)
# 畢竟提供的庫(kù)識(shí)別能力有限,不一定能完整得到結(jié)果,需要對(duì)結(jié)果進(jìn)行篩選
result = re.sub('[a-zA-Z’!"#$%&\'()*+,-./:;<=>?@,。?★、…【】《》?“”‘’![\\]^_`{|}~]+', '', result.replace(' ', ''), re.S)
print(result)
# 判斷識(shí)別是否成功
if len(result) == 4:
# 獲得驗(yàn)證碼輸入框并輸入驗(yàn)證碼信息
input_third = browser.find_element_by_name('code')
input_third.send_keys(result)
time.sleep(2)
# 獲得登陸按鈕并點(diǎn)擊
button_2 = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'body > div.main > div > form > ul > li:nth-child(5) > input[type="submit"]')))
button_2.click()
time.sleep(5)
else:
return auto_login()
def handle_verification_code(img):
img = inverse_color(img, (0, 160))
img = clear_noise(img)
return img
def main():
auto_login()
if __name__ == '__main__':
main()
# 結(jié)束程序
exit()
工程師必備
- 項(xiàng)目客服
- 培訓(xùn)客服
- 平臺(tái)客服
TOP




















