Created
March 30, 2020 07:15
-
-
Save zhengchun/d38f6e63f57e4320ad0f0a245fad7fb4 to your computer and use it in GitHub Desktop.
chromedp event callback
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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