用Go实现极验滑动验证码识别


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

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

go

package main

import (
    "bytes"
    "image"
    "image/png"
    "log"
    "time"

    "github.com/tebeka/selenium"
)

const (
    browserDriverPath = "/path/to/chromedriver"
    port              = 9515
    browserPath       = "http://localhost:9515"
    url               = "https://www.geetest.com/type/"
)

type CrackGeetest struct {
    WebDriver selenium.WebDriver
}

func NewCrackGeetest() *CrackGeetest {
    opts := []selenium.ServiceOption{}
    service, err := selenium.NewChromeDriverService(browserDriverPath, port, opts...)
    if err != nil {
        log.Fatalf("Error starting the ChromeDriver server: %v", err)
    }

    caps := selenium.Capabilities{"browserName": "chrome"}
    wd, err := selenium.NewRemote(caps, browserPath)
    if err != nil {
        log.Fatalf("Error creating new WebDriver session: %v", err)
    }

    return &CrackGeetest{WebDriver: wd}
}

func (cg *CrackGeetest) Open() {
    if err := cg.WebDriver.Get(url); err != nil {
        log.Fatalf("Error opening the URL: %v", err)
    }
}

func (cg *CrackGeetest) Close() {
    cg.WebDriver.Quit()
}
模拟点击
首先模拟点击切换为滑动验证,然后模拟点击弹出验证图片。

go

func (cg *CrackGeetest) ChangeToSlide() selenium.WebElement {
    huadong, err := cg.WebDriver.FindElement(selenium.ByCSSSelector, ".products-content ul > li:nth-child(2)")
    if err != nil {
        log.Fatalf("Error finding the slide option element: %v", err)
    }
    return huadong
}

func (cg *CrackGeetest) GetGeetestButton() selenium.WebElement {
    button, err := cg.WebDriver.FindElement(selenium.ByCSSSelector, ".geetest_radar_tip")
    if err != nil {
        log.Fatalf("Error finding the initial verification button: %v", err)
    }
    return button
}
获取背景图
首先等待验证码加载完成(WaitPic),获取网页截图(GetScreenshot),然后获取验证背景图所在的位置及大小参数(GetPosition)和滑块对象(GetSlider)。

go

func (cg *CrackGeetest) WaitPic() {
    _, err := cg.WebDriver.FindElement(selenium.ByCSSSelector, ".geetest_popup_wrap")
    if err != nil {
        log.Fatalf("Error waiting for the verification image to load: %v", err)
    }
}

func (cg *CrackGeetest) GetScreenshot() image.Image {
    screenshot, err := cg.WebDriver.Screenshot()
    if err != nil {
        log.Fatalf("Error taking screenshot: %v", err)
    }
    img, err := png.Decode(bytes.NewReader(screenshot))
    if err != nil {
        log.Fatalf("Error decoding screenshot: %v", err)
    }
    return img
}

func (cg *CrackGeetest) GetPosition() (int, int, int, int) {
    img, err := cg.WebDriver.FindElement(selenium.ByClassName, "geetest_canvas_img")
    if err != nil {
        log.Fatalf("Error finding the verification image element: %v", err)
    }
    location, err := img.Location()
    if err != nil {
        log.Fatalf("Error getting location of the verification image: %v", err)
    }
    size, err := img.Size()
    if err != nil {
        log.Fatalf("Error getting size of the verification image: %v", err)
    }
    top, bottom, left, right := location.Y, location.Y+size.Height, location.X, location.X+size.Width
    return top, bottom, left, right
}

func (cg *CrackGeetest) GetSlider() selenium.WebElement {
    slider, err := cg.WebDriver.FindElement(selenium.ByClassName, "geetest_slider_button")
    if err != nil {
        log.Fatalf("Error finding the slider element: %v", err)
    }
    return slider
}
再通过上述返回的背景图位置和大小参数,对网页截图进行切片(GetGeetestImage),最后获取背景图。

go

func (cg *CrackGeetest) GetGeetestImage(name string) image.Image {
    top, bottom, left, right := cg.GetPosition()
    log.Printf("验证码位置: %d %d %d %d\n", top, bottom, left, right)
    screenshot := cg.GetScreenshot()
    captcha := screenshot.(interface {
        SubImage(r image.Rectangle) image.Image
    }).SubImage(image.Rect(left, top, right, bottom))
    file, err := os.Create(name)
    if err != nil {
        log.Fatalf("Error creating image file: %v", err)
    }
    defer file.Close()
    png.Encode(file, captcha)
    return captcha
}
删除样式获取无缺口背景图
go

func (cg *CrackGeetest) DeleteStyle() {
    script := "document.querySelectorAll('canvas')[2].style=''"
    _, err := cg.WebDriver.ExecuteScript(script, nil)
    if err != nil {
        log.Fatalf("Error executing script to delete style: %v", err)
    }
}
识别缺口
go

func IsPixelEqual(img1, img2 image.Image, x, y int) bool {
    pix1 := img1.At(x, y)
    pix2 := img2.At(x, y)
    r1, g1, b1, _ := pix1.RGBA()
    r2, g2, b2, _ := pix2.RGBA()
    threshold := uint32(60)
    return (abs(r1, r2) < threshold) && (abs(g1, g2) < threshold) && (abs(b1, b2) < threshold)
}

func abs(a, b uint32) uint32 {
    if a > b {
        return a - b
    }
    return b - a
}

func GetGap(img1, img2 image.Image) int {
    left := 60
    for i := left; i < img1.Bounds().Dx(); i++ {
        for j := 0; j < img1.Bounds().Dy(); j++ {
            if !IsPixelEqual(img1, img2, i, j) {
                return i
            }
        }
    }
    return left
}
模拟拖动
go

func GetTrack(distance int) []int {
    track := []int{}
    current := 0
    mid := distance * 3 / 5
    t := 0.2
    v := 0.0
    distance += 14
    for current < distance {
        a := 2.0
        if current >= mid {
            a = -3.0
        }
        v0 := v
        v = v0 + a*t
        move := v0*t + 0.5*a*t*t
        current += int(move)
        track = append(track, int(move))
    }
    return track
}

func ShakeMouse(wd selenium.WebDriver) {
    actions := wd.Actions()
    actions.MoveByOffset(-3, 0).Perform()
    actions.MoveByOffset(2, 0).Perform()
}

func MoveToGap(wd selenium.WebDriver, slider selenium.WebElement, tracks []int) {
    actions := wd.Actions()
    actions.ClickAndHold(slider).Perform()
    for _, x := range tracks {
        actions.MoveByOffset(x, 0).Perform()
    }
    backTracks := []int{-1, -1, -2, -2, -3, -2, -2, -1, -1}
    for _, x := range backTracks {
        actions.MoveByOffset(x, 0).Perform()
    }
    ShakeMouse(wd)
    time.Sleep(500 * time.Millisecond)
    actions.Release().Perform()
}
整个控制流程
执行主体流程,若验证失败,则再次调用Crack进行识别,直至成功。更多内容联系1436423940

go

func (cg *CrackGeetest) Crack() {
    defer cg.Close()
    for {
        cg.Open()
        slideBtn := cg.ChangeToSlide()
        slideBtn.Click()
        geetestBtn := cg.GetGeetestButton()
        geetestBtn.Click()
        cg.WaitPic()
        slider := cg.GetSlider()
        img1 := cg.GetGeetestImage("captcha1.png")
        cg.DeleteStyle()
        img2 := cg.GetGeetestImage("captcha2.png")
        gap := GetGap(img1, img2)
        log.Printf("缺口位置: %d\n", gap)
        gap -= BORDER
        tracks := GetTrack(gap)
        MoveToGap(cg.WebDriver, slider, tracks)
        success, err := cg.WebDriver.FindElement(selenium.ByCSSSelector, ".geetest_success_radar_tip_content")
        if err == nil {
            text, _ := success.Text()
            if text == "验证成功" {
                break
            }
        }
        time.Sleep(5 * time.Second)
    }
}

func main() {
    crack := NewCrackGeetest()
    crack.Crack()
}
至此,使用Go实现极验滑动验证码识别的方法已经记录完毕。

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值