基於Pytorch版yolov5的滑塊驗證碼破解思路詳解
前言
本文將使用pytorch框架的目標識別技術實現滑塊驗證碼的破解。我們這裡選擇瞭yolov5算法
例:輸入圖像
輸出圖像
可以看到經過檢測之後,我們能很準確的定位到缺口的位置,並且能得到缺口的坐標,這樣一來我們就能很輕松的實現滑動驗證碼的破解。
一.前期工作
yolov系列是常用的目標檢測算法,yolov5不僅配置簡單,而且在速度上也有不小的提升,我們很容易就能訓練我們自己的數據集。
YOLOV5 Pytorch版本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
import xml.etree.ElementTree as ET import pickle import os # os.listdir() 方法用於返回指定的文件夾包含的文件或文件夾的名字的列表 from os import listdir, getcwd from os.path import join sets = ['train', 'test', 'val'] classes = ['target'] #之前標註時有幾個類,這裡就輸入幾個類 """ ............ """
進入data文件夾,修改coco.yaml的內容
# COCO 2017 dataset http://cocodataset.org # Download command: bash yolov5/data/get_coco2017.sh # Train command: python train.py --data ./data/coco.yaml # Dataset should be placed next to yolov5 folder: # /parent_folder # /coco # /yolov5 # train and val datasets (image directory or *.txt file with image paths) train: ../coco/train2017.txt # 118k images val: ../coco/val2017.txt # 5k images test: ../coco/test-dev2017.txt # 20k images for submission to https://competitions.codalab.org/competitions/20794 # number of classes nc: 1 # class names names: ['target'] # Print classes # with open('data/coco.yaml') as f: # d = yaml.load(f, Loader=yaml.FullLoader) # dict # for i, x in enumerate(d['names']): # print(i, x)
再進入models文件夾,修改yolov5s.yaml的內容
nc: 1 # number of classes depth_multiple: 0.33 # model depth multiple width_multiple: 0.50 # layer channel multiple """ '''''''''''' """
至此配置環節終於結束瞭,可以開始訓練瞭!
打開train.py,我們一般隻需要修改–weights,–cfg,–data,–epochs幾個設置即可
parser = argparse.ArgumentParser() parser.add_argument('--weights', type=str, default='yolov5s.pt', help='initial weights path') parser.add_argument('--cfg', type=str, default='models/yolov5s.yaml', help='model.yaml path') parser.add_argument('--data', type=str, default='data/coco.yaml', help='data.yaml path') parser.add_argument('--hyp', type=str, default='data/hyp.scratch.yaml', help='hyperparameters path') parser.add_argument('--epochs', type=int, default=300) parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs') parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='[train, test] image sizes') parser.add_argument('--rect', action='store_true', help='rectangular training') parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') parser.add_argument('--notest', action='store_true', help='only test final epoch') parser.add_argument('--noautoanchor', action='store_true', help='disable autoanchor check') parser.add_argument('--evolve', action='store_true', help='evolve hyperparameters') parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') parser.add_argument('--cache-images', action='store_true', help='cache images for faster training') parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') parser.add_argument('--adam', action='store_true', help='use torch.optim.Adam() optimizer') parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify') parser.add_argument('--log-imgs', type=int, default=16, help='number of images for W&B logging, max 100') parser.add_argument('--log-artifacts', action='store_true', help='log artifacts, i.e. final trained model') parser.add_argument('--workers', type=int, default=4, help='maximum number of dataloader workers') parser.add_argument('--project', default='runs/train', help='save to project/name') parser.add_argument('--name', default='exp', help='save to project/name') parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') 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.pt path(s)') parser.add_argument('--source', type=str, default='test.jpg', help='source') # file/folder, 0 for webcam parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)') parser.add_argument('--conf-thres', type=float, default=0.25, help='object confidence threshold') parser.add_argument('--iou-thres', type=float, default=0.45, help='IOU threshold for NMS') parser.add_argument('--device', default='0', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') parser.add_argument('--view-img', action='store_true', help='display results') parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3') parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') parser.add_argument('--augment', action='store_true', help='augmented inference') parser.add_argument('--update', action='store_true', help='update all models') parser.add_argument('--project', default='runs/detect', help='save results to project/name') parser.add_argument('--name', default='exp', help='save results to project/name') parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') 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的安裝方法本文不作延伸。
from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains import requests,re import os import requests import re import time from selenium.webdriver import ActionChains
3.編寫破解程序
訪問網站,發現破解之前要依次點擊
編寫代碼
def run() driver = webdriver.Chrome() headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.106 Safari/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 with open( 'test.jpg','wb' ) as f: f.write(img) #將圖片保存到主目錄,命名為test.jpg
現在圖片也有瞭,檢測程序也準備好瞭,那麼開始檢測吧!
''' os.popen()的用法,簡單來說就是執行cmd命令,並得到cmd的返回值 這裡是執行detect.py ''' result = os.popen("python detect.py").readlines() #執行目標檢測程序 list = [] for line in result: list.append(line) #將cmd的返回信息存入列表 print(list) a = re.findall("(.*):(.*]).(.*)\\n",list[-4]) #獲得圖片的位置信息 print(a) print(len(a)) if len(a) != 0: #如果能檢測到方框 tensor=a[0][1] pro = a[0][2] list_=tensor[2:-1].split(",") location = [] for i in list_: 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完整代碼如下
from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains import requests,re import os import requests import re import time from selenium.webdriver import ActionChains def run() driver = webdriver.Chrome() headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.106 Safari/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 with open( 'test.jpg','wb' ) as f: f.write(img) #將圖片保存到主目錄,命名為test.jpg ''' os.popen()的用法,簡單來說就是執行cmd命令,並得到cmd的返回值 這裡是執行detect.py ''' result = os.popen("python detect.py").readlines() #執行目標檢測程序 list = [] for line in result: list.append(line) #將cmd的返回信息存入列表 print(list) a = re.findall("(.*):(.*]).(.*)\\n",list[-4]) #獲得圖片的位置信息 print(a) print(len(a)) if len(a) != 0: #如果能檢測到方框 tensor=a[0][1] pro = a[0][2] list_=tensor[2:-1].split(",") location = [] for i in list_: 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("未能識別") while True: run()
到此這篇關於基於Pytorch版yolov5的滑塊驗證碼破解思路詳解的文章就介紹到這瞭,更多相關Pytorch滑塊驗證碼破解內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- python深度學習標準庫使用argparse調參
- Python命令行解析器argparse詳解
- Python Parser的用法
- Python實現解析參數的三種方法詳解
- Python argparse庫的基本使用步驟