You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Golang+goquery爬取动态验证码并维持会话提交表单?

解决方案

步骤1:保存首次请求页面的验证码图片

核心是复用会话(Cookie),因为验证码与当前会话绑定,单独请求验证码地址会拿到新的无效验证码。具体实现:

package main

import (
	"io"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"os"

	"github.com/PuerkitoBio/goquery"
)

func main() {
	// 初始化带CookieJar的客户端,维持会话一致性
	jar, _ := cookiejar.New(nil)
	client := &http.Client{Jar: jar}

	// 1. 请求目标页面(首次请求,必须保留会话)
	targetURL := "https://example.com/your-target-page"
	resp, err := client.Get(targetURL)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	// 2. 解析页面,提取验证码图片的src属性
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		panic(err)
	}
	captchaSrc, exists := doc.Find("img[src*='/nn/mm/captchaimg']").Attr("src")
	if !exists {
		panic("未找到验证码图片标签")
	}

	// 拼接完整的验证码请求URL(处理相对路径)
	baseURL, _ := url.Parse(targetURL)
	captchaURL := baseURL.ResolveReference(&url.URL{Path: captchaSrc}).String()

	// 3. 用同一个客户端请求验证码,保存图片到本地
	captchaResp, err := client.Get(captchaURL)
	if err != nil {
		panic(err)
	}
	defer captchaResp.Body.Close()

	file, err := os.Create("captcha.png")
	if err != nil {
		panic(err)
	}
	defer file.Close()
	_, err = io.Copy(file, captchaResp.Body)
	if err != nil {
		panic(err)
	}
}

关键要点:

  • 必须复用同一个http.Client(带CookieJar)请求页面和验证码,确保会话一致;
  • 处理验证码的相对路径,拼接成完整URL避免请求错误;
  • 保存的图片就是首次页面绑定的有效验证码,可直接传入深度学习模型识别。

步骤3:维持会话提交表单

核心是提取首次页面的所有表单参数(包括隐藏字段),复用会话提交,不能重新请求页面。代码示例(承接上面的main函数):

// 接步骤1的代码,在保存验证码之后

	// 1. 解析表单的action地址和所有字段
	form := doc.Find("form").First()
	formAction, exists := form.Attr("action")
	if !exists {
		panic("未找到表单提交地址")
	}
	// 拼接完整的表单提交URL
	formSubmitURL := baseURL.ResolveReference(&url.URL{Path: formAction}).String()

	// 收集表单所有字段(含隐藏字段,如CSRF Token)
	formData := url.Values{}
	form.Find("input").Each(func(i int, s *goquery.Selection) {
		name, _ := s.Attr("name")
		value, _ := s.Attr("value")
		if name != "" {
			formData.Set(name, value)
		}
	})

	// 2. 填入深度学习模型识别的验证码结果(替换为实际字段名,如"verify_code")
	recognizedCode := "XXXX" // 替换为你的识别结果
	formData.Set("captcha_code", recognizedCode)

	// 3. 用同一个客户端提交表单,维持会话
	submitResp, err := client.PostForm(formSubmitURL, formData)
	if err != nil {
		panic(err)
	}
	defer submitResp.Body.Close()

	// 读取提交结果(可选,用于验证是否提交成功)
	submitBody, _ := io.ReadAll(submitResp.Body)
	println(string(submitBody))

关键要点:

  • 必须从首次请求的页面提取所有表单字段,包括CSRF Token这类会话绑定的隐藏字段,重新请求页面会导致字段失效;
  • 提交时复用同一个http.Client,确保Cookie与首次请求一致;
  • 确认验证码对应的表单字段名(需根据目标页面实际调整,比如可能是captcha、verify_code等)。

额外注意事项

  • 验证码有效期1-2分钟,需控制识别和提交的总时长,避免超时;
  • 部分网站会验证请求头,可给客户端统一设置模拟浏览器的请求头:
// 替换原有的client.Get(targetURL),手动构造请求添加头
req, err := http.NewRequest("GET", targetURL, nil)
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36")
req.Header.Set("Referer", targetURL)
resp, err := client.Do(req)

内容的提问来源于stack exchange,提问作者Hong Sup Lee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 06:40:43