Skip to content

Instantly share code, notes, and snippets.

@djmally
Created April 16, 2018 19:36
Show Gist options
  • Save djmally/80cda4b9d8f1e3728d50f6a89f4e3382 to your computer and use it in GitHub Desktop.
Save djmally/80cda4b9d8f1e3728d50f6a89f4e3382 to your computer and use it in GitHub Desktop.
package main
import (
"context"
"fmt"
"time"
"github.com/mafredri/cdp"
"github.com/mafredri/cdp/devtool"
"github.com/mafredri/cdp/protocol/input"
"github.com/mafredri/cdp/protocol/network"
"github.com/mafredri/cdp/protocol/page"
"github.com/mafredri/cdp/protocol/runtime"
"github.com/mafredri/cdp/rpcc"
)
func main() {
// Demo program that clicks, focuses, and injects text into an <input>
// element on some webpage.
//
// Assumes a Chrome browser instance listening on `localhost:9222`.
//
// Change the `example.com` URL below to your desired
// page. Note that you won't see any useful results if the page doesn't
// have any <input> tags on it.
client := createClient()
// *** CHANGE THIS TO YOUR DESIRED URL *** ----------------------------------------------v
_, err := client.Page.Navigate(context.Background(), page.NewNavigateArgs("http://www.example.com"))
if err != nil {
panic(err.Error())
}
// Try to click on some input element
if _, err := client.Runtime.Evaluate(context.Background(), runtime.NewEvaluateArgs("document.querySelector(\"input\").click()")); err != nil {
panic(err.Error())
}
// Try to focus on some input element
if _, err := client.Runtime.Evaluate(context.Background(), runtime.NewEvaluateArgs("document.querySelector(\"input\").focus()")); err != nil {
panic(err.Error())
}
// Enter text
password := "hunter2"
for _, char := range password {
err := client.Input.DispatchKeyEvent(context.Background(), input.NewDispatchKeyEventArgs("keyDown").SetText(string(char)))
if err != nil {
panic(err.Error())
}
}
}
// creatClient repeatedly attempts to connect to Chrome, and returns a client instance once it connects
func createClient() *cdp.Client {
var client *cdp.Client
for client == nil {
var err error
client, err = connectDevtools("localhost", 9222)
if err != nil {
fmt.Println("Error connecting to Chrome", "error", err)
fmt.Println("Retrying connection....")
}
time.Sleep(1 * time.Second)
}
return client
}
// newClient creates a CDP client and performs some domain initialization
func newClient(conn *rpcc.Conn) (*cdp.Client, error) {
client := cdp.NewClient(conn)
// Enable various domains on the client
if err := client.Runtime.Enable(context.Background()); err != nil {
return nil, err
}
if err := client.Network.Enable(context.Background(), network.NewEnableArgs()); err != nil {
return nil, err
}
if err := client.Page.Enable(context.Background()); err != nil {
return nil, err
}
return client, nil
}
// connectDevtools performs the actual browser connection and RPCC setup
func connectDevtools(host string, port uint16) (*cdp.Client, error) {
// Create a devtools instance
dt := devtool.New(fmt.Sprintf("http://%s:%d", host, port))
// Select the page (tab) context in the browser
target, err := dt.Get(context.Background(), devtool.Page)
if err != nil {
// If there was no page context, create a new one
target, err = dt.Create(context.Background())
if err != nil {
return nil, err
}
}
// Initiate a new RPC connection to the Chrome Debugging Protocol target.
conn, err := rpcc.DialContext(
context.Background(),
target.WebSocketDebuggerURL,
rpcc.WithWriteBufferSize(104857586),
)
if err != nil {
return nil, err
}
return newClient(conn)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment