使用Golang的Colly库实现点击按钮/展开下拉菜单功能的方法
Colly实现动态页面交互操作的解决方案
首先明确结论:Colly本身不支持直接模拟点击按钮、触发JS事件这类浏览器交互行为。Colly的定位是轻量级静态HTTP爬虫,仅会下载目标URL的原始HTML响应,不会执行页面内嵌的JavaScript,也没有浏览器的DOM渲染、事件触发能力,无法直接完成下拉菜单展开、点击触发内容更新这类动态操作。
你可以根据目标站点的反爬强度选择以下两种可行方案:
方案1:抓包构造接口请求(优先推荐)
点击按钮触发页面内容更新的本质,是页面JS在交互后发起了对应的AJAX/Fetch请求拉取新数据,你可以直接抓包拿到这个接口的请求规则,用Colly直接发起请求获取数据,效率远高于模拟浏览器操作。
操作步骤:
- 打开浏览器开发者工具的「网络」面板,点击对应按钮/下拉菜单,过滤XHR/Fetch类型的请求,找到返回目标更新内容的接口
- 分析接口的请求方法、请求头、参数(包括Query参数、请求体、Cookie、CSRF Token等校验字段,如果有加密参数需要逆向对应JS逻辑生成)
- 用Colly构造和浏览器请求完全一致的请求,直接获取返回数据,JSON格式直接解析,HTML片段可以用Colly自带的HTML解析能力提取字段
示例代码:
package main import ( "fmt" "net/http" "github.com/gocolly/colly/v2" ) func main() { // 初始化采集器 c := colly.NewCollector( colly.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"), ) // 先访问初始页面,获取Cookie、CSRF Token等必要校验参数 var csrfToken string c.OnHTML("meta[name=csrf-token]", func(e *colly.HTMLElement) { csrfToken = e.Attr("content") }) c.OnScraped(func(r *colly.Response) { // 构造点击按钮对应的接口请求 apiCollector := c.Clone() apiCollector.OnResponse(func(resp *colly.Response) { fmt.Println("接口返回内容:", string(resp.Body)) // 这里可以做后续的数据提取逻辑 }) // 发起接口请求,带上所有必要的头和参数 err := apiCollector.Request( "POST", "https://目标站点/点击后调用的接口地址", nil, nil, http.Header{ "X-CSRF-Token": []string{csrfToken}, "X-Requested-With": []string{"XMLHttpRequest"}, "Content-Type": []string{"application/x-www-form-urlencoded"}, }, ) if err != nil { panic(err) } }) // 访问初始页面 c.Visit("https://目标站点/初始页面地址") }
方案2:结合无头浏览器实现模拟交互
如果目标站点接口加密逻辑复杂,无法直接构造请求,可以把Colly和Go生态的无头浏览器库搭配使用:用无头浏览器完成模拟点击、页面渲染的操作,拿到完整的渲染后HTML,再交给Colly做数据解析提取。
常用的Go无头浏览器库有chromedp、rod两种,示例基于chromedp实现:
package main import ( "context" "fmt" "github.com/chromedp/chromedp" "github.com/gocolly/colly/v2" ) func main() { // 初始化无头浏览器上下文 ctx, cancel := chromedp.NewContext(context.Background()) defer cancel() var renderedHTML string // 执行模拟交互逻辑 err := chromedp.Run(ctx, chromedp.Navigate("https://目标站点/初始页面地址"), // 等待下拉菜单按钮加载完成 chromedp.WaitVisible(`#dropdown-btn`, chromedp.ByID), // 模拟点击展开下拉菜单 chromedp.Click(`#dropdown-btn`, chromedp.ByID), // 等待目标选项加载完成 chromedp.WaitVisible(`.option-item`, chromedp.ByQuery), // 模拟点击对应选项 chromedp.Click(`.option-item:nth-child(2)`, chromedp.ByQuery), // 等待内容更新区域加载完成 chromedp.WaitVisible(`#content-area`, chromedp.ByID), // 拿到完整渲染后的页面HTML chromedp.OuterHTML("html", &renderedHTML), ) if err != nil { panic(err) } // 将渲染后的HTML交给Colly解析 c := colly.NewCollector() c.OnHTML("#content-area", func(e *colly.HTMLElement) { // 提取目标字段 fmt.Println("提取到的更新内容:", e.Text) }) // 解析HTML内容 c.ParseHTML(renderedHTML) }
内容的提问来源于stack exchange,提问作者fxmb
相关产品推荐
相关产品推荐

