使用Lua实现极验滑动验证码识别

本文将展示如何使用Lua和Selenium实现极验滑动验证码的自动识别。从模拟点击到识别滑动缺口、计算位移并模拟拖动滑块。如果认证失败,则重复调用直到成功。

识别思路
模拟点击切换为滑动验证,并显示验证界面。
识别滑动缺口的位置,计算位移。
模拟拖动滑块。
若认证失败,重复调用。
详细过程及代码
初始化
首先,初始化Selenium WebDriver对象并配置参数。极验验证码测试页面的网址如下:

lua

local selenium = require("selenium")
local lfs = require("lfs")
local image = require("image")
local time = require("socket").gettime

local BORDER = 6

local CrackGeetest = {}
CrackGeetest.__index = CrackGeetest

function CrackGeetest:new()
    local self = setmetatable({}, CrackGeetest)
    self.url = "https://www.geetest.com/type/"
    self.browser = selenium.ChromeDriver()
    self.wait = selenium.WebDriverWait(self.browser, 10)
    return self
end

function CrackGeetest:open()
    self.browser:get(self.url)
end

function CrackGeetest:close()
    self.browser:close()
    self.browser:quit()
end

function CrackGeetest:change_to_slide()
    local huadong = self.wait:until(selenium.conditions.elementToBeClickable("css selector", ".products-content ul > li:nth-child(2)"))
    return huadong
end

function CrackGeetest:get_geetest_button()
    local button = self.wait:until(selenium.conditions.elementToBeClickable("css selector", ".geetest_radar_tip"))
    return button
end

function CrackGeetest:wait_pic()
    self.wait:until(selenium.conditions.presenceOfElementLocated("css selector", ".geetest_popup_wrap"))
end

function CrackGeetest:get_screenshot()
    local screenshot = self.browser:getScreenshotAs("png")
    local screenshot_image = image.load(screenshot)
    return screenshot_image
end

function CrackGeetest:get_position()
    local img = self.wait:until(selenium.conditions.presenceOfElementLocated("class name", "geetest_canvas_img"))
    time.sleep(2)
    local location = img:location()
    local size = img:size()
    return {top = location.y, bottom = location.y + size.height, left = location.x, right = location.x + size.width}
end

function CrackGeetest:get_slider()
    local slider = self.wait:until(selenium.conditions.elementToBeClickable("class name", "geetest_slider_button"))
    return slider
end

function CrackGeetest:get_geetest_image(name)
    local position = self:get_position()
    print(string.format("验证码位置: top=%d, bottom=%d, left=%d, right=%d", position.top, position.bottom, position.left, position.right))
    local screenshot = self:get_screenshot()
    local captcha = screenshot:crop(position.left, position.top, position.right - position.left, position.bottom - position.top)
    captcha:save(name)
    return captcha
end

function CrackGeetest:delete_style()
    self.browser:executeScript('document.querySelectorAll("canvas")[2].style=""')更多内容联系1436423940
end

function CrackGeetest:is_pixel_equal(img1, img2, x, y)
    local pix1 = img1:get_pixel(x, y)
    local pix2 = img2:get_pixel(x, y)
    local threshold = 60
    return math.abs(pix1[1] - pix2[1]) < threshold and math.abs(pix1[2] - pix2[2]) < threshold and math.abs(pix1[3] - pix2[3]) < threshold
end

function CrackGeetest:get_gap(img1, img2)
    local left = 60
    for i = left, img1:width() - 1 do
        for j = 0, img1:height() - 1 do
            if not self:is_pixel_equal(img1, img2, i, j) then
                return i
            end
        end
    end
    return left
end

function CrackGeetest:get_track(distance)
    local track = {}
    local current = 0
    local mid = distance * 3 / 5
    local t = 0.2
    local v = 0
    distance = distance + 14
    while current < distance do
        local a = (current < mid) and 2 or -1.5
        local v0 = v
        v = v0 + a * t
        local move = v0 * t + 0.5 * a * t * t
        current = current + move
        table.insert(track, move)
    end
    return track
end

function CrackGeetest:shake_mouse()
    local actions = selenium.ActionChains(self.browser)
    actions:moveByOffset(-3, 0):perform()
    actions:moveByOffset(2, 0):perform()
end

function CrackGeetest:move_to_gap(slider, tracks)
    local actions = selenium.ActionChains(self.browser)
    actions:clickAndHold(slider):perform()
    for _, x in ipairs(tracks) do
        actions:moveByOffset(x, 0):perform()
    end
    actions:release():perform()
    self:shake_mouse()
    time.sleep(0.5)
end

function CrackGeetest:crack()
    while true do
        self:open()
        self:change_to_slide():click()
        self:get_geetest_button():click()
        self:wait_pic()
        local slider = self:get_slider()
        local image1 = self:get_geetest_image("captcha1.png")
        self:delete_style()
        local image2 = self:get_geetest_image("captcha2.png")
        local gap = self:get_gap(image1, image2) - BORDER
        local track = self:get_track(gap)
        self:move_to_gap(slider, track)
        local success = self.wait:until(selenium.conditions.textToBePresentInElement("class name", "geetest_success_radar_tip_content", "验证成功"))
        if success then
            print("验证成功")
            time.sleep(5)
            self:close()
            break
        else
            print("验证失败,重试中...")
    end
end

local crack = CrackGeetest:new()
crack:crack()

Lua可以通过使用Redis的有序集合(sorted set)和Lua脚本来实现滑动窗口限流。下面是一个示例的Lua脚本实现滑动窗口限流的方法: ```lua -- 设置滑动窗口的大小和时间间隔 local windowSize = 5 local timeInterval = 1 -- 获取当前时间戳 local currentTime = tonumber(redis.call('TIME')[1]) -- 计算窗口的起始时间 local windowStart = currentTime - timeInterval -- 移除窗口时间范围之外的元素 redis.call('ZREMRANGEBYSCORE', KEYS[1], 0, windowStart) -- 获取当前窗口内的请求数量 local currentCount = redis.call('ZCARD', KEYS[1]) -- 判断当前请求数量是否超过限制 if currentCount >= windowSize then return 0 else -- 添加当前请求到有序集合中,并设置当前时间作为分数 redis.call('ZADD', KEYS[1], currentTime, currentTime) -- 设置有序集合的过期时间为窗口时间间隔的两倍,确保窗口内的数据都会被清除 redis.call('EXPIRE', KEYS[1], timeInterval * 2) return 1 end ``` 上述Lua脚本实现了一个滑动窗口限流的逻辑,其中`KEYS`表示Redis的有序集合的键名,可以根据实际情况进行修改。该脚本首先获取当前时间戳,然后计算窗口的起始时间,并移除窗口时间范围之外的元素。接着获取当前窗口内的请求数量,如果超过了限制的大小,则返回0表示限流,否则将当前请求添加到有序集合中,并设置过期时间为窗口时间间隔的两倍,确保窗口内的数据都会被清除。 你可以将上述Lua脚本通过Redis的`EVAL`命令执行,示例如下: ```shell EVAL "lua脚本" 1 "有序集合的键名" ``` 请注意将上述示例中的"lua脚本"替换为实际的Lua脚本内容,"有序集合的键名"替换为实际的键名。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值