滑动拼图验证码思路
1. 最简单的的调用打码平台,收费
2. 还有一种利用华为云物体检测接口,可以自己上传图片去训练模型,模型训练好后,部署上线,就可以直接用了,收费,目测一次0.27元,也没细算,有提供接口服务,重要可以自己提供数据训练模型

3. 获取到一张完整的图片和带缺口的图片,利用PIL模块,对比两张图的像素点,计算出距离,然后selenium滑动,免费,比如:
以下代码为虎嗅 登陆
代码为18年7月的,已失效,只提供思路
# coding=utf-8
from selenium import webdriver
from selenium.webdriver.common.proxy import Proxy
from selenium.webdriver.common.proxy import ProxyType
from selenium.webdriver.support.wait import WebDriverWait
# from selenium.webdriver.support.ui import WebDriverWait
# from selenium.common.exceptions import NoAlertPresentException,TimeoutException,NoSuchElementException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from PIL import ImageGrab, Image
import time, random, re, json, requests, os, sys
sys.path.append('C:/Users/Administrator/Desktop/tian_yan_cha/img_huxiu')
class Hu_Xiu:
def __init__(self):
chromedriver = 'C:/Users/Administrator/AppData/Local/Programs/Python/Python35/Scripts/chromedriver'
chromeOptions = webdriver.ChromeOptions()
chromeOptions.add_argument("--proxy-server = http://115.198.32.22:6666")
self.driver = webdriver.Chrome(chromedriver, chrome_options=chromeOptions) # chromedriver, chrome_options=chromeOptions
self.driver.maximize_window()
# self.driver = webdriver.Firefox()
self.header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
}
def visit_web(self):
# 访问网站, 出现拼图按钮, 鼠标移动到拼图按钮上并执行, 刷新 极验 拼图
print('----------- 访问网站 ----------')
self.driver.get("https://www.huxiu.com/")
time.sleep(random.uniform(10, 15))
# 等待页面的上元素刷新出来 '''判断某个元素中是否可见并且是enable的,代表可点击''' 注册 按钮
WebDriverWait(self.driver, 10, 0.5).until(EC.element_to_be_clickable((By.XPATH, '//*[@class="js-register"]')))
reg_element = self.driver.find_element_by_xpath('//*[@class="js-register"]')
reg_element.click()
WebDriverWait(self.driver, 10, 0.5).until(EC.element_to_be_clickable((By.XPATH, '//div[@class="gt_slider_knob gt_show"]')))
def visit_web_show(self):
# 鼠标移动到拖动按钮,显示出拖动图片
element = self.driver.find_element_by_xpath('//div[@class="gt_slider_knob gt_show"]')
ActionChains(self.driver).move_to_element(element).perform()
time.sleep(random.uniform(3, 5))
# 刷新一下极验图片
element = self.driver.find_element_by_xpath('//a[@class="gt_refresh_button"]')
element.click()
time.sleep(random.uniform(3, 5))
# print(self.driver.page_source)
def get_merge_img(self, image_name, location_list):
# ---------》 重新合并 还原 图片 《----------
print('---------》 重新合并 还原 图片 《----------')
print(location_list)
# 打开图片
img = Image.open(image_name)
# 创建新的图片,大小为260*116
new_im = Image.new('RGB', (260, img.height))
im_list_up = []
im_list_down = []
for location in location_list:
# y值== -58 的图片属于上半部分,高度58
if location['y'] == -58:
im_list_up.append(img.crop((abs(location['x']), 58, abs(location['x']) + 10, img.height)))
# 下边图片
if location['y'] == 0:
im_list_down.append(img.crop((abs(location['x']), 0, abs(location['x']) + 10, 58)))
# 黏贴图片
x_offset = 0
for im in im_list_up:
new_im.paste(im, (x_offset, 0))
x_offset += im.size[0]
x_offset = 0
for im in im_list_down:
new_im.paste(im, (x_offset, 58))
x_offset += im.size[0]
# new_im.show()
return new_im
def get_img(self, xpath_rules):
# 保存所有图片
print('---------- 保存所有图片 ----------')
images_list = self.driver.find_elements_by_xpath(xpath_rules)
location_list = []
for image_list in images_list:
location = {}
# 在html里面解析出小图片的url地址,还有长高的数值
location['x'] = int(re.findall("background-image: url\(\"(.*?)\"\); background-position: (.*?)px (.*?)px;",image_list.get_attribute('style'))[0][1])
location['y'] = int(re.findall("background-image: url\(\"(.*?)\"\); background-position: (.*?)px (.*?)px;",image_list.get_attribute('style'))[0][2])
location_list.append(location)
imageurl = re.findall("background-image: url\(\"(.*?)\"\); background-position: (.*?)px (.*?)px;",image_list.get_attribute('style'))[0][0]
# 替换图片的后缀,获得图片的URL
image_url = imageurl.replace('webp', 'jpg')
print(image_url)
# 获取图片名字
image_name = './img_huxiu/' + image_url.split('/')[-1]
# 下载图片 保存
res = requests.get(url=image_url, headers=self.header)
with open(image_name, 'wb') as f:
f.write(res.content)
# ---------》 重新合并 还原 图片 《----------
ima = self.get_merge_img(image_name, location_list)
return ima, image_name
def is_similar_color(self, img1, img2, i, j):
# 对比颜色 RGB值
# 获取指定位置的RGB值
# print('------------ 对比颜色 RGB值 -------------')
pixel01 = img1.getpixel((i, j)) # 像素值 pixel01 -- (31, 160, 80)
pixel02 = img2.getpixel((i, j)) # 像素值 pixel02 -- (31, 160, 80)
# print('pixel01 -- ', pixel01)
# print('pixel02 -- ', pixel02)
for k in range(0, len(pixel01)):
# 如果相差超过50则就认为找到了缺口的位置
if abs(pixel01[k] - pixel02[k]) >= 30:
return False
return True
def get_offset_destance(self, img1, img2):
# 计算缺口距离
# 两张原始图的大小都是相同的260*116
# 那就通过两个for循环依次对比每个像素点的RGB值
# 如果相差超过50则就认为找到了缺口的位置
print('--------------- 计算缺口距离 --------------')
for i in range(0, img1.width):
for j in range(0, img1.height):
# 判断颜色是否相近
if self.is_similar_color(img1, img2, i, j) == False:
img3 = img1.crop((i, j, i + 50, j + 40))
img3.save('./img_huxiu/gap.jpg')
print('=== 缺口距离 i == ', str(i))
return i
def get_track(self, loc):
# 根据缺口的位置模拟x轴移动的轨迹
print('--------------- 根据缺口的位置模拟x轴移动的轨迹 --------------')
# 前 4/5 加速运动, 后 1/5 减速运动
'''
速度公式: v = v0 + at v0 初速度 a 加速度值 t 时间 v 末速度
位移公式: s = v0*t + 1/2 * a*t*t
'''
v = 0 # 初速度
t = 0.2 # 时间
s0 = 0 # 当前的位移
mid = 4/5*loc
print('mid= %s' % mid)
move_list = [] #其中一个元素 代表 在0.2s时间内的位移距离
while s0 < loc:
if s0 < mid:
# 加速运动
a = 2
else:
# 减速运动
a = -4
v0 = v
# 0.2s 内的位移距离
s = v0*t + 0.5*a*t*t
# 当前位置
s0 += s
# print(s)
# print('s0= ', s0)
move_list.append(round(s))
# 速度已经达到v,该速度作为下次的初速度
v = v0 + a * t
print('s0= ', s0)
print('move_list= %s' % move_list)
# move_list= [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2]
return move_list
def sliding(self, m_list):
# 点击 滑动按钮 进行 滑动 验证
print('--------------- 点击 滑动按钮 进行 滑动 验证 --------------')
# 获取元素坐标
elment = self.driver.find_element_by_xpath('//div[@class="gt_slider_knob gt_show"]')
location = elment.location
print('刷新按钮图片大小 = ', elment.size) # {'height': 44, 'width': 44}
# 获取圆球高度
y = location['y']
print('y = ', y)
# 点击元素不放
ActionChains(self.driver).click_and_hold(on_element=elment).perform()
time.sleep(random.uniform(0.2, 0.7))
# 拖动元素
track_string = ''
for track in m_list:
# xoffset=track+22:这里的移动位置的值是相对于滑动圆球左上角的相对值,而轨迹变量里的是圆球的中心点,所以要加上圆球长度的一半。
# yoffset=y-445:这里也是一样的。不过要注意的是不同的浏览器渲染出来的结果是不一样的,要保证最终的计算后的值是22,也就是圆球高度的一半
track_string = track_string + '(%s, %s)' % (track, y - 423)
ActionChains(self.driver).move_to_element_with_offset(to_element=elment, xoffset=track + 22 , yoffset=y - 445).perform()
time.sleep(random.uniform(0.03, 0.15))
print('track_string = ', track_string)
# xoffset=21,本质就是向后退一格。这里退了5格是因为圆球的位置和滑动条的左边缘有5格的距离
p = 0
while p < 5:
ActionChains(self.driver).move_to_element_with_offset(to_element=elment, xoffset=21, yoffset=y - 445).perform()
time.sleep(random.uniform(0.1, 0.7))
p += 1
# 释放鼠标
ActionChains(self.driver).release(on_element=elment).perform()
time.sleep(random.uniform(3, 5))
def register(self):
# 验证通过, 输入账号密码
element = self.driver.find_element_by_xpath('//input[@id="sms_username"]')
element.clear()
element.send_keys("手机号")
ele_captcha = self.driver.find_element_by_xpath('//span[@class="js-btn-captcha btn-captcha"]')
ele_captcha.click()
def all_steps(self):
# 鼠标移动到拼图按钮上并执行, 刷新 极验 拼图
self.visit_web_show()
# 保存所有图片
img1, img1_name = self.get_img('//div[@class="gt_cut_bg_slice"]')
img2, img2_name = self.get_img('//div[@class="gt_cut_fullbg_slice"]')
# print('img1 = %s ; img2 = %s' % (img1, img2))
# 计算距离 x 轴移动距离
loc = self.get_offset_destance(img1, img2) # 84
os.remove(img1_name)
os.remove(img2_name)
# 生成 x 轴 移动轨迹
# loc = 84
move_list = self.get_track(loc)
# 点击 滑动按钮 进行 滑动 验证
self.sliding(move_list)
def judge_succ(self):
# 判断是否验证成功
try:
WebDriverWait(self.driver, 10, 0.5).until(
EC.element_to_be_clickable((By.XPATH, '//div[@class="gt_ajax_tip gt_success"]')))
print('>>>>>>>>>>>>>>>>>> 验证成功 <<<<<<<<<<<<<<<<<<<<<')
return True
except:
print(">>>>>>>>>>>>>>>>>> 验证失败,点击刷新后重试 <<<<<<<<<<<<<<<<<<<<<")
time.sleep(random.uniform(5, 10))
return False
def run(self):
# 访问网站, 出现拼图按钮,
self.visit_web()
# 步骤
self.all_steps()
# 判断 验证是否 成功, 不成功的话, 在从头 试一遍
if self.judge_succ() == True:
print('>>>>>>>>>>>>>>>>>> 验证成功 <<<<<<<<<<<<<<<<<<<<<')
# 成功后输入手机号,发送验证码
self.register()
else:
# 失败后递归执行拖动
self.all_steps()
if __name__ == '__main__':
# 虎嗅网 爬虫
hx = Hu_Xiu()
hx.run()

浙公网安备 33010602011771号