chromedp 新选项卡爬虫处理

起因

相信很多人都遇到这种情况,我们访问网站的时候,点击某个链接,访问的页面会在浏览器新标签或者新窗口中显示。我在使用chromedp进行爬虫时,如果进行点击事件,并且a标签的属性未target="_blank",chromdp不会获取新标签的Context,而是仍会停留在原来的Context,这个时候我们就需要监听新的标签。

例子

/**
 * 注册新tab标签的监听服务   
 */
package main

import (
	"context"
	"github.com/chromedp/cdproto/target"
	"github.com/chromedp/chromedp"
	"log"
	"net/http"
	"net/http/httptest"
	"time"
)

/**
 * 注册新tab标签的监听服务
 */
func addNewTabListener(ctx context.Context) <-chan target.ID {
	mux := http.NewServeMux()
	ts := httptest.NewServer(mux)
	defer ts.Close()

	return chromedp.WaitNewTarget(ctx, func(info *target.Info) bool {
		return info.URL != ""
	})
}


func main() {
	// 
	opts := append(chromedp.DefaultExecAllocatorOptions[:],
		chromedp.NoDefaultBrowserCheck,                   //不检查默认浏览器
		chromedp.Flag("headless", false),                 //开启图像界面
		chromedp.Flag("ignore-certificate-errors", true), //忽略错误
		chromedp.Flag("disable-web-security", true),      //禁用网络安全标志
		chromedp.Flag("disable-extensions", false),  .//开启插件支持
		chromedp.Flag("disable-default-apps", false),
		chromedp.NoFirstRun, //不是首次运行
		chromedp.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36"),

	)

	allocCtx, _ := chromedp.NewExecAllocator(context.Background(), opts...)
	//	defer cancel()
	//标签1
	ctx, _ := chromedp.NewContext(
		allocCtx,
		chromedp.WithLogf(log.Printf),
	)
	
	ch := addNewTabListener(ctx)
	// run task list
	err := chromedp.Run(ctx,
		chromedp.Navigate("https://buyin.jinritemai.com/dashboard/live/control"),
		chromedp.Sleep(3*time.Second),
		chromedp.WaitReady(`._1M2DJMjmtJZhkk7ei5nC9F`, chromedp.ByQuery),
		chromedp.Sleep(5*time.Second),
		chromedp.Click(`._1M2DJMjmtJZhkk7ei5nC9F`, chromedp.ByQuery, chromedp.NodeNotVisible),
	)
	if err != nil {
		log.Fatal(err)
	}
	//标签2
	newCtx, _ := chromedp.NewContext(ctx, chromedp.WithTargetID(<-ch))
	var res string
	err= chromedp.Run(newCtx,
		chromedp.WaitReady(`#app`,chromedp.ByID),
		chromedp.Text(`#app`,&res, chromedp.NodeVisible, chromedp.ByID),
		)
	if err != nil {
		log.Fatal(err)
	}
	log.Println((res))

}

参考

https://studygolang.com/articles/30736
https://github.com/chromedp/chromedp/issues/367