# -*- 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):
"""
初始化项
"""
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):
"""
滑动滑块操作
:param dis: 滑动的距离
: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()
# 小范围震荡一下,进一步迷惑极验后台,这一步可以极大地提高成功率
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):
"""
模拟人为拖动滑块行为,快到缺口位置时,减缓拖动的速度
:param dis: 滑动距离
:return: 轨迹
"""
dis += 20
v = 0
t = 0.3
# 保存0.3内的位移
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
# 反着滑动到准确位置
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):
"""
获取验证码图片
:param url: 验证码页面地址
:return: 验证码图片对象
"""
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):
"""
对比像素确定缺口位置
:param image: 验证码图片对象
:return: 滑动的距离
"""
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):
"""
运行调度
:param url: 验证码图片地址
:return:
"""
verify_url = url
img = self.get_image(verify_url)
dis = self.get_position(img)
if dis:
real_dis = dis - 8 # 实际滑动距离,增减数值具体情况具体分析
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)
注意:
只是实现了滑动验证码,至于滑块轨迹算法,并未解决,如果有好的轨迹算法,欢迎沟通