日期:7月8日
作者:Commas
签名:(ง •_•)ง 积跬步以致千里,积小流以成江海……
注释:如果您觉得
有所帮助
,帮忙点个赞
,也可以关注我
,我们一起成长;如果有不对的地方,还望各位大佬不吝赐教,谢谢^ - ^1.01365 = 37.7834;0.99365 = 0.0255
1.02365 = 1377.4083;0.98365 = 0.0006
文章目录
一、前言二、分析问题(1)打开 Lorca 库(2)分析 Lorca 库中的 New 函数 三、解决问题四、最终效果展示一、前言
上期教程《【Go|第5期】Lorca无法正常运行的解决方案》解决了Chrome
安全机制导致无法正常运行Lorca
程序的问题。小伙伴们可能又发现了另外一个问题,Lorca
窗口的副标题上多了一行非常醒目的字:Chrome正受到自动测试软件的控制。虽然功能方面不受影响,但是这一行字却足以让你的用户感到困惑。
示例一:
示例二:
示例三:
二、分析问题
关于“Chrome正受到自动测试软件的控制”这个副标题的问题,一般是由于浏览器的自动化测试工具或插件所引起的。这些工具可能会在浏览器窗口的标题栏中显示此消息,以指示当前的浏览器会话处于自动化测试模式下。
第一点,Lorca整个运行过程中,没有使用Selenium
或其他类似的自动化测试框架进行Web
应用程序测试;第二点,Lorca在启动的时候,添加了禁用浏览器扩展(Extensions
)功能的命令行启动参数;第三点,旧版Chrome
不会显示此类副标题,可能没有实现这一功能,而新版则增加了这个浏览器行为,旨在提醒用户当前浏览器正处于自动化测试模式下。
不确定未来最新版本会不会解决此问题,与其寄托未来,不如把握现在。既然是自动化测试(automation
)这个因素引起的,那么我们是否可以查找一下Lorca
是否运行的时候有添加此类参数呢?
(1)打开 Lorca 库
main.go
的代码片段:package mainimport ("log""net/url""/zserge/lorca")func main() {// Create UI with basic HTML passed via data URIui, err := lorca.New("data:text/html,"+url.PathEscape(`<html><head><title>Hello</title></head><body><h1>Hello, world!</h1></body></html>`), "", 480, 320, "--remote-allow-origins=*")if err != nil {log.Fatal(err)}defer ui.Close()// Wait until UI window is closed<-ui.Done()}
截图说明:
Ctrl + 鼠标左键
,点选lorca.New
中的New
, 打开Lorca
库。Lorca
库的ui.go
代码片段
func New(url, dir string, width, height int, customArgs ...string) (UI, error) {if url == "" {url = "data:text/html,<html></html>"}tmpDir := ""if dir == "" {name, err := ioutil.TempDir("", "lorca")if err != nil {return nil, err}dir, tmpDir = name, name}args := append(defaultChromeArgs, fmt.Sprintf("--app=%s", url))args = append(args, fmt.Sprintf("--user-data-dir=%s", dir))args = append(args, fmt.Sprintf("--window-size=%d,%d", width, height))args = append(args, customArgs...)args = append(args, "--remote-debugging-port=0")chrome, err := newChromeWithArgs(ChromeExecutable(), args...)done := make(chan struct{})if err != nil {return nil, err}go func() {chrome.cmd.Wait()close(done)}()return &ui{chrome: chrome, done: done, tmpDir: tmpDir}, nil}
(2)分析 Lorca 库中的 New 函数
1、chrome, err := newChromeWithArgs(ChromeExecutable(), args...)
这一行代码是创建一个chrome
实例,其中args
就是启动程序的命令行参数的切片(slice
)。
这些参数也并非我们所要查找的参数,这里可以过了。
2、接着,我们顺藤摸瓜看一下customArgs
,如下:
var defaultChromeArgs = []string{"--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-client-side-phishing-detection","--disable-default-apps","--disable-dev-shm-usage","--disable-infobars","--disable-extensions","--disable-features=site-per-process","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-popup-blocking","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-sync","--disable-translate","--disable-windows10-custom-titlebar","--metrics-recording-only","--no-first-run","--no-default-browser-check","--safebrowsing-disable-auto-update","--enable-automation","--password-store=basic","--use-mock-keychain",}
其中,--enable-automation
貌似与自动化测试(automation
)有关,这不就是我们想要找到参数吗?
另外,在上述命令行中,我们也发现了--disable-infobars
命令,用于启动Chromium
网页浏览器并禁用副标题(也叫做信息栏)功能。该信息栏就是浏览器窗口顶部显示通知、警告或其他消息的小型信息栏,然而新版chrome
目前已不再支持该命令了,这才是导致问题出现的真正原因。
三、解决问题
不希望看到"Chrome正受到自动测试软件的控制" 这个副标题,可以在启动Chrome
时省略--enable-automation
标志,或者将其设置为--disable-automation
。这里我们以省略--enable-automation
做演示:
完整的ui.go
代码,可以直接拿走,覆盖原来的代码即可使用,如下:
package lorcaimport ("encoding/json""errors""fmt""io/ioutil""os""reflect")// UI interface allows talking to the HTML5 UI from Go.type UI interface {Load(url string) errorBounds() (Bounds, error)SetBounds(Bounds) errorBind(name string, f interface{}) errorEval(js string) ValueDone() <-chan struct{}Close() error}type ui struct {chrome *chromedone chan struct{}tmpDir string}var defaultChromeArgs = []string{"--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-client-side-phishing-detection","--disable-default-apps","--disable-dev-shm-usage","--disable-infobars","--disable-extensions","--disable-features=site-per-process","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-popup-blocking","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-sync","--disable-translate","--disable-windows10-custom-titlebar","--metrics-recording-only","--no-first-run","--no-default-browser-check","--safebrowsing-disable-auto-update","--password-store=basic","--use-mock-keychain",}// New returns a new HTML5 UI for the given URL, user profile directory, window// size and other options passed to the browser engine. If URL is an empty// string - a blank page is displayed. If user profile directory is an empty// string - a temporary directory is created and it will be removed on// ui.Close(). You might want to use "--headless" custom CLI argument to test// your UI code.func New(url, dir string, width, height int, customArgs ...string) (UI, error) {if url == "" {url = "data:text/html,<html></html>"}tmpDir := ""if dir == "" {name, err := ioutil.TempDir("", "lorca")if err != nil {return nil, err}dir, tmpDir = name, name}args := append(defaultChromeArgs, fmt.Sprintf("--app=%s", url))args = append(args, fmt.Sprintf("--user-data-dir=%s", dir))args = append(args, fmt.Sprintf("--window-size=%d,%d", width, height))args = append(args, customArgs...)args = append(args, "--remote-debugging-port=0")chrome, err := newChromeWithArgs(ChromeExecutable(), args...)done := make(chan struct{})if err != nil {return nil, err}go func() {chrome.cmd.Wait()close(done)}()return &ui{chrome: chrome, done: done, tmpDir: tmpDir}, nil}func (u *ui) Done() <-chan struct{} {return u.done}func (u *ui) Close() error {// ignore err, as the chrome process might be already dead, when user close the window.u.chrome.kill()<-u.doneif u.tmpDir != "" {if err := os.RemoveAll(u.tmpDir); err != nil {return err}}return nil}func (u *ui) Load(url string) error {return u.chrome.load(url) }func (u *ui) Bind(name string, f interface{}) error {v := reflect.ValueOf(f)// f must be a functionif v.Kind() != reflect.Func {return errors.New("only functions can be bound")}// f must return either value and error or just errorif n := v.Type().NumOut(); n > 2 {return errors.New("function may only return a value or a value+error")}return u.chrome.bind(name, func(raw []json.RawMessage) (interface{}, error) {if len(raw) != v.Type().NumIn() {return nil, errors.New("function arguments mismatch")}args := []reflect.Value{}for i := range raw {arg := reflect.New(v.Type().In(i))if err := json.Unmarshal(raw[i], arg.Interface()); err != nil {return nil, err}args = append(args, arg.Elem())}errorType := reflect.TypeOf((*error)(nil)).Elem()res := v.Call(args)switch len(res) {case 0:// No results from the function, just return nilreturn nil, nilcase 1:// One result may be a value, or an errorif res[0].Type().Implements(errorType) {if res[0].Interface() != nil {return nil, res[0].Interface().(error)}return nil, nil}return res[0].Interface(), nilcase 2:// Two results: first one is value, second is errorif !res[1].Type().Implements(errorType) {return nil, errors.New("second return value must be an error")}if res[1].Interface() == nil {return res[0].Interface(), nil}return res[0].Interface(), res[1].Interface().(error)default:return nil, errors.New("unexpected number of return values")}})}func (u *ui) Eval(js string) Value {v, err := u.chrome.eval(js)return value{err: err, raw: v}}func (u *ui) SetBounds(b Bounds) error {return u.chrome.setBounds(b)}func (u *ui) Bounds() (Bounds, error) {return u.chrome.bounds()}
四、最终效果展示
示例一:
示例二:
示例三:
参考文章:
《List of Chromium Command Line Switches》
我的微信公众号会飞的小猴子,等你来关注哦 ^ - ^
版权声明:本文为博主原创文章,如需转载,请给出:
原文链接:/qq_35844043/article/details/131612569