小編今天準(zhǔn)備爬取一個(gè)網(wǎng)站的數(shù)據(jù)鸟整,但是被登錄的驗(yàn)證碼擋住了
小編很不服
于是小編就想著怎么繞過驗(yàn)證碼去爬取網(wǎng)站的數(shù)據(jù)引镊。
學(xué)習(xí)Python過程中會遇到很多問題,可以到我們的 python學(xué)習(xí)交流群【七 三 五篮条,九 三 四弟头,八 四 一】,基礎(chǔ)涉茧,進(jìn)階赴恨。從企業(yè)招聘人才需求 到怎么學(xué)習(xí)python,和學(xué)習(xí)什么內(nèi)容都有免費(fèi)系統(tǒng)分享伴栓。希望可以幫助你快速了解Python伦连,學(xué)習(xí)python
雖說圖形驗(yàn)證碼最簡單,但是對于我這等新手钳垮,還是要苦學(xué)一番惑淳。首先尋找測試網(wǎng)站,網(wǎng)站選的是如云閣小說網(wǎng)饺窿,小網(wǎng)站不怕被封汛聚。他們的驗(yàn)證碼一般如下:
可以看出有微弱的干擾線和較強(qiáng)的干擾點(diǎn),驗(yàn)證碼是沒有邊框的短荐,這里為了排版好看,我加上去的...
1.灰度處理? ?把彩色驗(yàn)證碼圖片轉(zhuǎn)為灰色的圖片叹哭。
importcv2
image?=?cv2.imread('1.jpeg',0)
cv2.imwrite('1.jpg',?image)
2.?二值化處理? ?將圖片處理為只有黑白兩色的圖片忍宋,這里發(fā)現(xiàn)干擾線沒有了,這就意味著我們只需要處理干擾點(diǎn)即可风罩。
importcv2
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)降噪原理就是檢測黑色點(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)情況
降噪代碼如下:
importcv2
importnumpyasnp
fromPILimportImage
definverse_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()
foriinrange(height):
forjinrange(width):
img2[i,?j]?=?(255-?image[i,?j])
img?=?np.array(img2)
#?對處理后的圖片做截取
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')
returnimage
defclear_noise(img):
#?圖片降噪處理
x,?y?=?img.width,?img.height
foriinrange(x):
forjinrange(y):
ifsum_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')
returnimg
defsum_9_region(img,?x,?y):
"""
田字格
"""
#?獲取當(dāng)前像素點(diǎn)的顏色值
cur_pixel?=?img.getpixel((x,?y))
width?=?img.width
height?=?img.height
ifcur_pixel?==255:#?如果當(dāng)前點(diǎn)為白色區(qū)域,則不統(tǒng)計(jì)鄰域值
return10
ify?==0:#?第一行
ifx?==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))
return4-?sum_1?/255
elifx?==?width?-1:#?右上頂點(diǎn)
sum_2?=?cur_pixel?+?img.getpixel((x,?y?+1))?+?img.getpixel((x?-1,?y))?+?img.getpixel((x?-1,?y?+1))
return4-?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))
return6-?sum_3?/255
elify?==?height?-1:#?最下面一行
ifx?==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))
return4-?sum_4?/255
elifx?==?width?-1:#?右下頂點(diǎn)
sum_5?=?cur_pixel?+?img.getpixel((x,?y?-1))?+?img.getpixel((x?-1,?y))?+?img.getpixel((x?-1,?y?-1))
return4-?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))
return6-?sum_6?/255
else:#?y不在邊界
ifx?==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))
return6-?sum_7?/255
elifx?==?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))
return6-?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))
return9-?sum_9?/255
defmain():
img?='1.jpeg'
img?=?inverse_color(img,?(0,160))
clear_noise(img)
if__name__?=='__main__':
main()
解決最大的問題后,接下來就是實(shí)現(xiàn)自動登陸荠割。首先使用selenium自動點(diǎn)擊登陸按鈕妹卿。
到登陸界面后,利用selenium自動輸入用戶名蔑鹦,密碼夺克,對驗(yàn)證碼區(qū)域進(jìn)行截圖。而后對驗(yàn)證碼截圖進(jìn)行處理嚎朽,最后成功獲取驗(yàn)證碼铺纽。
這里為什么是截圖呢,原因是驗(yàn)證碼圖片一直在變化哟忍。比如說我現(xiàn)在復(fù)制這個(gè)8863驗(yàn)證碼的圖片鏈接狡门,在新的標(biāo)簽頁打開,會發(fā)現(xiàn)驗(yàn)證碼改變了锅很,不是8863其馏,而是另外一張驗(yàn)證碼圖片。那么我們通過獲取當(dāng)前頁面的驗(yàn)證碼鏈接爆安,從而來獲取驗(yàn)證碼圖片叛复,這種方法肯定是不可行的。
通過查閱相關(guān)資料扔仓,知道了帶cookies訪問驗(yàn)證碼鏈接頁面褐奥,能夠成功解決這個(gè)問題。不過由于相關(guān)的庫沒導(dǎo)入成功翘簇,也就放棄了撬码。等下回做驗(yàn)證碼機(jī)器學(xué)習(xí)的時(shí)候,再給予解決缘揪。
登陸成功
自動登陸代碼如下:
importre
importcv2
importtime
importnumpyasnp
importpytesseract
fromPILimportImage
fromseleniumimportwebdriver
fromselenium.webdriver.common.byimportBy
fromselenium.webdriver.support.uiimportWebDriverWait
fromselenium.webdriver.supportimportexpected_conditionsasEC
USER?='你的用戶名'
PASSWORD?='你的密碼'
browser?=?webdriver.Chrome()
wait?=?WebDriverWait(browser,20)
definverse_color(image,?col_range):...
defclear_noise(img):...
defsum_9_region(img,?x,?y):...
defauto_login():
"""
實(shí)現(xiàn)網(wǎ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)
#?獲取瀏覽器截圖后耍群,手動定位驗(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')
#?對驗(yàn)證碼進(jìn)行灰度,二值化處理蹈垢,而后降噪處理
handle_verification_code('Verification.png')
#?對處理后的驗(yàn)證碼圖片進(jìn)行識別
image?=?Image.open('handle_two.png')
image.show()
result?=?pytesseract.image_to_string(image)
#?畢竟提供的庫識別能力有限慷吊,不一定能完整得到結(jié)果,需要對結(jié)果進(jìn)行篩選
result?=?re.sub('[a-zA-Z’!"#$%&'()*+,-./:;<=>?@曹抬,溉瓶。?★、…【】《》谤民?“”‘’堰酿![\]^_`{|}~]+','',?result.replace('?',''),?re.S)
print(result)
#?判斷識別是否成功
iflen(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:
returnauto_login()
defhandle_verification_code(img):
img?=?inverse_color(img,?(0,160))
img?=?clear_noise(img)
returnimg
defmain():
auto_login()
if__name__?=='__main__':
main()
#?結(jié)束程序
exit()
這里用會聲會影給視頻加了個(gè)BGM,不過結(jié)尾的時(shí)候不是很搭张足,水平有限吶触创!還是得好好多學(xué)習(xí)。