forked from Davincible/chromedp-undetected
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathactions.go
182 lines (155 loc) · 4.94 KB
/
actions.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
package chromedpundetected
import (
"context"
"encoding/json"
"fmt"
"io"
"math/rand"
"os"
"time"
"github.com/chromedp/cdproto/cdp"
"github.com/chromedp/cdproto/emulation"
"github.com/chromedp/cdproto/network"
"github.com/chromedp/chromedp"
"github.com/Davincible/chromedp-undetected/util/easyjson"
)
// Cookie is used to set browser cookies.
type Cookie struct {
Name string `json:"name" yaml:"name"`
Value string `json:"value" yaml:"value"`
Domain string `json:"domain" yaml:"domain"`
Path string `json:"path" yaml:"path"`
Expires float64 `json:"expires" yaml:"expires"`
HTTPOnly bool `json:"httpOnly" yaml:"httpOnly"`
Secure bool `json:"secure" yaml:"secure"`
}
// UserAgentOverride overwrites the Chrome user agent.
//
// It's better to use this method than emulation.UserAgentOverride.
func UserAgentOverride(userAgent string) chromedp.ActionFunc {
return func(ctx context.Context) error {
return cdp.Execute(ctx, "Network.setUserAgentOverride",
emulation.SetUserAgentOverride(userAgent), nil)
}
}
// LoadCookiesFromFile takes a file path to a json file containing cookies, and
// loads in the cookies into the browser.
func LoadCookiesFromFile(path string) chromedp.ActionFunc {
return chromedp.ActionFunc(func(ctx context.Context) error {
f, err := os.Open(path) //nolint:gosec
if err != nil {
return fmt.Errorf("failed to open file '%s': %w", path, err)
}
data, err := io.ReadAll(f)
if err != nil {
return err
}
if err := f.Close(); err != nil {
return err
}
var cookies []Cookie
if err := json.Unmarshal(data, &cookies); err != nil {
return fmt.Errorf("unmarshal cookies from json: %w", err)
}
return LoadCookies(cookies)(ctx)
})
}
// LoadCookies will load a set of cookies into the browser.
func LoadCookies(cookies []Cookie) chromedp.ActionFunc {
return chromedp.ActionFunc(func(ctx context.Context) error {
for _, cookie := range cookies {
expiry := cdp.TimeSinceEpoch(time.Unix(int64(cookie.Expires), 0))
if err := network.SetCookie(cookie.Name, cookie.Value).
WithHTTPOnly(cookie.HTTPOnly).
WithSecure(cookie.Secure).
WithDomain(cookie.Domain).
WithPath(cookie.Path).
WithExpires(&expiry).
Do(ctx); err != nil {
return err
}
}
return nil
})
}
// SaveCookies extracts the cookies from the current URL and appends them to
// provided array.
func SaveCookies(cookies *[]Cookie) chromedp.ActionFunc {
return chromedp.ActionFunc(func(ctx context.Context) error {
c, err := network.GetCookies().Do(ctx)
if err != nil {
return err
}
for _, cookie := range c {
*cookies = append(*cookies, Cookie{
Name: cookie.Name,
Value: cookie.Value,
Domain: cookie.Domain,
Path: cookie.Path,
Expires: cookie.Expires,
HTTPOnly: cookie.HTTPOnly,
Secure: cookie.HTTPOnly,
})
}
return nil
})
}
// SaveCookiesTo extracts the cookies from the current page and saves them
// as JSON to the provided path.
func SaveCookiesTo(path string) chromedp.ActionFunc {
return chromedp.ActionFunc(func(ctx context.Context) error {
var c []Cookie
if err := SaveCookies(&c).Do(ctx); err != nil {
return err
}
b, err := json.MarshalIndent(c, "", " ")
if err != nil {
return err
}
if err := os.WriteFile(path, b, 0644); err != nil { //nolint:gosec
return err
}
return nil
})
}
// RunCommandWithRes runs any Chrome Dev Tools command, with any params and
// sets the result to the res parameter. Make sure it is a pointer.
//
// In contrast to the native method of chromedp, with this method you can directly
// pass in a map with the data passed to the command.
func RunCommandWithRes(method string, params, res any) chromedp.ActionFunc {
return chromedp.ActionFunc(func(ctx context.Context) error {
i := easyjson.New(params)
o := easyjson.New(res)
return cdp.Execute(ctx, method, i, o)
})
}
// RunCommand runs any Chrome Dev Tools command, with any params.
//
// In contrast to the native method of chromedp, with this method you can directly
// pass in a map with the data passed to the command.
func RunCommand(method string, params any) chromedp.ActionFunc {
return chromedp.ActionFunc(func(ctx context.Context) error {
i := easyjson.New(params)
return cdp.Execute(ctx, method, i, nil)
})
}
// BlockURLs blocks a set of URLs in Chrome.
func BlockURLs(url ...string) chromedp.ActionFunc {
return RunCommand("Network.setBlockedURLs", map[string][]string{"urls": url})
}
// SendKeys does the same as chromedp.SendKeys excepts it randomly waits 100-500ms
// between sending key presses.
func SendKeys(sel any, v string, opts ...chromedp.QueryOption) chromedp.ActionFunc {
return chromedp.ActionFunc(func(ctx context.Context) error {
rand.Seed(time.Now().Unix())
for _, key := range v {
if err := chromedp.SendKeys(sel, string(key), opts...).Do(ctx); err != nil {
return err
}
s := rand.Int63n(100) + 100 //nolint:gosec
time.Sleep(time.Duration(s) * time.Millisecond)
}
return nil
})
}