Skip to content

Instantly share code, notes, and snippets.

@zhengchun
Created March 30, 2020 07:15
Show Gist options
  • Save zhengchun/d38f6e63f57e4320ad0f0a245fad7fb4 to your computer and use it in GitHub Desktop.
Save zhengchun/d38f6e63f57e4320ad0f0a245fad7fb4 to your computer and use it in GitHub Desktop.
chromedp event callback
package main
import (
"context"
"log"
"encoding/json"
"fmt"
"strings"
"github.com/chromedp/cdproto"
"github.com/chromedp/cdproto/network"
"github.com/chromedp/cdproto/page"
"github.com/chromedp/cdproto/cdp"
"github.com/chromedp/chromedp"
"github.com/chromedp/chromedp/runner"
)
var (
msgChann = make(chan cdproto.Message)
ctxt context.Context
)
func devToolHandler(s string, is ...interface{}) {
/*
Uncomment the following line to have a log of the events
log.Printf(s, is...)
*/
/*
We need this to be on a separate gorutine
otherwise we block the browser and we don't receive messages
*/
go func () {
for _, elem := range is {
var msg cdproto.Message
// The CDP messages are sent as strings so we need to convert them back
json.Unmarshal([]byte(fmt.Sprintf("%s", elem)), &msg)
msgChann <- msg
}
}()
}
func main() {
// create context
ctxt, cancel := context.WithCancel(context.Background())
defer cancel()
// create chrome instance
c, err := chromedp.New(ctxt,
chromedp.WithRunnerOptions(
runner.Flag("disable-infobars", true)),
chromedp.WithLog(devToolHandler))
if err != nil {
log.Fatal(err)
}
err = c.Run(ctxt, network.Enable())
if err != nil {
log.Println(err)
}
c.Run(ctxt, chromedp.ActionFunc(func(_ context.Context, h cdp.Executor) error {
// This is in an action function because the Executor is needed in some method
go func() {
for {
/*
Right now I have no guaranties (did not run enough tests) that the messages are evaluated
in the same order they are received
*/
msg := <- msgChann
switch msg.Method.String() {
case "Page.frameScheduledNavigation":
var schednavevent page.EventFrameScheduledNavigation
json.Unmarshal(msg.Params, &schednavevent)
fmt.Println(schednavevent.URL)
case "Network.requestWillBeSent":
var reqWillSend network.EventRequestWillBeSent
json.Unmarshal(msg.Params, &reqWillSend)
fmt.Println(reqWillSend.Request.URL)
case "Network.responseReceived":
var respevent network.EventResponseReceived
// json.Unmarshal(msg.Params, &respevent)
// This contains a bunch of data, like the response headers
fmt.Println(respevent.Response)
/*
Uncomment the following lines if you want to print the response body
rbp := network.GetResponseBody(respevent.RequestID)
b, e := rbp.Do(ctxt, h)
if e != nil {
fmt.Println(e)
continue
}
fmt.Printf("%s\n", b)
*/
default:
continue
}
}
}()
return nil
}))
err = c.Run(ctxt, chromedp.Navigate("https://duckduckgo.com"))
if err != nil {
log.Fatal(err)
}
/*
Since chromedp.Navigate does not wait for the page to be fully loaded
we wait manually, there may be a better and more reliable way to do this
*/
state := "notloaded"
for {
script := `document.readyState`
err = c.Run(ctxt, chromedp.EvaluateAsDevTools(script, &state))
if err != nil {
log.Println(err)
}
if strings.Compare(state, "complete") == 0 {
break
}
}
// shutdown chrome
err = c.Shutdown(ctxt)
if err != nil {
log.Fatal(err)
}
// wait for chrome to finish the shutdown
err = c.Wait()
if err != nil {
log.Fatal(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment