# -*- coding: utf-8 -*-
import random,? time
from PIL import Image
from time import sleep
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
class DealVerifyCode(object):
? ? def __init__(self):
? ? ? ? """
? ? ? ? 初始化項(xiàng)
? ? ? ? """
? ? ? ? self.headers = {
? ? ? ? ? ? "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) \
? ? ? ? ? ? ? ? ? ? ? ? ? AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36"
? ? ? ? }
? ? ? ? self.driver = webdriver.Chrome()
? ? def slide_block(self, dis):
? ? ? ? """
? ? ? ? 滑動(dòng)滑塊操作
? ? ? ? :param dis: 滑動(dòng)的距離
? ? ? ? :return:
? ? ? ? """
? ? ? ? element = self.driver.find_element_by_xpath('//div[@class="dvc-slider__handler"]')
? ? ? ? if element:
? ? ? ? ? ? tracks = self.get_tracks(dis)
? ? ? ? ? ? ActionChains(self.driver).click_and_hold(on_element=element).perform()
? ? ? ? ? ? for track in tracks['forward_tracks']:
? ? ? ? ? ? ? ? ActionChains(self.driver).move_by_offset(xoffset=track, yoffset=0).perform()
? ? ? ? ? ? sleep(0.5)
? ? ? ? ? ? for track in tracks['back_tracks']:
? ? ? ? ? ? ? ? ActionChains(self.driver).move_by_offset(xoffset=track, yoffset=0).perform()
? ? ? ? ? ? # 小范圍震蕩一下独泞,進(jìn)一步迷惑極驗(yàn)后臺(tái)抗悍,這一步可以極大地提高成功率
? ? ? ? ? ? ActionChains(self.driver).move_by_offset(xoffset=-3, yoffset=0).perform()
? ? ? ? ? ? time.sleep(0.5)
? ? ? ? ? ? ActionChains(self.driver).move_by_offset(xoffset=3, yoffset=0).perform()
? ? ? ? ? ? time.sleep(0.5)
? ? ? ? ? ? ActionChains(self.driver).release(on_element=element).perform()
? ? def get_tracks(self, dis):
? ? ? ? """
? ? ? ? 模擬人為拖動(dòng)滑塊行為涂圆,快到缺口位置時(shí)秫舌,減緩?fù)蟿?dòng)的速度
? ? ? ? :param dis: 滑動(dòng)距離
? ? ? ? :return: 軌跡
? ? ? ? """
? ? ? ? dis += 20
? ? ? ? v = 0
? ? ? ? t = 0.3
? ? ? ? # 保存0.3內(nèi)的位移
? ? ? ? forward_tracks = []
? ? ? ? current = 0
? ? ? ? mid = dis * 4 / 5
? ? ? ? while current <= dis:
? ? ? ? ? ? if current < mid:
? ? ? ? ? ? ? ? a = random.uniform(2, 3)
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? a = -3
? ? ? ? ? ? v0 = v
? ? ? ? ? ? s = v0 * t + 0.5 * a * (t ** 2)
? ? ? ? ? ? current += s
? ? ? ? ? ? forward_tracks.append(round(s))
? ? ? ? ? ? m = random.uniform(1, 1.5)
? ? ? ? ? ? v = v0 + m * a * t
? ? ? ? # 反著滑動(dòng)到準(zhǔn)確位置
? ? ? ? back_tracks = [-3, -3, -2, -2, -2, -2, -2, -1, -1, -1]? # 總共等于-20
? ? ? ? return {'forward_tracks': forward_tracks, 'back_tracks': back_tracks}
? ? def get_image(self, url):
? ? ? ? """
? ? ? ? 獲取驗(yàn)證碼圖片
? ? ? ? :param url: 驗(yàn)證碼頁面地址
? ? ? ? :return: 驗(yàn)證碼圖片對(duì)象
? ? ? ? """
? ? ? ? self.driver.get(url)
? ? ? ? dis = 280
? ? ? ? self.slide_block(dis)
? ? ? ? self.driver.save_screenshot('./img.png')
? ? ? ? img_obj = Image.open('img.png')
? ? ? ? img = self.driver.find_element_by_xpath('//img[@class="dvc-captcha__bgImg"]')
? ? ? ? location = img.location
? ? ? ? size = img.size
? ? ? ? left = location['x']
? ? ? ? top = location['y']
? ? ? ? right = left + size['width']
? ? ? ? bottom = top + size['height']
? ? ? ? # print left, top, right, bottom
? ? ? ? # 將屏幕截圖裁剪
? ? ? ? verify_img = img_obj.crop((left, top, right, bottom))
? ? ? ? # verify_img.show()
? ? ? ? verify_img.save('./verify_img.jpg')
? ? ? ? return verify_img
? ? def get_position(self, image):
? ? ? ? """
? ? ? ? 對(duì)比像素確定缺口位置
? ? ? ? :param image: 驗(yàn)證碼圖片對(duì)象
? ? ? ? :return: 滑動(dòng)的距離
? ? ? ? """
? ? ? ? image = image.convert('L')
? ? ? ? # image.show()
? ? ? ? threshold = 150
? ? ? ? threshold2 = 50
? ? ? ? num = 10
? ? ? ? for i in range(55, image.size[0] - 20):
? ? ? ? ? ? for j in range(0, image.size[1] - 20):
? ? ? ? ? ? ? ? flag = True
? ? ? ? ? ? ? ? for l in range(0, num):
? ? ? ? ? ? ? ? ? ? pixel = image.getpixel((i, j)) - image.getpixel((i + 1, j + l))
? ? ? ? ? ? ? ? ? ? if pixel < threshold2: flag = False
? ? ? ? ? ? ? ? for l in range(0, num):
? ? ? ? ? ? ? ? ? ? pixel = image.getpixel((i, j + l))
? ? ? ? ? ? ? ? ? ? if pixel < threshold: flag = False
? ? ? ? ? ? ? ? if flag:
? ? ? ? ? ? ? ? ? ? return i
? ? def run(self, url):
? ? ? ? """
? ? ? ? 運(yùn)行調(diào)度
? ? ? ? :param url: 驗(yàn)證碼圖片地址
? ? ? ? :return:
? ? ? ? """
? ? ? ? verify_url = url
? ? ? ? img = self.get_image(verify_url)
? ? ? ? dis = self.get_position(img)
? ? ? ? if dis:
? ? ? ? ? ? real_dis = dis - 8? # 實(shí)際滑動(dòng)距離,增減數(shù)值具體情況具體分析
? ? ? ? else:
? ? ? ? ? ? real_dis = 200
? ? ? ? self.slide_block(real_dis)
? ? ? ? time.sleep(2)
? ? ? ? try:
? ? ? ? ? ? tips = self.driver.find_element_by_xpath('//div[@class="dvc-slider__tips"]')
? ? ? ? ? ? if tips:
? ? ? ? ? ? ? ? self.run(verify_url)
? ? ? ? except:
? ? ? ? ? ? pass
? ? ? ? ? ? # self.driver.quit()
if __name__ == '__main__':
? ? url = 'https://www.anjuke.com/captcha-verify/?callback=shield&from=antispam&serialID=f51e8ecae16400c96feb87fba1cddc37_2a8c6e02a1044e3bb0e223a55f029d42&history=aHR0cHM6Ly9jcy5hbmp1a2UuY29tLw%3D%3D'
? ? deal = DealVerifyCode()
? ? deal.run(url)
注意:
只是實(shí)現(xiàn)了滑動(dòng)驗(yàn)證碼,至于滑塊軌跡算法助琐,并未解決祭埂,如果有好的軌跡算法,歡迎溝通