zoukankan      html  css  js  c++  java
  • 重拾chromedp自动操控浏览器-一些例子

    之前总结了chromedp的一些例子,今天找出来供参考:

    package main
    
    import (
        "context"
        "encoding/json"
        "flag"
        "fmt"
        "io"
        "io/ioutil"
        "log"
        "net/http"
        "net/http/httptest"
        "os"
        "strings"
        "time"
    
        "github.com/chromedp/cdproto/cdp"
        "github.com/chromedp/cdproto/dom"
        "github.com/chromedp/cdproto/network"
        "github.com/chromedp/cdproto/page"
        cdpruntime "github.com/chromedp/cdproto/runtime"
        "github.com/chromedp/cdproto/target"
        "github.com/chromedp/chromedp"
        "github.com/chromedp/chromedp/device"
        "github.com/chromedp/chromedp/kb"
    )
    
    func main() {
        log.Printf("example:")
        ExampleListenTarget_acceptAlert()
        //ByJSPath()
        //Emulate()
        //ConsoleLog()
        //ManyTabs()
        //Title()
        //WaitNewTarget()
        //DocumentDump()
        //RetrieveHTML()
        //Download1()
        //Download2()
        //Testiframe()
        //Click()
        //Cookie()
        //Evaluate()
        //Headers()
        //Keys()
        //Logic()
        //Remote()
    
    }
    
    //监听并自动关闭弹出的alert对话框。其中也包括了ExecAllocator的用法
    func ExampleListenTarget_acceptAlert() {
        //内置http测试服务器,用于在网页上显示alert按钮
        ts := httptest.NewServer(writeHTML(`
    <input id='alert' type='button' value='alert' onclick='alert("alert text");'/>please等5秒后,自动点击Alert,并自动关闭alert对话框。
        `))
        defer ts.Close()
        //fmt.Println(ts.URL)
        //增加选项,允许chrome窗口显示出来
        options := []chromedp.ExecAllocatorOption{
            chromedp.Flag("headless", false),
            chromedp.Flag("hide-scrollbars", false),
            chromedp.Flag("mute-audio", false),
            chromedp.UserAgent(`Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36`),
        }
        options = append(chromedp.DefaultExecAllocatorOptions[:], options...)
        //创建chrome窗口
        allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), options...)
        defer cancel()
        ctx, cancel := chromedp.NewContext(allocCtx)
        defer cancel()
    
        //chromedp监听网页上弹出alert对话框
        chromedp.ListenTarget(ctx, func(ev interface{}) {
            if ev, ok := ev.(*page.EventJavascriptDialogOpening); ok {
                fmt.Println("closing alert:", ev.Message)
                go func() {
                    //自动关闭alert对话框
                    if err := chromedp.Run(ctx,
                        //注释掉下一行可以更清楚地看到效果
                        page.HandleJavaScriptDialog(true),
                    ); err != nil {
                        panic(err)
                    }
                }()
            }
        })
    
        if err := chromedp.Run(ctx,
            chromedp.Navigate(ts.URL),
            chromedp.Sleep(5*time.Second),
            //自动点击页面上的alert按钮,弹出alert对话框
            chromedp.Click("#alert", chromedp.ByID),
        ); err != nil {
            panic(err)
        }
    
        // Output:
        // closing alert: alert text
    }
    
    //向内置http服务器页面输出内容
    func writeHTML(content string) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            //在这里设置utf-8,避免乱码
            w.Header().Set("Content-Type", "text/html; charset=utf-8")
            io.WriteString(w, strings.TrimSpace(content))
        })
    }
    
    //用JSPath获取网页元素
    func ByJSPath() {
        ctx, cancel := chromedp.NewContext(context.Background())
        defer cancel()
    
        ts := httptest.NewServer(writeHTML(`
    <body>
        <div id="content">cool content</div>
    </body>
        `))
        defer ts.Close()
    
        var ids []cdp.NodeID
        var html string
        if err := chromedp.Run(ctx,
            chromedp.Navigate(ts.URL),
            //可以在Chrome devTools中,在想要选择的元素上,用鼠标右键>Copy>Copy JS path 得到JSPath
            chromedp.NodeIDs(`document.querySelector("body > div#content")`, &ids, chromedp.ByJSPath),
            chromedp.ActionFunc(func(ctx context.Context) error {
                var err error
                html, err = dom.GetOuterHTML().WithNodeID(ids[0]).Do(ctx)
                return err
            }),
        ); err != nil {
            panic(err)
        }
    
        fmt.Println("Outer HTML:")
        fmt.Println(html)
    }
    
    //模拟不同的设备访问网站。其中也包括了ExecAllocator的用法
    func Emulate() {
        //增加选项,允许chrome窗口显示出来
        options := []chromedp.ExecAllocatorOption{
            chromedp.Flag("headless", false),
            chromedp.Flag("hide-scrollbars", false),
            chromedp.Flag("mute-audio", false),
            chromedp.UserAgent(`Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36`),
        }
        options = append(chromedp.DefaultExecAllocatorOptions[:], options...)
        //创建chrome窗口
        allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), options...)
        defer cancel()
        ctx, cancel := chromedp.NewContext(allocCtx)
        defer cancel()
    
        var buf []byte
        if err := chromedp.Run(ctx,
            chromedp.Emulate(device.IPhone7),
            chromedp.Navigate(`https://baidu.com/`),
            //chromedp.WaitVisible(`#kw`, chromedp.ByID),
            chromedp.Sleep(3*time.Second),
            chromedp.SendKeys(`input[name=word]`, "what's my user agent?
    "),
            //chromedp.WaitVisible(`#lg`, chromedp.ByID),
            chromedp.Sleep(3*time.Second),
            chromedp.CaptureScreenshot(&buf),
        ); err != nil {
            panic(err)
        }
    
        if err := ioutil.WriteFile("baidu-iphone7.png", buf, 0644); err != nil {
            panic(err)
        }
    }
    
    //获取chrome控制台的内容
    func ConsoleLog() {
        //增加选项,允许chrome窗口显示出来
        options := []chromedp.ExecAllocatorOption{
            chromedp.Flag("headless", false),
            chromedp.Flag("hide-scrollbars", false),
            chromedp.Flag("mute-audio", false),
            chromedp.UserAgent(`Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36`),
        }
        options = append(chromedp.DefaultExecAllocatorOptions[:], options...)
        //创建chrome窗口
        allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), options...)
        defer cancel()
        ctx, cancel := chromedp.NewContext(allocCtx)
        defer cancel()
        ts := httptest.NewServer(writeHTML(`
    <body>
    <script>
        console.log("hello js world")
        console.warn("warn hello js world")    
        var p = document.createElement("div");
        p.setAttribute("id", "jsFinished");
        document.body.appendChild(p);
    </script>
    </body>
        `))
        defer ts.Close()
    
        chromedp.ListenTarget(ctx, func(ev interface{}) {
            switch ev := ev.(type) {
            case *cdpruntime.EventConsoleAPICalled:
                fmt.Printf("console.%s call:
    ", ev.Type)
                for _, arg := range ev.Args {
                    fmt.Printf("%s - %s
    ", arg.Type, arg.Value)
                }
    
            }
    
        })
    
        if err := chromedp.Run(ctx,
            chromedp.Navigate(ts.URL),
            chromedp.Sleep(5*time.Second), //在打开的chrome窗口上有提示:chrome正受到自动测试软件的控制
            chromedp.WaitVisible("#jsFinished", chromedp.ByID),
        ); err != nil {
            panic(err)
        }
    }
    
    //控制多个chrome tab页
    func ManyTabs() {
        // new browser, first tab
        ctx1, cancel := chromedp.NewContext(context.Background())
        defer cancel()
    
        // ensure the first tab is created
        if err := chromedp.Run(ctx1); err != nil {
            panic(err)
        }
    
        // same browser, second tab
        ctx2, _ := chromedp.NewContext(ctx1)
    
        // ensure the second tab is created
        if err := chromedp.Run(ctx2); err != nil {
            panic(err)
        }
    
        c1 := chromedp.FromContext(ctx1)
        c2 := chromedp.FromContext(ctx2)
    
        fmt.Printf("Same browser: %t
    ", c1.Browser == c2.Browser)
        fmt.Printf("Same tab: %t
    ", c1.Target == c2.Target)
    }
    func Title() {
        ctx, cancel := chromedp.NewContext(context.Background())
        defer cancel()
    
        ts := httptest.NewServer(writeHTML(`
    <head>
        <title>fancy website title</title>
    </head>
    <body>
        <div id="content"></div>
    </body>
        `))
        defer ts.Close()
    
        var title string
        if err := chromedp.Run(ctx,
            chromedp.Navigate(ts.URL),
            chromedp.Title(&title),
        ); err != nil {
            panic(err)
        }
        fmt.Println(title)
    }
    
    //等待chrome打开新的tab页,
    func WaitNewTarget() {
        ctx, cancel := chromedp.NewContext(context.Background())
        defer cancel()
    
        mux := http.NewServeMux()
        mux.Handle("/first", writeHTML(`
    <input id='newtab' type='button' value='open' onclick='window.open("/second", "_blank");'/>
        `))
        mux.Handle("/second", writeHTML(``))
        ts := httptest.NewServer(mux)
        defer ts.Close()
    
        // Grab the first spawned tab that isn't blank.
        ch := chromedp.WaitNewTarget(ctx, func(info *target.Info) bool {
            return info.URL != ""
        })
        if err := chromedp.Run(ctx,
            chromedp.Navigate(ts.URL+"/first"),
            chromedp.Click("#newtab", chromedp.ByID),
        ); err != nil {
            panic(err)
        }
        newCtx, cancel := chromedp.NewContext(ctx, chromedp.WithTargetID(<-ch))
        defer cancel()
    
        var urlstr string
        if err := chromedp.Run(newCtx, chromedp.Navigate("https://www.baidu.com"), chromedp.Location(&urlstr)); err != nil {
            panic(err)
        }
        fmt.Println("new tab's path:", strings.TrimPrefix(urlstr, ts.URL))
    }
    
    //向页面注入javascript并执行,获取执行后的页面DOM结构。
    //核心是使用runtime.Evaluate
    func DocumentDump() {
        ctx, cancel := chromedp.NewContext(context.Background())
        defer cancel()
    
        ts := httptest.NewServer(writeHTML(`<!doctype html>
    <html>
    <body>
      <div id="content">the content</div>
    <iframe src="https://www.baidu.com"></iframe>
    </body>
    </html>`))
        defer ts.Close()
    
        const expr = `(function(d, id, v) {
            var b = d.querySelector('body');
            var el = d.createElement('div');
            el.id = id;
            el.innerText = v;
            b.insertBefore(el, b.childNodes[0]);
        })(document, %q, %q);`
    
        var nodes []*cdp.Node
        if err := chromedp.Run(ctx,
            chromedp.Navigate(ts.URL),
            chromedp.Nodes(`document`, &nodes, chromedp.ByJSPath),
            chromedp.WaitVisible(`#content`),
            chromedp.ActionFunc(func(ctx context.Context) error {
                s := fmt.Sprintf(expr, "thing", "a new thing!")
                _, exp, err := cdpruntime.Evaluate(s).Do(ctx)
                if err != nil {
                    return err
                }
                if exp != nil {
                    return exp
                }
                return nil
            }),
            chromedp.WaitVisible(`#thing`),
        ); err != nil {
            panic(err)
        }
    
        fmt.Println("Document tree:")
        fmt.Print(nodes[0].Dump("  ", "  ", false))
    }
    
    //获取网页html源码
    //核心是使用OuterHTML
    func RetrieveHTML() {
        ctx, cancel := chromedp.NewContext(context.Background())
        defer cancel()
    
        ts := httptest.NewServer(writeHTML(`
    <body>
    <p id="content" onclick="changeText()">Original content.</p>
    <iframe src="https://www.baidu.com"></iframe>
    <script>
    function changeText() {
        document.getElementById("content").textContent = "New content!"
    }
    </script>
    </body>
        `))
        defer ts.Close()
    
        var outerBefore, outerAfter string
        if err := chromedp.Run(ctx,
            chromedp.Navigate(ts.URL),
            chromedp.OuterHTML("#content", &outerBefore),
            chromedp.Click("#content", chromedp.ByID),
            chromedp.OuterHTML("#content", &outerAfter),
        ); err != nil {
            panic(err)
        }
        fmt.Println("OuterHTML before clicking:")
        fmt.Println(outerBefore)
        fmt.Println("OuterHTML after clicking:")
        fmt.Println(outerAfter)
    }
    
    //download1的测试
    func Download1() {
        //开启静态文件服务器
        http.Handle("/", http.FileServer(http.Dir("E:/goapp/src/chromedpnewExample/")))
        http.Handle("/index", writeHTML(`<!doctype html>
    <html>
    <body>  
     <a  id="down" href="123.zip">download</a>
    </body>
    </html>`))
        go http.ListenAndServe(":9090", nil)
        //增加选项,允许chrome窗口显示出来
        options := []chromedp.ExecAllocatorOption{
            chromedp.Flag("headless", false),
            chromedp.Flag("hide-scrollbars", false),
            chromedp.Flag("mute-audio", false),
            chromedp.UserAgent(`Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36`),
        }
        options = append(chromedp.DefaultExecAllocatorOptions[:], options...)
        //创建chrome窗口
        allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), options...)
        defer cancel()
        ctx, cancel := chromedp.NewContext(allocCtx)
        defer cancel()
        //下载目录
        wd, _ := os.Getwd()
        wd += "\d"
        fmt.Println(wd)
        if err := chromedp.Run(ctx,
            page.SetDownloadBehavior(page.SetDownloadBehaviorBehaviorAllow).WithDownloadPath(wd),
            chromedp.Navigate("http://www.mersenne.org/ftp_root/gimps/p95v287.MacOSX.noGUI.tar.gz"),
            chromedp.Sleep(3*time.Second), //这里不知道如何等待下载结束?如果chrome设置成headless为true的时候下载不正常?
        ); err != nil {
            panic(err)
        }
        fmt.Println("down load ok")
    
    }
    
    //download2的测试
    //123.zip为任意压缩包,存放于主程序目录下;并在主程序所在目录中新建子目录d
    func Download2() {
        //开启静态文件服务器
        http.Handle("/", http.FileServer(http.Dir("E:/goapp/src/chromedpnewExample/")))
        http.Handle("/index", writeHTML(`<!doctype html>
    <html>
    <body>  
     <a  id="down" href="123.zip">download</a>
    </body>
    </html>`))
        go http.ListenAndServe(":9090", nil)
        //增加选项,允许chrome窗口显示出来
        options := []chromedp.ExecAllocatorOption{
            chromedp.Flag("headless", false),
            chromedp.Flag("hide-scrollbars", false),
            chromedp.Flag("mute-audio", false),
            chromedp.UserAgent(`Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36`),
        }
        options = append(chromedp.DefaultExecAllocatorOptions[:], options...)
        //创建chrome窗口
        allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), options...)
        defer cancel()
        ctx, cancel := chromedp.NewContext(allocCtx)
        defer cancel()
        //下载目录
        wd, _ := os.Getwd()
        wd += "\d"
        fmt.Println(wd)
        if err := chromedp.Run(ctx,
            page.SetDownloadBehavior(page.SetDownloadBehaviorBehaviorAllow).WithDownloadPath(wd),
            chromedp.Navigate("http://localhost:9090/index"),
            chromedp.WaitVisible("#down"),
            chromedp.Click("#down", chromedp.ByID),
            chromedp.Sleep(3*time.Second), //这里不知道如何等待下载结束?如果chrome设置成headless为true的时候下载不正常?
        ); err != nil {
            panic(err)
        }
        fmt.Println("down load ok")
    
    }
    
    //iframe的测试
    
    /*123.html
    <html>
    <body>
    <a id="clickme" href="https://www.google.com>clickme!</a>
    </body>
    </htm>
    */
    func Testiframe() {
        //开启静态文件服务器
        wd, _ := os.Getwd()
        http.Handle("/", http.FileServer(http.Dir(wd)))
        http.Handle("/index", writeHTML(`<!doctype html>
    <html>
    <body>
      <div id="content" name="content name">the content</div> 
    <iframe src="123.html"></iframe>
    </body>
    </html>`))
        go http.ListenAndServe(":9090", nil)
        framefile123 := `
    <html><body>
    <a id="clickme" href="https://www.google.com">clickme!</a>
    </body></html>
        `
        f123 := []byte(framefile123)
        if err := ioutil.WriteFile("./123.html", f123, 0666); err != nil {
            panic(err)
        }
    
        //增加选项,允许chrome窗口显示出来
        options := []chromedp.ExecAllocatorOption{
            chromedp.Flag("headless", false),
            chromedp.Flag("hide-scrollbars", false),
            chromedp.Flag("mute-audio", false),
            chromedp.UserAgent(`Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36`),
        }
        options = append(chromedp.DefaultExecAllocatorOptions[:], options...)
        //创建chrome窗口
        allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), options...)
        defer cancel()
        ctx, cancel := chromedp.NewContext(allocCtx)
        defer cancel()
        var outer, url, frameurl string
        var ok bool
        if err := chromedp.Run(ctx,
            chromedp.Navigate("http://localhost:9090/index"),
            chromedp.Sleep(2*time.Second),
            chromedp.WaitVisible("iframe", chromedp.ByQuery),
            chromedp.AttributeValue("iframe", "src", &outer, &ok),
            chromedp.Location(&url),
        ); err != nil {
            panic(err)
        }
        fmt.Println("Outer:", outer, " url:", url)
        frameurl = url[0:strings.LastIndex(url, "/")] + "/" + outer
        fmt.Println("frameurl", frameurl)
        if err := chromedp.Run(ctx,
            chromedp.Navigate(frameurl),
            chromedp.Sleep(2*time.Second),
            chromedp.WaitVisible("#clickme"),
            chromedp.Click("#clickme", chromedp.ByID),
            chromedp.Sleep(2*time.Second),
        ); err != nil {
            panic(err)
        }
    }
    
    //以下例子来自https://github.com/chromedp/examples
    //单击元素,获取textarea的value
    func Click() {
        // create chrome instance
        ctx, cancel := chromedp.NewContext(
            context.Background(),
            chromedp.WithLogf(log.Printf),
        )
        defer cancel()
    
        // create a timeout
        ctx, cancel = context.WithTimeout(ctx, 15*time.Second)
        defer cancel()
    
        // navigate to a page, wait for an element, click
        var example string
        err := chromedp.Run(ctx,
            chromedp.Navigate(`https://golang.org/pkg/time/`),
            // wait for footer element is visible (ie, page is loaded)
            chromedp.WaitVisible(`body > footer`),
            // find and click "Expand All" link
            chromedp.Click(`#pkg-examples > div`, chromedp.NodeVisible),
            // retrieve the value of the textarea
            chromedp.Value(`#example_After .play .input textarea`, &example),
        )
        if err != nil {
            log.Fatal(err)
        }
        log.Printf("Go's time.After example:
    %s", example)
    }
    
    //设置Cookie
    func Cookie() {
        var (
            flagPort = flag.Int("port", 8544, "port")
        )
        flag.Parse()
    
        // start cookie server
        go cookieServer(fmt.Sprintf(":%d", *flagPort))
    
        // create context
        ctx, cancel := chromedp.NewContext(context.Background())
        defer cancel()
    
        // run task list
        var res string
        err := chromedp.Run(ctx, setcookies(
            fmt.Sprintf("http://localhost:%d", *flagPort), &res,
            "cookie1", "value1",
            "cookie2", "value2",
        ))
        if err != nil {
            log.Fatal(err)
        }
    
        log.Printf("main: chrome received cookies: %s", res)
    }
    
    // cookieServer creates a simple HTTP server that logs any passed cookies.
    func cookieServer(addr string) error {
        mux := http.NewServeMux()
        mux.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
            cookies := req.Cookies()
            for i, cookie := range cookies {
                log.Printf("server:  from %s, server received cookie %d: %v", req.RemoteAddr, i, cookie)
            }
            buf, err := json.MarshalIndent(req.Cookies(), "", "  ")
            if err != nil {
                http.Error(res, err.Error(), http.StatusInternalServerError)
                return
            }
            fmt.Fprintf(res, indexHTML, string(buf))
        })
        return http.ListenAndServe(addr, mux)
    }
    
    // setcookies returns a task to navigate to a host with the passed cookies set
    // on the network request.
    func setcookies(host string, res *string, cookies ...string) chromedp.Tasks {
        if len(cookies)%2 != 0 {
            panic("length of cookies must be divisible by 2")
        }
        return chromedp.Tasks{
            chromedp.ActionFunc(func(ctx context.Context) error {
                // create cookie expiration
                expr := cdp.TimeSinceEpoch(time.Now().Add(180 * 24 * time.Hour))
                // add cookies to chrome
                for i := 0; i < len(cookies); i += 2 {
                    success, err := network.SetCookie(cookies[i], cookies[i+1]).
                        WithExpires(&expr).
                        WithDomain("localhost").
                        WithHTTPOnly(true).
                        Do(ctx)
                    if err != nil {
                        return err
                    }
                    if !success {
                        return fmt.Errorf("could not set cookie %q to %q", cookies[i], cookies[i+1])
                    }
                }
                return nil
            }),
            // navigate to site
            chromedp.Navigate(host),
            // read the returned values
            chromedp.Text(`#result`, res, chromedp.ByID, chromedp.NodeVisible),
            // read network values
            chromedp.ActionFunc(func(ctx context.Context) error {
                cookies, err := network.GetAllCookies().Do(ctx)
                if err != nil {
                    return err
                }
    
                for i, cookie := range cookies {
                    log.Printf("chromedp:  chrome cookie %d: %+v", i, cookie)
                }
    
                return nil
            }),
        }
    }
    
    const (
        indexHTML = `<!doctype html>
    <html>
    <body>
      <div id="result">%s</div>
    </body>
    </html>`
    )
    
    //执行javascript,显示window对象的keys
    func Evaluate() {
        // create context
        ctx, cancel := chromedp.NewContext(context.Background())
        defer cancel()
    
        // run task list
        var res []string
        err := chromedp.Run(ctx,
            chromedp.Navigate(`https://www.baidu.com/`),
            chromedp.WaitVisible(`#wrapper`, chromedp.ByID),
            chromedp.Evaluate(`Object.keys(window);`, &res),
        )
        if err != nil {
            log.Fatal(err)
        }
    
        log.Printf("window object keys: %v", res)
    }
    
    func Headers() {
        var (
            flagPort = flag.Int("port", 8544, "port")
        )
        flag.Parse()
    
        // run server
        go headerServer(fmt.Sprintf(":%d", *flagPort))
    
        // create context
        ctx, cancel := chromedp.NewContext(context.Background())
        defer cancel()
    
        // run task list
        var res string
        err := chromedp.Run(ctx, setheaders(
            fmt.Sprintf("http://localhost:%d", *flagPort),
            map[string]interface{}{
                "X-Header": "my request header",
            },
            &res,
        ))
        if err != nil {
            log.Fatal(err)
        }
    
        log.Printf("received headers: %s", res)
    }
    
    // headerServer is a simple HTTP server that displays the passed headers in the html.
    func headerServer(addr string) error {
        mux := http.NewServeMux()
        mux.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
            buf, err := json.MarshalIndent(req.Header, "", "  ")
            if err != nil {
                http.Error(res, err.Error(), http.StatusInternalServerError)
                return
            }
            fmt.Fprintf(res, indexHTML_headers, string(buf))
        })
        return http.ListenAndServe(addr, mux)
    }
    
    // setheaders returns a task list that sets the passed headers.
    func setheaders(host string, headers map[string]interface{}, res *string) chromedp.Tasks {
        return chromedp.Tasks{
            network.Enable(),
            network.SetExtraHTTPHeaders(network.Headers(headers)),
            chromedp.Navigate(host),
            chromedp.Text(`#result`, res, chromedp.ByID, chromedp.NodeVisible),
        }
    }
    
    const indexHTML_headers = `<!doctype html>
    <html>
    <body>
      <div id="result">%s</div>
    </body>
    </html>`
    
    func Keys() {
        var (
            flagPort = flag.Int("port", 8544, "port")
        )
        flag.Parse()
    
        // run server
        go testServer(fmt.Sprintf(":%d", *flagPort))
    
        //增加选项,允许chrome窗口显示出来
        options := []chromedp.ExecAllocatorOption{
            chromedp.Flag("headless", false),
            chromedp.Flag("hide-scrollbars", false),
            chromedp.Flag("mute-audio", false),
            chromedp.UserAgent(`Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36`),
        }
        options = append(chromedp.DefaultExecAllocatorOptions[:], options...)
        //创建chrome窗口
        allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), options...)
        defer cancel()
        // create context
        ctx, cancel := chromedp.NewContext(allocCtx)
        defer cancel()
    
        // run task list
        var val1, val2, val3, val4 string
        err := chromedp.Run(ctx, sendkeys(fmt.Sprintf("http://localhost:%d", *flagPort), &val1, &val2, &val3, &val4))
        if err != nil {
            log.Fatal(err)
        }
    
        log.Printf("#input1 value: %s", val1)
        log.Printf("#textarea1 value: %s", val2)
        log.Printf("#input2 value: %s", val3)
        log.Printf("#select1 value: %s", val4)
    }
    
    // sendkeys sends
    func sendkeys(host string, val1, val2, val3, val4 *string) chromedp.Tasks {
        return chromedp.Tasks{
            chromedp.Navigate(host),
            chromedp.WaitVisible(`#input1`, chromedp.ByID),
            chromedp.WaitVisible(`#textarea1`, chromedp.ByID),
            chromedp.Sleep(3 * time.Second),
            chromedp.SendKeys(`#textarea1`, kb.End+"
    
    aoeu
    
    test1
    
    blah2
    
    			other box!	
    test4", chromedp.ByID),
            chromedp.Sleep(3 * time.Second),
            chromedp.Value(`#input1`, val1, chromedp.ByID),
            chromedp.Value(`#textarea1`, val2, chromedp.ByID),
            chromedp.SetValue(`#input2`, "test3", chromedp.ByID),
            chromedp.Sleep(3 * time.Second),
            chromedp.Value(`#input2`, val3, chromedp.ByID),
            chromedp.SendKeys(`#select1`, kb.ArrowDown+kb.ArrowDown, chromedp.ByID),
            chromedp.Sleep(3 * time.Second),
            chromedp.Value(`#select1`, val4, chromedp.ByID),
        }
    }
    
    // testServer is a simple HTTP server that displays the passed headers in the html.
    func testServer(addr string) error {
        mux := http.NewServeMux()
        mux.HandleFunc("/", func(res http.ResponseWriter, _ *http.Request) {
            fmt.Fprint(res, indexHTML_keys)
        })
        return http.ListenAndServe(addr, mux)
    }
    
    const indexHTML_keys = `<!doctype html>
    <html>
    <head>
      <title>example</title>
    </head>
    <body>
      <div id="box1" style="display:none">
        <div id="box2">
          <p>box2</p>
        </div>
      </div>
      <div id="box3">
        <h2>box3</h3>
        <p id="box4">
          box4 text
          <input id="input1" value="some value"><br><br>
          <textarea id="textarea1" style="500px;height:400px">textarea</textarea><br><br>
          <input id="input2" type="submit" value="Next">
          <select id="select1">
            <option value="one">1</option>
            <option value="two">2</option>
            <option value="three">3</option>
            <option value="four">4</option>
          </select>
        </p>
      </div>
    </body>
    </html>`
    
    //复杂逻辑,获取页面标题和链接
    func Logic() {
        // create context
        ctx, cancel := chromedp.NewContext(context.Background())
        defer cancel()
    
        // list awesome go projects for the "Selenium and browser control tools."
        res, err := listAwesomeGoProjects(ctx, "Selenium and browser control tools.")
        if err != nil {
            log.Fatalf("could not list awesome go projects: %v", err)
        }
    
        // output the values
        for k, v := range res {
            log.Printf("project %s (%s): '%s'", k, v.URL, v.Description)
        }
    }
    
    // projectDesc contains a url, description for a project.
    type projectDesc struct {
        URL, Description string
    }
    
    // listAwesomeGoProjects is the highest level logic for browsing to the
    // awesome-go page, finding the specified section sect, and retrieving the
    // associated projects from the page.
    func listAwesomeGoProjects(ctx context.Context, sect string) (map[string]projectDesc, error) {
        // force max timeout of 15 seconds for retrieving and processing the data
        var cancel func()
        ctx, cancel = context.WithTimeout(ctx, 15*time.Second)
        defer cancel()
    
        sel := fmt.Sprintf(`//p[text()[contains(., '%s')]]`, sect)
    
        // navigate
        if err := chromedp.Run(ctx, chromedp.Navigate(`https://github.com/avelino/awesome-go`)); err != nil {
            return nil, fmt.Errorf("could not navigate to github: %v", err)
        }
    
        // wait visible
        if err := chromedp.Run(ctx, chromedp.WaitVisible(sel)); err != nil {
            return nil, fmt.Errorf("could not get section: %v", err)
        }
    
        sib := sel + `/following-sibling::ul/li`
    
        // get project link text
        var projects []*cdp.Node
        if err := chromedp.Run(ctx, chromedp.Nodes(sib+`/child::a/text()`, &projects)); err != nil {
            return nil, fmt.Errorf("could not get projects: %v", err)
        }
    
        // get links and description text
        var linksAndDescriptions []*cdp.Node
        if err := chromedp.Run(ctx, chromedp.Nodes(sib+`/child::node()`, &linksAndDescriptions)); err != nil {
            return nil, fmt.Errorf("could not get links and descriptions: %v", err)
        }
    
        // check length
        if 2*len(projects) != len(linksAndDescriptions) {
            return nil, fmt.Errorf("projects and links and descriptions lengths do not match (2*%d != %d)", len(projects), len(linksAndDescriptions))
        }
    
        // process data
        res := make(map[string]projectDesc)
        for i := 0; i < len(projects); i++ {
            res[projects[i].NodeValue] = projectDesc{
                URL:         linksAndDescriptions[2*i].AttributeValue("href"),
                Description: strings.TrimPrefix(strings.TrimSpace(linksAndDescriptions[2*i+1].NodeValue), "- "),
            }
        }
    
        return res, nil
    }
    
    //这个没测试成功
    func Remote() {
        var devToolWsUrl string
        flag.StringVar(&devToolWsUrl, "devtools-ws-url", "", "DevTools Websocket URL")
        flag.Parse()
    
        actxt, cancelActxt := chromedp.NewRemoteAllocator(context.Background(), devToolWsUrl)
        defer cancelActxt()
    
        ctxt, cancelCtxt := chromedp.NewContext(actxt) // create new tab
        defer cancelCtxt()                             // close tab afterwards
    
        var body string
        if err := chromedp.Run(ctxt,
            chromedp.Navigate("https://baidu.com"),
            chromedp.WaitVisible("#logo_homepage_link"),
            chromedp.OuterHTML("html", &body),
        ); err != nil {
            log.Fatalf("Failed getting body of pleasegiveurl: %v", err)
        }
    
        log.Println("Body of  pleasegiveurl starts with:")
        log.Println(body[0:100])
    }
  • 相关阅读:
    ubuntu远程windows桌面
    spring boot 给返回值加状态 BaseData
    spring boot 拦截异常 统一处理
    IntelliJ IDEA spring boot 远程Ddbug调试
    IntelliJ IDEA 常用插件
    spring boot 请求地址带有.json 兼容处理
    spring boot 接口返回值去掉为null的字段
    spring boot 集成disconf
    Spring boot 自定义拦截器
    Linux下安装MySQL
  • 原文地址:https://www.cnblogs.com/pu369/p/12330074.html
Copyright © 2011-2022 走看看