基于Pytorch版yolov5的滑块验证码破解思路详解
前言
本文将使用pytorch框架的目标识别技术实现滑块验证码的破解。我们这里选择了yolov5算法
例:输入图像
输出图像
可以看到经过检测之后,我们能很准确的定位到缺口的位置,并且能得到缺口的坐标,这样一来我们就能很轻松的实现滑动验证码的破解。
一.前期工作
yolov系列是常用的目标检测算法,yolov5不仅配置简单,而且在速度上也有不小的提升,我们很容易就能训练我们自己的数据集。
YOLOV5Pytorch版本GIthub网址感谢这位作者的代码。
下载之后,是这样的格式
---data/ Annotations/存放图片的标注文件(.xml) images/存放待训练的图片 ImageSets/存放划分数据集的文件 labels/存放图片的方框信息
其中只需要修改Annotations和images两个文件夹。
首先我们将待训练的图片放入images
数据集要感谢这位大神的整理https://github.com/tzutalin/labelImg,在这个基础上我增加了50张来自腾讯的验证码图片
数据集已上传百度云
链接:https://pan.baidu.com/s/1XS5KVoXqGHglfP0mZ3HJLQ
提取码:wqi8
然后我们需要对其进行标注,告诉计算机我们希望它识别什么内容。这时候我们需要精灵标注这款软件。免费而且功能强大,五星好评!
第一步选择images文件夹,第二步有几类就写几类,建议用英文。这里只有一类,即为缺失快的位置,命名为target。注意标注的时候要左右恰好卡住,不然获得的坐标就不精准。
标注完成后,点击导出,文件格式不用动,直接点确定,就会在images/outputs文件夹生成我们的标注文件。全部复制到Annotations文件夹即可。
回到主目录,运行makeTxt.py和voc_label.py,makeTxt直接运行即可,voc_label需要修改classes的值,这次只有一target
importxml.etree.ElementTreeasET importpickle importos #os.listdir()方法用于返回指定的文件夹包含的文件或文件夹的名字的列表 fromosimportlistdir,getcwd fromos.pathimportjoin sets=['train','test','val'] classes=['target']#之前标注时有几个类,这里就输入几个类 """ ............ """
进入data文件夹,修改coco.yaml的内容
#COCO2017datasethttp://cocodataset.org #Downloadcommand:bashyolov5/data/get_coco2017.sh #Traincommand:pythontrain.py--data./data/coco.yaml #Datasetshouldbeplacednexttoyolov5folder: #/parent_folder #/coco #/yolov5 #trainandvaldatasets(imagedirectoryor*.txtfilewithimagepaths) train:../coco/train2017.txt#118kimages val:../coco/val2017.txt#5kimages test:../coco/test-dev2017.txt#20kimagesforsubmissiontohttps://competitions.codalab.org/competitions/20794 #numberofclasses nc:1 #classnames names:['target'] #Printclasses #withopen('data/coco.yaml')asf: #d=yaml.load(f,Loader=yaml.FullLoader)#dict #fori,xinenumerate(d['names']): #print(i,x)
再进入models文件夹,修改yolov5s.yaml的内容
nc:1#numberofclasses depth_multiple:0.33#modeldepthmultiple width_multiple:0.50#layerchannelmultiple """ '''''''''''' """
至此配置环节终于结束了,可以开始训练了!
打开train.py,我们一般只需要修改–weights,–cfg,–data,–epochs几个设置即可
parser=argparse.ArgumentParser() parser.add_argument('--weights',type=str,default='yolov5s.pt',help='initialweightspath') parser.add_argument('--cfg',type=str,default='models/yolov5s.yaml',help='model.yamlpath') parser.add_argument('--data',type=str,default='data/coco.yaml',help='data.yamlpath') parser.add_argument('--hyp',type=str,default='data/hyp.scratch.yaml',help='hyperparameterspath') parser.add_argument('--epochs',type=int,default=300) parser.add_argument('--batch-size',type=int,default=16,help='totalbatchsizeforallGPUs') parser.add_argument('--img-size',nargs='+',type=int,default=[640,640],help='[train,test]imagesizes') parser.add_argument('--rect',action='store_true',help='rectangulartraining') parser.add_argument('--resume',nargs='?',const=True,default=False,help='resumemostrecenttraining') parser.add_argument('--nosave',action='store_true',help='onlysavefinalcheckpoint') parser.add_argument('--notest',action='store_true',help='onlytestfinalepoch') parser.add_argument('--noautoanchor',action='store_true',help='disableautoanchorcheck') parser.add_argument('--evolve',action='store_true',help='evolvehyperparameters') parser.add_argument('--bucket',type=str,default='',help='gsutilbucket') parser.add_argument('--cache-images',action='store_true',help='cacheimagesforfastertraining') parser.add_argument('--image-weights',action='store_true',help='useweightedimageselectionfortraining') parser.add_argument('--device',default='',help='cudadevice,i.e.0or0,1,2,3orcpu') parser.add_argument('--multi-scale',action='store_true',help='varyimg-size+/-50%%') parser.add_argument('--single-cls',action='store_true',help='trainmulti-classdataassingle-class') parser.add_argument('--adam',action='store_true',help='usetorch.optim.Adam()optimizer') parser.add_argument('--sync-bn',action='store_true',help='useSyncBatchNorm,onlyavailableinDDPmode') parser.add_argument('--local_rank',type=int,default=-1,help='DDPparameter,donotmodify') parser.add_argument('--log-imgs',type=int,default=16,help='numberofimagesforW&Blogging,max100') parser.add_argument('--log-artifacts',action='store_true',help='logartifacts,i.e.finaltrainedmodel') parser.add_argument('--workers',type=int,default=4,help='maximumnumberofdataloaderworkers') parser.add_argument('--project',default='runs/train',help='savetoproject/name') parser.add_argument('--name',default='exp',help='savetoproject/name') parser.add_argument('--exist-ok',action='store_true',help='existingproject/nameok,donotincrement') opt=parser.parse_args()
直接运行train.py,开始训练!
。。。。。。。。。。。。。。。。
训练完成后,进入runs/train/exp/weights,我们复制best.pt到主目录。
最后,我们打开datect.py,修改几个属性
parser=argparse.ArgumentParser() parser.add_argument('--weights',nargs='+',type=str,default='best.pt',help='model.ptpath(s)') parser.add_argument('--source',type=str,default='test.jpg',help='source')#file/folder,0forwebcam parser.add_argument('--img-size',type=int,default=640,help='inferencesize(pixels)') parser.add_argument('--conf-thres',type=float,default=0.25,help='objectconfidencethreshold') parser.add_argument('--iou-thres',type=float,default=0.45,help='IOUthresholdforNMS') parser.add_argument('--device',default='0',help='cudadevice,i.e.0or0,1,2,3orcpu') parser.add_argument('--view-img',action='store_true',help='displayresults') parser.add_argument('--save-txt',action='store_true',help='saveresultsto*.txt') parser.add_argument('--save-conf',action='store_true',help='saveconfidencesin--save-txtlabels') parser.add_argument('--classes',nargs='+',type=int,help='filterbyclass:--class0,or--class023') parser.add_argument('--agnostic-nms',action='store_true',help='class-agnosticNMS') parser.add_argument('--augment',action='store_true',help='augmentedinference') parser.add_argument('--update',action='store_true',help='updateallmodels') parser.add_argument('--project',default='runs/detect',help='saveresultstoproject/name') parser.add_argument('--name',default='exp',help='saveresultstoproject/name') parser.add_argument('--exist-ok',action='store_true',help='existingproject/nameok,donotincrement') opt=parser.parse_args()
–source属性我们可以先修改为data/images,对自己的数据集进行识别看看能否正常识别。
小Tips,如果执行后不报错,但没有检测框的话,试试看修改–device为cpu,cuda版本太低会导致使用gpu没有检测框(问就是被这个小问题迫害了很久--_–)。
最后在112行左右的位置,添加一个print
这时执行程序就会返回方框的位置信息和自信度了
我们的前驱工作终于完成了~
二.编写爬虫
1.寻找合适的网站
经过一番搜寻,最后锁定了https://007.qq.com/online.html
因为它的网站结构很方便我们的操作。
2.导入依赖库
这里我们采用selenium来模拟人类的操作。
关于selenium的安装和webdriver的安装方法本文不作延伸。
fromseleniumimportwebdriver fromselenium.webdriver.common.action_chainsimportActionChains importrequests,re importos importrequests importre importtime fromselenium.webdriverimportActionChains
3.编写破解程序
访问网站,发现破解之前要依次点击
编写代码
defrun() driver=webdriver.Chrome() headers={"User-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/80.0.3987.106Safari/537.36"} #伪装请求头 driver.get('https://007.qq.com/online.html')#访问网站 driver.find_element_by_xpath('/html/body/div[1]/section[1]/div/div/div/div[2]/div[1]/a[2]').click() driver.find_element_by_xpath('//*[@id="code"]').click() #模拟点击操作
继续
这里便是我们要识别的图片,不过直接定位的话并不能定位到,因为这段代码是由iframe包裹着的,我们需要先定位到这个iframe
time.sleep(2)#休眠2秒,防止报错 driver.switch_to_frame("tcaptcha_iframe")#根据iframe的id定位到iframe target=driver.find_element_by_xpath("/html/body/div/div[3]/div[2]/div[1]/div[2]/img").get_attribute("src") #得到图片的原地址 response=requests.get(target,headers=headers) #访问图片地址 img=response.content withopen('test.jpg','wb')asf: f.write(img) #将图片保存到主目录,命名为test.jpg
现在图片也有了,检测程序也准备好了,那么开始检测吧!
''' os.popen()的用法,简单来说就是执行cmd命令,并得到cmd的返回值 这里是执行detect.py ''' result=os.popen("pythondetect.py").readlines()#执行目标检测程序 list=[] forlineinresult: list.append(line)#将cmd的返回信息存入列表 print(list) a=re.findall("(.*):(.*]).(.*)\\n",list[-4])#获得图片的位置信息 print(a) print(len(a)) iflen(a)!=0:#如果能检测到方框 tensor=a[0][1] pro=a[0][2] list_=tensor[2:-1].split(",") location=[] foriinlist_: print(i) b=re.findall("tensor(.*)",i)[0] location.append(b[1:-2]) #提取出来方框左上角的xy和右下角的xy drag1=driver.find_element_by_xpath('/html/body/div/div[3]/div[2]/div[2]/div[2]/div[1]') #定位到拖动按钮处 action_chains=ActionChains(driver)#实例化鼠标操作类 action_chains.drag_and_drop_by_offset(drag1,int(int(location[2])/2-85),0).perform() #模拟鼠标按住并拖动距离X后再放开 input("等待操作") driver.quit() else: driver.quit() print("未能识别")
这里着重说一下
action_chains.drag_and_drop_by_offset(drag1,int(int(location[2])/2-85),0).perform()
为什么要拖int(int(location[2])/2-85)远。
首先location这个列表的格式为[左上x,左上y,右下x,右下y],location[2]即为取出右下角的x值。
我们保存到本地的验证码图片分辨率如下
但网站显示的图片大小
x轴刚好为本地图片的一半,所以int(location[2]/2)得到的便是
但是待拖动的方块本身距离左边还有一定距离,通过分析发现
这个小方块的最左边距离图片的最左边的距离即为红框中的26,即
26+68-10=84,因为这个10是试出来的长度,我们就令这段距离为85吧
至此int(int(location[2])/2-85)的由来也解释清楚了。
大功告成啦,那让我们看一遍演示吧!
selenium完整代码如下
fromseleniumimportwebdriver fromselenium.webdriver.common.action_chainsimportActionChains importrequests,re importos importrequests importre importtime fromselenium.webdriverimportActionChains defrun() driver=webdriver.Chrome() headers={"User-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/80.0.3987.106Safari/537.36"} #伪装请求头 driver.get('https://007.qq.com/online.html')#访问网站 driver.find_element_by_xpath('/html/body/div[1]/section[1]/div/div/div/div[2]/div[1]/a[2]').click() driver.find_element_by_xpath('//*[@id="code"]').click() #模拟点击操作 time.sleep(2)#休眠2秒,防止报错 driver.switch_to_frame("tcaptcha_iframe")#根据iframe的id定位到iframe target=driver.find_element_by_xpath("/html/body/div/div[3]/div[2]/div[1]/div[2]/img").get_attribute("src") #得到图片的原地址 response=requests.get(target,headers=headers) #访问图片地址 img=response.content withopen('test.jpg','wb')asf: f.write(img) #将图片保存到主目录,命名为test.jpg ''' os.popen()的用法,简单来说就是执行cmd命令,并得到cmd的返回值 这里是执行detect.py ''' result=os.popen("pythondetect.py").readlines()#执行目标检测程序 list=[] forlineinresult: list.append(line)#将cmd的返回信息存入列表 print(list) a=re.findall("(.*):(.*]).(.*)\\n",list[-4])#获得图片的位置信息 print(a) print(len(a)) iflen(a)!=0:#如果能检测到方框 tensor=a[0][1] pro=a[0][2] list_=tensor[2:-1].split(",") location=[] foriinlist_: print(i) b=re.findall("tensor(.*)",i)[0] location.append(b[1:-2]) #提取出来方框左上角的xy和右下角的xy drag1=driver.find_element_by_xpath('/html/body/div/div[3]/div[2]/div[2]/div[2]/div[1]') #定位到拖动按钮处 action_chains=ActionChains(driver)#实例化鼠标操作类 action_chains.drag_and_drop_by_offset(drag1,int(int(location[2])/2-85),0).perform() #模拟鼠标按住并拖动距离X后再放开 input("等待操作") driver.quit() else: driver.quit() print("未能识别") whileTrue: run()
到此这篇关于基于Pytorch版yolov5的滑块验证码破解思路详解的文章就介绍到这了,更多相关Pytorch滑块验证码破解内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。