一、工具库安装与基础配置
1. 核心库安装
# 安装rod核心库
go get github.com/go-rod/rod
# 安装stealth隐身插件
go get github.com/go-rod/stealth
# 安装stepper行为模拟器
go get github.com/go-rod/stepper
# 安装代理支持模块
go get github.com/go-rod/rod/lib/proxy
2. 可选工具安装
# 安装浏览器启动器控制
go get github.com/go-rod/rod/lib/launcher
# 安装设备模拟器
go get github.com/go-rod/rod/lib/devices
# 安装截图工具
go get github.com/go-rod/rod/lib/utils
二、完整配置示例
1. 基础隐身配置
package main
import (
"github.com/go-rod/rod"
"github.com/go-rod/stealth"
"time"
)
func main() {
// 启动浏览器(带隐身配置)
browser := rod.New().
Trace(true). // 启用操作追踪
MustConnect()
defer browser.MustClose()
// 创建隐身页面
page := stealth.MustPage(browser)
// 设置随机视窗尺寸(避免统一分辨率)
page.MustSetViewport(&proto.EmulationSetDeviceMetricsOverride{
Width: randomInt(1200, 1920),
Height: randomInt(800, 1080),
Scale: 1,
})
// 导航到目标网站
page.MustNavigate("https://target-site.com").MustWaitLoad()
// 随机停留时间
time.Sleep(time.Duration(randomInt(3, 8)) * time.Second)
}
func randomInt(min, max int) int {
return rand.Intn(max-min) + min
}
2. 高级行为模拟示例
package main
import (
"github.com/go-rod/rod"
"github.com/go-rod/stealth"
"github.com/go-rod/stepper"
"time"
)
func main() {
// 初始化浏览器
browser := rod.New().
Proxy("socks5://user:pass@proxy-ip:port").
MustConnect()
defer browser.MustClose()
// 创建隐身页面
page := stealth.MustPage(browser)
page.MustNavigate("https://example.com/login").MustWaitLoad()
// 复杂行为模拟
stepper.New().
// 第一阶段:浏览行为
RandomDelay(2, 5).
MoveMouse(page, 0, 0, 30).
Scroll(page, 0, 500, 20).
Click(page, "#help-link").
// 第二阶段:登录操作
RandomDelay(1, 3).
Type(page, "#username", "[email protected]", 60).
RandomDelay(500, 1500). // 0.5-1.5秒
Type(page, "#password", "securePass123", 80).
RandomDelay(1, 2).
MoveMouse(page, 300, 200, 15).
Click(page, "#login-btn").
// 执行所有操作
Run()
// 验证登录成功
if page.MustHas(".welcome-message") {
page.MustScreenshot("welcome.png")
}
}
三、代理管理与轮换实现
1. 代理池实现
package proxy
import (
"sync"
"time"
)
type ProxyPool struct {
proxies []string
current int
lock sync.Mutex
lastChange time.Time
}
func NewProxyPool(proxies []string) *ProxyPool {
return &ProxyPool{
proxies: proxies,
}
}
func (p *ProxyPool) Get() string {
p.lock.Lock()
defer p.lock.Unlock()
// 每5分钟自动轮换
if time.Since(p.lastChange) > 5*time.Minute {
p.current = (p.current + 1) % len(p.proxies)
p.lastChange = time.Now()
}
return p.proxies[p.current]
}
2. 集成代理轮换的爬虫
package main
import (
"./proxy"
"github.com/go-rod/rod"
"time"
)
func main() {
// 初始化代理池
proxies := []string{
"http://proxy1:8080",
"socks5://proxy2:1080",
"http://user:pass@proxy3:3128",
}
pool := proxy.NewProxyPool(proxies)
// 创建浏览器实例
browser := rod.New().
ControlURL(launcher.New().
Proxy(pool.Get()).
MustLaunch()).
MustConnect()
defer browser.MustClose()
// 每小时轮换代理
go func() {
for range time.Tick(time.Hour) {
browser.ControlURL(launcher.New().
Proxy(pool.Get()).
MustLaunch())
}
}()
// 爬虫主逻辑...
}
四、验证码处理方案
1. 自动识别集成
package captcha
import (
"encoding/base64"
"io/ioutil"
"net/http"
)
type Solver interface {
Solve(image []byte) (string, error)
}
type TwoCaptcha struct {
APIKey string
}
func (t *TwoCaptcha) Solve(image []byte) (string, error) {
// 实现2Captcha API调用
encoded := base64.StdEncoding.EncodeToString(image)
resp, err := http.PostForm("https://2captcha.com/in.php",
url.Values{
"key": {t.APIKey},
"method": {"base64"},
"body": {encoded},
})
// 处理响应...
return solution, nil
}
2. 验证码处理流程
func handleCaptcha(page *rod.Page) {
// 定位验证码元素
captcha := page.MustElement("#captcha-image")
// 获取验证码图片
imgBytes := captcha.MustScreenshot()
// 使用验证码服务
solver := &captcha.TwoCaptcha{APIKey: "your-api-key"}
text, err := solver.Solve(imgBytes)
if err != nil {
panic(err)
}
// 输入验证码
page.MustElement("#captcha-input").MustInput(text)
page.MustElement("#submit-btn").MustClick()
}
五、异常处理与恢复
1. 智能恢复机制
func safeScrape(page *rod.Page, url string) (string, error) {
var result string
err := rod.Try(func() {
page.MustNavigate(url).MustWaitLoad()
// 检查是否被拦截
if page.MustHas("#block-page") {
panic("block detected")
}
result = page.MustElement("body").MustText()
})
if err != nil {
// 保存调试信息
page.MustScreenshot("error.png")
log.Printf("Error scraping %s: %v", url, err)
// 执行恢复流程
recoverFromError(page)
return "", err
}
return result, nil
}
func recoverFromError(page *rod.Page) {
// 1. 尝试刷新页面
page.MustReload()
// 2. 如果仍然失败,更换代理
if page.MustHas("#block-page") {
rotateProxy(page)
page.MustReload()
}
// 3. 最终回退方案
if page.MustHas("#block-page") {
page.MustClose()
panic("permanent block detected")
}
}
六、最佳实践建议
环境隔离:为每个任务创建独立的浏览器实例
browser := rod.New().MustConnect() defer browser.MustClose() // 确保资源释放
指纹多样化:
// 随机选择设备配置 devices := []*proto.EmulationSetDeviceMetricsOverride{ {Width: 1366, Height: 768}, {Width: 1920, Height: 1080}, {Width: 1536, Height: 864}, } page.MustSetViewport(devices[rand.Intn(len(devices))])
流量伪装:
// 模拟常规浏览流量 page.MustNavigate("https://google.com") stepper.New().RandomDelay(3, 8).Run() page.MustNavigate(targetURL)
定期维护:
// 每2小时重启浏览器 go func() { for range time.Tick(2 * time.Hour) { browser.MustClose() browser = rod.New().MustConnect() } }()