当前位置: 首页 > 后端技术 > Python

Python+scrapy爬虫:手绘验证码识别

时间:2023-03-26 13:10:06 Python

一、介绍今天主要介绍微博客户端登录时出现的四方手绘验证码,话不多说,看看验证码长什么样喜欢。二、思路1、由于微博上的手绘验证码只有四个格子,而每个格子之间都有有向线段连接,因此我们可以判断出四个格子的不同方向有24种验证码,我们对四个格子进行标注,结果如下:那么我们可以排列出24个不同的手绘验证码,分别是下面的24种。2、我们从微博客户端获取了24个手绘验证码最后需要进行模板匹配,所以滑动是通过全图匹配进行的。三、代码实现1、首先需要通过微博移动端(https://passport.weibo.cn/sig...)批量获取手绘验证码,但是这个验证码不一定出现,只有当账户有风险或者经常登录的时候才会出现。获取手绘验证码的代码如下:注意:发送用户名和密码前需要加载模拟浏览器的所有元素(用户名框、密码框),否则会报错#-*-编码:utf-8-*-从io导入BytesIO从PIL导入图像从selenium导入webdriver从selenium.webdriver.common.by导入Byfromselenium.common.exceptions从selenium.webdriver.support.ui导入TimeoutException从selenium.webdriver.support导入WebDriverWaitimportexpected_conditionsasECclassCrackWeiboSlide():def__init__(self):self.url="https://passport.weibo.cn/signin/login?entry=mweibo&r=https://m.weibo.cn/"self.browser=webdriver.Chrome(r"D:\chromedriver.exe")self.browser.maximize_window()self.wait=WebDriverWait(self.browser,5)def__del__(self):self.browser.close()def打开(self):#打开模拟浏览器self.browser.get(self.url)#获取用户名元素username=self.wait.until(EC.presence_of_element_located((By.XPATH,'//*[@id="loginName"]')))#获取密码框元素password=self.wait.uuntil(EC.presence_of_element_located((By.XPATH,'//*[@id="loginPassword"]')))#获取登录按钮元素submit=self.wait.until(EC.element_to_be_clickable((By.XPATH,'//*[@id="loginAction"]')))#提交数据并登录username.send_keys("15612345678")password.send_keys("xxxxxxxxxxxx")submit.click()defget_image(self,name="captcha.png"):try:#获取验证码imageelementimg=self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,"patt-shadow")))time.sleep(1)#获取验证码codeimagelocationlocationlocation=img.location#获取验证码图片的大小size=img.sizetop=location["y"]#upperbottom=location["y"]+size["height"]#lowerleft=location["x"]#Leftright=location["x"]+size["width"]#Rightprint("验证码位置:",left,top,right,bottom)#截图当前窗口截图=self.browser.get_screenshot_as_png()#读取截图screenshot=Image.open(BytesIO(screenshot))#截取九宫格图片验证码captcha=screenshot.crop((left,top,right,bottom))#将截取的九宫格验证码保存到指定位置captcha.save(name)print("微博登录验证码已保存!!!")returncaptchaexceptTimeoutException:print("没有验证码!!!")#回调打开模拟浏览器函数self.open()defmain(self):count=1whileTrue:#调用打开模拟浏览器函数self.open()#调用函数获取验证码图片self.get_image(str(count)+".png")count+=1if__name__=='__main__':crack=CrackWeiboSlide()crack.main()得到的24种手绘验证码,这些手绘验证码需要按照上面的数字命名。上图就是我们需要的模板,接下来我们就要遍历模板匹配2.模板匹配可以通过遍历手绘验证码模板来匹配selenium.webdriver.common.byimportByfromselenium.common.exceptionsimportTimeoutExceptionfromselenium.webdriver.support.uiimportWebDriverWaitfromselenium.webdriver.supportimportexpected_conditionsasECclassCrackWeiboSlide():def__init__(self):self.url="https://passport.weibo.cn/signin/login?entry=mweibo&r=https://m.weibo.cn/"self.browser=webdriver.Chrome(r"D:\chromedriver.exe")self.browser.maximize_window()self.wait=WebDriverWait(self.browser,5)def__del__(self):self.browser.close()defopen(self):#打开模拟浏览器self.browser.get(self.url)#获取用户名元素username=self.wait.until(EC.presence_of_element_located((By.XPATH,'//*[@id="loginName"]')))#获取密码框元素password=self.wait.until(EC.presence_of_element_located((By.XPATH,'//*[@id="loginPassword"]')))#获取登录按钮元素submit=self.wait.until(EC.element_to_be_clickable((By.XPATH,'//*[@id="loginAction"]')))#提交数据登录username.send_keys("15612345678")password.send_keys("xxxxxxxxxxxx")submit.click()defget_image(self,name="captcha.png"):try:#获取验证码图像元素img=self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,"patt-shadow")))time.sleep(1)#获取验证码图片位置location=img.location#获取验证码图片大小size=img.sizetop=location["y"]#Topbottom=location["y"]+size["height"]#Bottomleft=location["x"]#Leftright=location["x"]+size["width"]#Rightprint("验证码位置:",left,top,right,bottom)#当前窗口截图screenshot=self.browser.get_screenshot_as_png()#读取截图screenshot=Image.open(BytesIO(screenshot))#截取九宫格图片验证码captcha=screenshot.crop((left,top,right,bottom))#将截取的九宫格验证码保存到指定位置captcha.save(name)print("微博登录验证码已保存!!!")#返回微博手机端验证码图片returncaptchaexceptTimeoutException:print("没有验证码!!")#回调打开模拟浏览器功能self.open()defis_pixel_equal(self,image,template,i,j):#取出两张图片的像素pixel1=image.load()[i,j]#手机客户端获取的验证码pixel2=template.load()[i,j]#模板文件中的验证码threshold=20#thresholdpix_r=abs(pixel1[0]-pixel2[0])#Rpix_g=abs(pixel1[1]-pixel2[1])#Gpix_b=abs(pixel1[2]-pixel2[2])#Bif(pix_rthreshold:print("匹配成功!!!")returnTrueelse:returnFalsedefdetect_image(self,image):#遍历手绘验证代码模板文件fortemplate_nameinos.listdir(r"D:\photo\templates")中的所有验证码图片:print("matching",template_name)#打开验证码图片template=Image.open(r"D:\photo\templates\{}".format(template_name))ifself.same_image(image,template):#返回这张图片的顺序,比如4—>3—>1—>2numbers=[int(number)fornumberinlist(template_name.split(".")[0])]print("按顺序拖动",numbers)returnnumbersdefmove(self,numbers):#逐点得到四个圆=self.browser.find_element_by_css_selector('.patt-wrap.patt-circ')dx=dy=0#因为有四个格子,需要循环四次forindexinrange(4):circle=circles[numbers[index]-1]#如果是第一个循环ifindex==0:#点击第一个点action=ActionChains(self.browser).move_to_element_with_offset(circle,circle.size["width"]/2,circle.size['height']/2)action.click_and_hold().perform()else:#Smallmovementtimestimes=30#Dragforiinrange(times):ActionChains(self.browser).move_by_offset(dx/times,dy/times).perform()time.sleep(1/times)#如果是最后一个循环ifindex==3:#释放鼠标ActionChains(self.browser).release().perform()else:#CalculateOnceoffsetdx=circles[numbers[index+1]-1].location['x']-circle.location['x']dy=circles[numbers[index+1]-1].location['y']-circle.location['y']defmain(self):#callopen模拟浏览器函数self.open()image=self.get_image("captcha.png")#微博手机验证码图片numbers=self.detect_image(image)self.move(numbers)time.sleep(10)print('识别结束')if__name__=='__main__':crack=CrackWeiboSlide()crack.main()4.识别结果循环四次后绘制四个方向,最终得到效果图和文字源网络,仅供学习使用,如有侵权联系删除。我的公众号【Python圈】汇集了优质的技术文章和经验总结。学习Python的路上肯定会遇到困难,不要慌张,我这里有一套学习资料,包括40+电子书,600+教学视频,涉及Python基础、爬虫、框架、数据分析、机学习等等,别怕学不会!