-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbrowser_automation.go
134 lines (117 loc) · 3.88 KB
/
browser_automation.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
package main
import (
"context"
"fmt"
"github.com/chromedp/cdproto/cdp"
"github.com/chromedp/chromedp"
"os"
"strconv"
"sync"
"time"
)
var nextRemoteDebuggingPort = 9444
var remoteDebuggingPortAllocateLock = sync.Mutex{}
func GetBrowserCtx() (context.Context, context.CancelFunc) {
options := append(chromedp.DefaultExecAllocatorOptions[:],
chromedp.UserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"),
)
if os.Getenv("IS_IN_CONTAINER") == "" {
//options = append(options, chromedp.Flag("headless", false))
}
// use lock to avoid assigning a single port to multiple instance when concurrently calling this method
remoteDebuggingPortAllocateLock.Lock()
options = append(options, chromedp.Flag("enable-automation", false),
chromedp.Flag("disable-blink-features", "AutomationControlled"),
chromedp.Flag("remote-debugging-port", strconv.FormatInt(int64(nextRemoteDebuggingPort), 10)), // use chrome://inspect to connect to remote target and debug
chromedp.Flag("remote-debugging-address", "0.0.0.0"), // allow access outside the container
chromedp.WindowSize(2280, 1020),
// chromedp.Flag("lang", "zh-CN"),
)
logger.Infof("remote debugging port %v assigned", nextRemoteDebuggingPort)
nextRemoteDebuggingPort++
remoteDebuggingPortAllocateLock.Unlock()
allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), options...)
return allocCtx, cancel
}
// AutomationSuite is a tool set for chromedp for quick development of iWebsiteAgent.
type AutomationSuite struct{}
var browser AutomationSuite
func (s AutomationSuite) GetCurrentURL(ctx context.Context) (currentURL string, err error) {
err = chromedp.Run(ctx, chromedp.Tasks{
chromedp.Evaluate(`document.URL`, ¤tURL),
})
if err != nil {
return "", err
}
return currentURL, nil
}
func (s AutomationSuite) GetCurrentTitle(ctx context.Context) (title string, err error) {
err = chromedp.Run(ctx, chromedp.Tasks{
chromedp.Title(&title),
})
if err != nil {
return "", err
}
return title, nil
}
func (s AutomationSuite) GetHTML(ctx context.Context) (html string, err error) {
err = chromedp.Run(ctx, chromedp.Tasks{
chromedp.OuterHTML("html", &html),
})
if err != nil {
return "", err
}
return html, nil
}
func (s AutomationSuite) IsElementHidden(sel string, isHidden *bool) chromedp.Action {
return chromedp.EvaluateAsDevTools(fmt.Sprintf(`window.getComputedStyle(document.querySelector('%s')).display === 'none'`, sel), &isHidden)
}
func (s AutomationSuite) WaitUntilDocumentReady() chromedp.Action {
return chromedp.ActionFunc(func(ctx context.Context) error {
for {
var state string
err := chromedp.Evaluate(`document.readyState`, &state).Do(ctx)
if err != nil {
return err
}
if state == "complete" {
return nil
}
time.Sleep(time.Millisecond * 100)
}
})
}
func (s AutomationSuite) WaitUntilInvisible(ctx context.Context, selector string) error {
for {
var nodes []*cdp.Node
err := chromedp.Run(ctx,
chromedp.Nodes(selector, &nodes, chromedp.AtLeast(0)),
) // make sure exist
if err != nil {
return err
}
if len(nodes) == 0 {
return nil
}
var isHidden bool
err = chromedp.Run(ctx,
chromedp.EvaluateAsDevTools(fmt.Sprintf(`window.getComputedStyle(document.querySelector('%s')).display === 'none'`, selector), &isHidden),
)
if err != nil {
return err
}
if isHidden {
return nil
}
}
}
func (s AutomationSuite) GetWebElementWithWait(ctx context.Context, selector string) (*cdp.Node, error) {
ctx, cancel := context.WithTimeout(ctx, 300*time.Second)
defer cancel()
var nodes []*cdp.Node
err := chromedp.Run(ctx, chromedp.Nodes(selector, &nodes, chromedp.BySearch, chromedp.AtLeast(1)))
if err != nil {
return nil, fmt.Errorf("WaitWithTimeoutAndInterval failed: %w", err)
}
return nodes[0], nil // 返回第一个匹配的节点
}