准备工作
安装Go语言和相关库
首先,你需要安装Go语言。如果你还没有安装,可以访问Go语言官网进行安装。
接下来,我们需要安装Go语言的Selenium客户端库selenium和OpenCV的Go绑定库gocv。
在终端中运行以下命令安装依赖:
sh
go get -u github.com/tebeka/selenium
go get -u gocv.io/x/gocv
验证码页面
验证码页面地址:https://dun.163.com/trial/jigsaw
代码实现
1. 初始化Selenium
我们首先启动Selenium WebDriver并导航到验证码页面。
go
package main
import (
"fmt"
"log"
"time"
"github.com/tebeka/selenium"
)
const (
seleniumPath = "/path/to/selenium-server-standalone.jar"
chromeDriverPath = "/path/to/chromedriver"
port = 8080
)
func main() {
opts := []selenium.ServiceOption{}
service, err := selenium.NewSeleniumService(seleniumPath, port, opts...)
if err != nil {
log.Fatalf("Error starting the Selenium server: %v", err)
}
defer service.Stop()
caps := selenium.Capabilities{"browserName": "chrome"}
wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", port))
if err != nil {
log.Fatalf("Error connecting to the WebDriver: %v", err)
}
defer wd.Quit()
err = wd.Get("https://dun.163.com/trial/jigsaw")
if err != nil {
log.Fatalf("Error loading page: %v", err)
}
time.Sleep(3 * time.Second)
// 后续的验证码处理代码将放在这里
}
2. 获取验证码图片
获取验证码图片并保存到本地,以便使用OpenCV进行图像处理。
go
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"time"
"github.com/tebeka/selenium"
)
func getImage(wd selenium.WebDriver, selector string, filePath string) error {
elem, err := wd.FindElement(selenium.ByCSSSelector, selector)
if err != nil {
return err
}
imgURL, err := elem.GetAttribute("src")
if err != nil {
return err
}
resp, err := http.Get(imgURL)
if err != nil {
return err
}
defer resp.Body.Close()
imgData, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
err = ioutil.WriteFile(filePath, imgData, 0644)
if err != nil {
return err
}
return nil
}
func main() {
opts := []selenium.ServiceOption{}
service, err := selenium.NewSeleniumService(seleniumPath, port, opts...)
if err != nil {
log.Fatalf("Error starting the Selenium server: %v", err)
}
defer service.Stop()
caps := selenium.Capabilities{"browserName": "chrome"}
wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", port))
if err != nil {
log.Fatalf("Error connecting to the WebDriver: %v", err)
}
defer wd.Quit()
err = wd.Get("https://dun.163.com/trial/jigsaw")
if err != nil {
log.Fatalf("Error loading page: %v", err)
}
time.Sleep(3 * time.Second)
err = getImage(wd, ".yidun_bg-img", "bg.png")
if err != nil {
log.Fatalf("Error getting background image: %v", err)
}
err = getImage(wd, ".yidun_jigsaw", "puzzle.png")
if err != nil {
log.Fatalf("Error getting puzzle image: %v", err)
}
// 后续的验证码处理代码将放在这里
}
3. 使用OpenCV匹配图像
使用OpenCV找到拼图缺口的位置。
go
package main
import (
"fmt"
"image"
"log"
"gocv.io/x/gocv"
)
func getSlideDistance(bgPath, puzzlePath string) (float64, error) {
bgImg := gocv.IMRead(bgPath, gocv.IMReadColor)
if bgImg.Empty() {
return 0, fmt.Errorf("error reading background image")
}
defer bgImg.Close()
puzzleImg := gocv.IMRead(puzzlePath, gocv.IMReadColor)
if puzzleImg.Empty() {
return 0, fmt.Errorf("error reading puzzle image")
}
defer puzzleImg.Close()
result := gocv.NewMat()
defer result.Close()
gocv.MatchTemplate(bgImg, puzzleImg, &result, gocv.TmCcoeffNormed, gocv.NewMat())
_, maxVal, _, maxLoc := gocv.MinMaxLoc(result)
fmt.Printf("Max value: %f, Max location: %v\n", maxVal, maxLoc)
return float64(maxLoc.X), nil
}
func main() {
opts := []selenium.ServiceOption{}
service, err := selenium.NewSeleniumService(seleniumPath, port, opts...)
if err != nil {
log.Fatalf("Error starting the Selenium server: %v", err)
}
defer service.Stop()
caps := selenium.Capabilities{"browserName": "chrome"}
wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", port))
if err != nil {
log.Fatalf("Error connecting to the WebDriver: %v", err)
}
defer wd.Quit()
err = wd.Get("https://dun.163.com/trial/jigsaw")
if err != nil {
log.Fatalf("Error loading page: %v", err)
}
time.Sleep(3 * time.Second)
err = getImage(wd, ".yidun_bg-img", "bg.png")
if err != nil {
log.Fatalf("Error getting background image: %v", err)
}
err = getImage(wd, ".yidun_jigsaw", "puzzle.png")
if err != nil {
log.Fatalf("Error getting puzzle image: %v", err)
}
distance, err := getSlideDistance("bg.png", "puzzle.png")
if err != nil {
log.Fatalf("Error calculating slide distance: %v", err)
}
fmt.Printf("Slide distance: %f\n", distance)
// 后续的验证码处理代码将放在这里
}
4. 模拟滑动行为
模拟人类滑动行为,以避免被检测为机器人。
go
package main
import (
"fmt"
"log"
"math/rand"
"time"
"github.com/tebeka/selenium"
)
func slidePuzzle(wd selenium.WebDriver, distance float64) error {
slider, err := wd.FindElement(selenium.ByCSSSelector, ".yidun_slider")
if err != nil {
return err
}
rect, err := slider.Rect()
if err != nil {
return err
}
startX := rect.X + rect.Width/2
startY := rect.Y + rect.Height/2
err = wd.MoveToObject(slider, 1, 1)
if err != nil {
return err
}
err = wd.ButtonDown()
if err != nil {
return err
}
steps := 30
moveX := distance / float64(steps)
for i := 0; i < steps; i++ {
currentX := startX + int(moveX*float64(i))
err = wd.MoveTo(currentX, startY)
if err != nil {
return err
}
time.Sleep(time.Millisecond * time.Duration(100+rand.Intn(50)))
}
err = wd.ButtonUp()
if err != nil {
return err
}
return nil
}
func main() {
opts := []selenium.ServiceOption{}
service, err := selenium.NewSeleniumService(seleniumPath, port, opts...)
if err != nil {
log.Fatalf("Error starting the Selenium server: %v", err)
}
defer service.Stop()
caps := selenium.Capabilities{"browserName": "chrome"}
wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", port))
if err != nil {
log.Fatalf("Error connecting to the WebDriver: %v", err)
}
defer wd.Quit()
err = wd.Get("https://dun.163.com/trial/jigsaw")
if err != nil {
log.Fatalf("Error loading page: %v", err)
}
time.Sleep(3 * time.Second)
err = getImage(wd, ".yidun_bg-img", "bg.png")
if err != nil {
log.Fatalf("Error getting background image: %v", err)
}
err = getImage(wd, ".yidun_jigsaw", "puzzle.png")
if err != nil {
log.Fatalf("Error getting puzzle image: %v", err)
}
distance, err := getSlideDistance("bg.png", "puzzle.png")
if err != nil {
log.Fatalf("Error calculating slide distance: %v", err)
}
fmt.Printf("Slide distance: %f\n", distance)
err = slidePuzzle(wd, distance)
if err != nil {
log.Fatalf("Error sliding puzzle: %v", err)
}
time.Sleep(5 * time.Second)
}