滑块验证似乎很神秘,其实也简单,核心点在于如何模拟鼠标移动的轨迹更象人移动的轨迹,你模拟得越象就越容易成功。
主要步骤:
1)保存背景图片code.png
2)灰度code2.png、二值化code3.png、去噪code4.png背景图片
3)统计计算缺口的位置
4)模拟鼠标移动轨迹
5)拖动模块到指定位置
废话少说,直接上代码。
import time
import datetime
import random
import requests
import matplotlib.pyplot as plt
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.support.select import Select
from io import BytesIO
from PIL import Image
from collections import Counter
import pymongo
import os
import pandas as pd
path="默认下载保存路径"
# 获取JD登陆页面
url = "登录页面"
valid_url = "登录成功页面"
# 启动调试程序
browser = webdriver.Chrome(options=options,executable_path="d:\chromedriver.exe")
# 二值化,将所有的点位,全部换成0或255
def bi_value(w, h, image):
tem = 0
for x in range(w):
for y in range(h):
tem += image.getpixel((x, y))
pixel_ave = tem / w / h * 0.7
for x in range(w):
for y in range(h):
p = image.getpixel((x, y))
if p < pixel_ave:
image.putpixel((x, y), 0)
else:
image.putpixel((x, y), 255)
return image
# 降噪处理
def reduce_noise(image):
w, h = image.size
for x in range(0, 40): # 处理最左边
for y in range(h):
image2 = image.putpixel((x, y), 255)
return image
# 处理图片,灰度化与二值化、降噪
def get_target_picture():
im = Image.open("code.png")
#print("缺口背景图片")
im2 = im.convert("L")
im2.save("code2.png")
w, h = im2.size
im3 = bi_value(w, h, im2)
im3.save("code3.png")
im4 = reduce_noise(im3)
im4.save("code4.png")
#print("二值化除噪图片")
return im4
# 计算距离
def get_distance(image):
w, h = image.size
ls = []
for i in range(31, w - 31): # 图片最左边放置滑块,缺口坐标x不可能小于31
for j in range(10, h):
if image.getpixel((i, j)) < 100:
count = 0
for k in range(i, i + 31):
if image.getpixel((k, j)) < 100:
count += 1
else:
break
if count > 27: ls.append(i)
return Counter(ls).most_common(1)[0][0]
# 设计拖动轨迹
def get_tracks(distance):
"""
根据偏移量获取移动轨迹
这里把距离加长,拉过头
:param distance: 偏移量
:return: 移动轨迹
"""
print("需要拖动距离:",distance)
# 加长距离,拉过头
distance += 6
# 移动轨迹
tracks = []
# 当前位移
current = 0
# 变速阈值
if distance > 100:
mid1 = (distance * 1 / 3)
mid2 = (distance * 7 / 8)
else:
mid1 = (distance * 1 / 2)
mid2 = (distance * 5 / 6)
# 间隔时间
t = 0.3
# 初速度
v = 3
while current < distance:
if current < mid1:
a = random.randint(3, 5)
elif current < mid2:
a = random.randint(0, 2)
else:
a = - random.randint(9, 12)
v0 = v
v = v0 + a * t
move = v0 * t + 1 / 2 * a * t * t
current += move
tracks.append(round(move))
bais = distance-sum(tracks)
if bais!=0:
tracks.append(bais)
print("正向拖动轨迹:",tracks)
return tracks
def drog_slider(tracks): # 拖动滑块
# 定位滑块
ele = browser.find_element_by_xpath('.//div[@class="JDJRV-slide-inner JDJRV-slide-btn"]')
# 设计拖动动作链(点击且不放)
ActionChains(browser).move_to_element(ele).click_and_hold(ele).perform()
# 根据设计的轨迹,实现滑块拖动
for i in tracks:
ActionChains(browser).move_by_offset(i, random.uniform(-5,5)).perform()
# 睡眠0.25秒,伪装成人的判断过程
time.sleep(1)
for x in [-3, -2, -2, -1]:
ActionChains(browser).move_by_offset(x, random.uniform(-5,5)).perform()
# 释放滑块,类似于松开鼠标
ActionChains(browser).release().perform()
time.sleep(3)
print("实际拖动距离:",sum(tracks)-6)
def login():
username = ""
password = ""
browser.maximize_window()
browser.get(url)
time.sleep(2)
# 找到账户登录并且点击
login_ele = browser.find_element_by_xpath("//div[@class='login-tab login-tab-r']")
login_ele.click()
time.sleep(2)
# 输入用户名和密码
username_ele = browser.find_element_by_xpath("//input[@id='loginname']")
password_ele = browser.find_element_by_xpath("//input[@id='nloginpwd']")
time.sleep(1)
username_ele.send_keys(username)
time.sleep(1)
password_ele.send_keys(password)
time.sleep(1)
# 点击提交,进入滑动验证码页面
submit_btn = browser.find_element_by_xpath("//a[@id='loginsubmit']")
submit_btn.click()
time.sleep(1)
def save_bg_picture():
# 通过修改JS隐藏滑块并截屏获取验证码图片,保存至当前目录,名为code.png
js = 'document.getElementsByClassName("JDJRV-smallimg")[0].style.display="none"'
browser.execute_script(js)
code_path = 'code.png'
browser.find_element_by_xpath('.//div[@class="JDJRV-bigimg"]').screenshot(code_path)
time.sleep(1)
# 停止1秒后恢复JS改动,回到页面最初状态
js = 'document.getElementsByClassName("JDJRV-smallimg")[0].style.display="block"'
browser.execute_script(js)
def try_drog_slider(): # 再次尝试
print(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),"尝试登录")
save_bg_picture()
image = get_target_picture()
distance = get_distance(image)
tracks = get_tracks(distance)
drog_slider(tracks)
def try_login():
print(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),"尝试登录")
login()
save_bg_picture()
image = get_target_picture()
distance = get_distance(image)
tracks = get_tracks(distance)
drog_slider(tracks)
succ = False
try_times = 1
while try_times<3:
if browser.current_url == valid_url:
succ = True
print("尝试",try_times,"次登录成功!")
break
else:
try_drog_slider()
try_times+=1
print(browser.current_url)
if browser.current_url == valid_url:
succ = True
print("尝试",try_times,"次登录成功!")
break
if succ == False:
print("尝试",try_times,"次登录失败!")
browser.quit()
return succ
if try_login() == True:
print("可以开始干点正事了。")