-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
224 lines (192 loc) · 6.51 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
// The init program contains various examples of initialization and
// customization of browser sessions in Chrome Vision.
package main
import (
"context"
"log"
"os"
"time"
"github.com/daabr/chrome-vision/pkg/devtools"
"github.com/daabr/chrome-vision/pkg/devtools/page"
"github.com/daabr/chrome-vision/pkg/devtools/target"
)
func main() {
MinimalSession()
SessionWithTimeout()
BrowserCustomizations()
MultipleBrowsers()
MultipleBrowserTabs()
CleanupAfterSession()
CustomOutputRootDir()
}
// MinimalSession is an example of a minimalistic session initialization.
func MinimalSession() {
// Start a new browser.
ctx, err := devtools.NewContext(context.Background())
if err != nil {
log.Fatal(err)
}
// Kill the browser forcefully. If you want to close it gracefully,
// call the `devtools.Close` function instead.
defer devtools.Cancel(ctx)
// Do stuff...
// Optional (because of the `defer` above): send the browser a command
// to close itself gracefully, and wait until this is done.
devtools.Close(ctx)
}
// SessionWithTimeout is an example of a browsing session with a timeout
// for the entire session's lifetime.
func SessionWithTimeout() {
// Set an idiomatic timeout (or deadline) for the entire session,
// i.e. the browser will be killed as soon as the timeout expires.
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// Start a new browser.
ctx, err := devtools.NewContext(ctx)
if err != nil {
log.Fatal(err)
}
// No need to call `defer devtools.Cancel(ctx)` because `defer cancel()`
// above will propagate the cancellation to its descendant - the browsing
// session context.
// Do stuff...
// Optional (because of the `defer` above): send the browser a command
// to close itself gracefully, and wait until this is done.
devtools.Close(ctx)
}
// BrowserCustomizations is an example of customizing the browser during
// initialization, by modifying its execution path and command-line flags.
func BrowserCustomizations() {
// Customize the browser command-line flags, before starting it.
flags := devtools.DefaultBrowserFlags()
flags["disable-gpu"] = true // https://crbug.com/765284
flags["window-size"] = "1920,1080"
delete(flags, "headless")
// The `devtools.NewContext` function supports 0 or more customizations.
// Other options to consider: `devtools.BrowserPath` (to run a custom
// binary from a specific location) and `devtools.UserDataDir` (to use
// an existing non-temporary user data directory - useful if you want
// non-default user settings or user data in the browsing session).
ctx, err := devtools.NewContext(context.Background(), devtools.BrowserFlags(flags))
if err != nil {
log.Fatal(err)
}
defer devtools.Cancel(ctx)
// Do stuff...
devtools.Close(ctx)
}
// MultipleBrowsers is an example of running multiple browsers side-by-side.
func MultipleBrowsers() {
ctx := context.Background()
// Start the first new browser.
ctx1, err := devtools.NewContext(ctx)
if err != nil {
log.Fatal(err)
}
defer devtools.Cancel(ctx1)
// Start the second new browser.
ctx2, err := devtools.NewContext(ctx)
if err != nil {
log.Fatal(err)
}
defer devtools.Cancel(ctx2)
// Do stuff in the first browser...
nav := page.NewNavigate("https://en.wikipedia.org/wiki/1")
if _, err := nav.Do(ctx1); err != nil {
log.Fatal(err)
}
// Do stuff in the second browser...
nav = page.NewNavigate("https://en.wikipedia.org/wiki/2")
if _, err := nav.Do(ctx2); err != nil {
log.Fatal(err)
}
}
// MultipleBrowserTabs is an example of multi-tab browsing, with "chain"
// initialization of a second session as a descendant of the first one.
func MultipleBrowserTabs() {
// Chrome doesn't allow using tabs in headless mode.
flags := devtools.DefaultBrowserFlags()
flags["window-size"] = "1920,1080"
delete(flags, "headless")
// Start a new browser (first tab).
ctx1, err := devtools.NewContext(context.Background(), devtools.BrowserFlags(flags))
if err != nil {
log.Fatal(err)
}
defer devtools.Cancel(ctx1)
// Do stuff in the first tab...
nav := page.NewNavigate("https://en.wikipedia.org/wiki/1")
if _, err := nav.Do(ctx1); err != nil {
log.Fatal(err)
}
// Open a second tab in the existing browser.
ctx2, err := devtools.NewContext(ctx1)
if err != nil {
log.Fatal(err)
}
// No need to call `defer devtools.Cancel(ctx2)` because the `defer` above
// will propagate the cancellation of the main browsing session context
// (ctx1) to its descendant - the second tab's context (ctx2).
// Do stuff in the second tab...
nav = page.NewNavigate("https://en.wikipedia.org/wiki/2")
if _, err := nav.Do(ctx2); err != nil {
log.Fatal(err)
}
// Do stuff in the first tab again...
if session, ok := devtools.FromContext(ctx1); ok {
focus := target.NewActivateTarget(session.TargetID.Read())
if err := focus.Do(ctx1); err != nil {
log.Fatal(err)
}
}
nav = page.NewNavigate("https://en.wikipedia.org/wiki/3")
if _, err := nav.Do(ctx1); err != nil {
log.Fatal(err)
}
}
// CleanupAfterSession is an example of cleaning-up Chrome Vision's output
// directory (which contains logs and user data) after the session is done.
func CleanupAfterSession() {
// Start a new browser.
ctx, err := devtools.NewContext(context.Background())
if err != nil {
log.Fatal(err)
}
defer func() {
if session, ok := devtools.FromContext(ctx); ok {
log.Printf("Session output directory: %s", session.OutputDir)
os.RemoveAll(session.OutputDir)
log.Print("Delorted!")
}
}()
// Defer the `Cancel` call AFTER the cleanup function
// (https://tour.golang.org/flowcontrol/13).
defer devtools.Cancel(ctx)
// Do stuff...
}
// CustomOutputRootDir is an example of changing (and ultimately deleting)
// the default root directory where Chrome Vision's output directories
// (which contain logs and user data) are created.
func CustomOutputRootDir() {
customDir, err := os.MkdirTemp("", "foo_*")
if err != nil {
log.Fatalf(`os.MkdirTemp("", "foo_*"); got unexpected error: %v`, err)
}
defer func() {
os.RemoveAll(customDir)
}()
// We create an output directory per browser process, which contains
// logs and user data. By default, this directory is created under
// Go's `os.TempDir()` - see https://golang.org/pkg/os/#TempDir). The
// optional environment variable "CDP_OUTPUT_ROOT" overrides this path.
os.Setenv(devtools.OutputRootEnv, customDir)
defer os.Unsetenv(devtools.OutputRootEnv)
// Start a new browser.
ctx, err := devtools.NewContext(context.Background())
if err != nil {
log.Fatal(err)
}
defer devtools.Cancel(ctx)
// Do stuff...
devtools.Close(ctx)
}