首頁>技術>

前言

本文將使用pytorch框架的目標識別技術實現滑塊驗證碼的破解。我們這裡選擇了yolov5演算法

例:輸入影象

輸出影象

可以看到經過檢測之後,我們能很準確的定位到缺口的位置,並且能得到缺口的座標,這樣一來我們就能很輕鬆的實現滑動驗證碼的破解。

一.前期工作

yolov系列是常用的目標檢測演算法,yolov5不僅配置簡單,而且在速度上也有不小的提升,我們很容易就能訓練我們自己的資料集。YOLOV5 Pytorch版本GIthub網址感謝這位作者的程式碼。

下載之後,是這樣的格式

---data/	Annotations/ 存放圖片的標註檔案(.xml)	images/ 存放待訓練的圖片	ImageSets/ 存放劃分資料集的檔案	labels/ 存放圖片的方框資訊12345

其中只需要修改Annotations和images兩個資料夾。首先我們將待訓練的圖片放入images

資料集要感謝這位大神的整理https://github.com/tzutalin/labelImg,在這個基礎上我增加了50張來自騰訊的驗證碼圖片

資料集已上傳百度雲

連結:https://pan.baidu.com/s/1Ny_KUm1LhsLdLrKAVQH2XA提取碼:4v79

然後我們需要對其進行標註,告訴計算機我們希望它識別什麼內容。這時候我們需要精靈標註這款軟體。免費而且功能強大,五星好評!

第一步選擇images資料夾,第二步有幾類就寫幾類,建議用英文。這裡只有一類,即為缺失快的位置,命名為target。注意標註的時候要左右恰好卡住,不然獲得的座標就不精準。

回到主目錄,執行makeTxt.py和voc_label.py,makeTxt直接執行即可,voc_label需要修改classes的值,這次只有一target

import xml.etree.ElementTree as ETimport pickleimport os# os.listdir() 方法用於返回指定的資料夾包含的檔案或資料夾的名字的列表from os import listdir, getcwdfrom os.path import joinsets = ['train', 'test', 'val']classes = ['target']  #之前標註時有幾個類,這裡就輸入幾個類"""............   """12345678910111213141516

進入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 imagesval: ../coco/val2017.txt  # 5k imagestest: ../coco/test-dev2017.txt  # 20k images for submission to https://competitions.codalab.org/competitions/20794# number of classesnc: 1# class namesnames: ['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)12345678910111213141516171819202122232425

再進入models資料夾,修改yolov5s.yaml的內容

nc: 1  # number of classesdepth_multiple: 0.33  # model depth multiplewidth_multiple: 0.50  # layer channel multiple"""''''''''''''"""123456

至此配置環節終於結束了,可以開始訓練了!

開啟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()12345678910111213141516171819202122232425262728293031

直接執行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()123456789101112131415161718

–source屬性我們可以先修改為data/images,對自己的資料集進行識別看看能否正常識別。小Tips,如果執行後不報錯,但沒有檢測框的話,試試看修改–device為cpu,cuda版本太低會導致使用gpu沒有檢測框(問就是被這個小問題迫害了很久 --_–)。

最後在112行左右的位置,新增一個print

這時執行程式就會返回方框的位置資訊和自信度了

我們的前驅工作終於完成了~

二.編寫爬蟲1.尋找合適的網站

經過一番搜尋,最後鎖定了https://007.qq.com/online.html

因為它的網站結構很方便我們的操作。

2.匯入依賴庫

這裡我們採用selenium來模擬人類的操作。關於selenium的安裝和webdriver的安裝方法本文不作延伸。

from selenium import webdriverfrom selenium.webdriver.common.action_chains import ActionChainsimport requests,reimport osimport requestsimport re import timefrom selenium.webdriver import ActionChains12345678
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()	#模擬點選操作1234567891011121314

繼續

這裡便是我們要識別的圖片,不過直接定位的話並不能定位到,因為這段程式碼是由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.jpg12345678910

現在圖片也有了,檢測程式也準備好了,那麼開始檢測吧!

	'''	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("未能識別")        1234567891011121314151617181920212223242526272829303132333435

這裡著重說一下

action_chains.drag_and_drop_by_offset(drag1, int(int(location[2])/2-85), 0).perform()1

為什麼要拖 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 webdriverfrom selenium.webdriver.common.action_chains import ActionChainsimport requests,reimport osimport requestsimport re import timefrom selenium.webdriver import ActionChainsdef 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()

8
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • gocv 影象模板匹配