使用 Chromedp 监听网页请求和响应
在进行网络爬虫的时候,有很多网站都有反爬机制,比如你想抓点数据,结果发现每次请求都带一堆奇奇怪怪的参数 —— 什么 timestamp 签名、AES 加密的字段,还有各种 Token 令牌,跟密码本似的。你直接看网页源代码吧,那些 JS 代码被混淆得亲妈都不认识,像一团乱麻似的根本理不清头绪。
这时候我们可以使用chromedp来监听网页请求,它的核心价值在于:第一不用费劲巴拉地去解密那些被混淆的 JS 代码,直接拿现成的参数用;第二能盯着不同操作时参数怎么变,比如刷新页面时哪个值会变,登录时多了哪个字段;
什么是 Chromedp
ChromeDP 是一个 Go 语言实现的库,它提供了无头浏览器的操作和控制能力,可以用来进行网页自动化、爬虫和测试等工作。通过 ChromeDP,我们可以编程方式监听网页上的各种事件,包括网络请求和响应。
环境准备
首先,我们需要安装 Go 和 ChromeDP 库:
// 安装 ChromeDP
go get -u github.com/chromedp/chromedp
演示代码
下面是一个基本的示例,演示如何使用 ChromeDP 监听网页请求:
package main
import (
"context"
"encoding/base64"
"fmt"
"log"
"time"
"github.com/chromedp/cdproto/network"
"github.com/chromedp/chromedp"
)
func EnBase64(base64String string) string {
decodedBytes, err := base64.StdEncoding.DecodeString(base64String)
if err != nil {
log.Println("解码错误:", err)
return ""
}
return string(decodedBytes)
}
func main() {
// 创建一个带取消功能的上下文
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
defer cancel()
// 创建一个ChromeDP选项,启用网络事件
opts := append(chromedp.DefaultExecAllocatorOptions[:],
chromedp.Flag("headless", false),
chromedp.Flag("disable-gpu", true),
chromedp.Flag("enable-automation", true),
chromedp.Flag("disable-extensions", true),
)
allocCtx, cancel := chromedp.NewExecAllocator(ctx, opts...)
defer cancel()
// 创建一个新的浏览器实例
taskCtx, taskCancel := chromedp.NewContext(allocCtx)
defer taskCancel() // 确保在退出时取消 taskCtx
// 监听请求开始事件
chromedp.ListenTarget(taskCtx, func(ev interface{}) {
switch e := ev.(type) {
case *network.EventRequestWillBeSent:
// 打印请求信息
fmt.Printf("请求URL: %s\n", e.Request.URL)
fmt.Printf("请求方法: %s\n", e.Request.Method)
fmt.Printf("请求头: %v\n", e.Request.Headers)
// 如果有请求体,打印请求体
if e.Request.HasPostData {
entries := e.Request.PostDataEntries
for _, entry := range entries {
fmt.Printf("请求体: %s\n", EnBase64(entry.Bytes))
}
}
fmt.Println("------------------------")
case *network.EventResponseReceived:
// 打印响应信息
fmt.Printf("响应URL: %s\n", e.Response.URL)
fmt.Printf("响应状态: %d\n", e.Response.Status)
fmt.Printf("响应头: %v\n", e.Response.Headers)
// 获取响应体
/*
不知道怎么回事直接在ListenTarget中使用GetResponseBody,会一直报错invalid context
关于GetResponseBody 处理可以看 https://github.com/chromedp/chromedp/issues/427
*/
go func() {
chromedp.Run(taskCtx, chromedp.ActionFunc(func(ctx context.Context) error {
body, err := network.GetResponseBody(e.RequestID).Do(ctx)
if err != nil {
fmt.Println(err)
}
fmt.Printf("响应体: %s\n", string(body))
return nil
}))
}()
fmt.Println("------------------------")
}
})
// 启用网络监听
if err := chromedp.Run(taskCtx,
network.Enable(),
// 访问指定网页
chromedp.Navigate("https://blog.csdn.net/yang731227"),
// 等待页面加载完成
chromedp.Sleep(15*time.Second),
); err != nil {
log.Fatal(err)
}
}
过滤特定类型的请求
如果您只想监听特定类型的请求(例如,只关注 XHR 请求或特定 URL 模式),可以这样做:
// 在 EventRequestWillBeSent 事件处理中添加过滤逻辑
case *network.EventRequestWillBeSent:
// 只关注 XHR 请求
if e.Type == network.ResourceTypeXHR {
fmt.Printf("XHR请求: %s %s\n", e.Request.Method, e.Request.URL)
}
// 或者只关注特定URL模式
if strings.Contains(e.Request.URL, "api") {
fmt.Printf("API请求: %s %s\n", e.Request.Method, e.Request.URL)
}