解決自動化登陸的問題,順即可以解決爬蟲問題。css
selenium: Selenium 是一個用於 Web 應用程序測試的工具,Selenium 測試直接自動運行在瀏覽器中,就像真正的用戶在手工操做同樣。html
webdriver: chromeDriver是谷歌爲網站開發人員提供的自動化測試工具。python
selenium和webdriver其實原來是兩個不一樣的開源項目,後來selenium2就把selenium1(RC)和webdriver合併到一塊兒,仍是用selenium的名字,可是實現方式和協議基本沿用的是webdriver的。能夠看作同樣。git
簡單來講,須要經過chromedriver調用chrome,進行模擬瀏覽器操做。github
下載chromedriver。chrome和chromedriver 要版本對應,chromedriver版本下載,放到相應目錄。golang
下載golang代碼包。selenium的golang代碼包web
go get -t -d github.com/tebeka/selenium
通過個人理解和思考,我認爲selenium 主要運行模式以下(我的理解,僅供參考)。chrome
程序須要調用selenium庫執行相應的函數, 後臺調用chrome瀏覽器,而後將操做元素的請求給下方的瀏覽器驅動。瀏覽器驅動再轉發這個請求給瀏覽器。最後將結果返回。windows
由於selenium源碼包不是很大,同時由於是chrome進行實戰,因此我將源碼進行刪減而後進行添加註釋。godoc包應該沒有寫完整,好比webdriver,webelement只講了接口,並無將實現細節,咱們能夠根據selenium操做進行腦補。能夠參考python中selenium中的實現,好比自動化測試。瀏覽器
先繼續畫個圖進行包的講解的吧。
源碼簡略分析:
// 第一類 雜項 //刪除會話 func DeleteSession(urlPrefix, id string) error //開啓關閉debug調試 func SetDebug(debug bool) //設置代理 func (c Capabilities) AddProxy(p Proxy) //設置日誌級別 func (c Capabilities) SetLogLevel(typ log.Type, level log.Level) // 第二類 seleium後臺服務 //服務實例的可選項 type ServiceOption func(*Service) error //添加chrome路徑信息,返回的是serviceOption類型 func ChromeDriver(path string) ServiceOption //服務的結構體,包含隱藏類型 type Service struct { // contains filtered or unexported fields } //啓動chrome瀏覽器的服務器,返回service類型指針 func NewChromeDriverService(path string, port int, opts ...ServiceOption) (*Service, error) //關閉服務,記得defer關閉 func (s *Service) Stop() error // 第三類 chrome操做相關 //設置瀏覽器兼容性,map類型,好比chrome瀏覽器兼容性。 //caps := selenium.Capabilities{"browserName": "chrome"} type Capabilities map[string]interface{} //經過調用函數添加chrome兼容性 func (c Capabilities) AddChrome(f chrome.Capabilities) //啓動webdriver實例 func NewRemote(capabilities Capabilities, urlPrefix string) (WebDriver, error) //經過WebDriver接口能夠看出具體頁面的實現的方法,是接口,接口裏面是實現的方法。 type WebDriver interface { //返回服務器環境的版本信息 // Status returns various pieces of information about the server environment. Status() (*Status, error) //建立新的session // NewSession starts a new session and returns the session ID. NewSession() (string, error) //建立新的session(已廢棄) // SessionId returns the current session ID // Deprecated: This identifier is not Go-style correct. Use SessionID // instead. SessionId() string //獲取新的ssionid // SessionID returns the current session ID. SessionID() string //切換session // SwitchSession switches to the given session ID. SwitchSession(sessionID string) error //返回兼容性 // Capabilities returns the current session's capabilities. Capabilities() (Capabilities, error) //設置異步腳本執行時間 // SetAsyncScriptTimeout sets the amount of time that asynchronous scripts // are permitted to run before they are aborted. The timeout will be rounded // to nearest millisecond. SetAsyncScriptTimeout(timeout time.Duration) error //設置等待搜索元素的時間,目的: 若是頁面結果返回較慢,就須要等待頁面內容完整返回,而後再進行頁面元素操做。 // SetImplicitWaitTimeout sets the amount of time the driver should wait when // searching for elements. The timeout will be rounded to nearest millisecond. SetImplicitWaitTimeout(timeout time.Duration) error //設置等待頁面的時間 // SetPageLoadTimeout sets the amount of time the driver should wait when // loading a page. The timeout will be rounded to nearest millisecond. SetPageLoadTimeout(timeout time.Duration) error //設置會話退出 // Quit ends the current session. The browser instance will be closed. Quit() error //獲取如今窗口句柄,一串序號,打開一個窗口一個句柄 // CurrentWindowHandle returns the ID of current window handle. CurrentWindowHandle() (string, error) //獲取如今全部打開窗口句柄,獲取全部窗口句柄 // WindowHandles returns the IDs of current open windows. WindowHandles() ([]string, error) //返回當前頁面鏈接的URL // CurrentURL returns the browser's current URL. CurrentURL() (string, error) //獲取當前頁面的標題 // Title returns the current page's title. Title() (string, error) //返回當前頁面的全部內容 // PageSource returns the current page's source. PageSource() (string, error) //關閉如今的窗口 // Close closes the current window. Close() error //切換frame,frame裏面內嵌一個完整html,若是操做裏面的內容須要進入iframe中。switchframe(nil),返回到頂層 // SwitchFrame switches to the given frame. The frame parameter can be the // frame's ID as a string, its WebElement instance as returned by // GetElement, or nil to switch to the current top-level browsing context. SwitchFrame(frame interface{}) error 切換windows到指定窗口 // SwitchWindow switches the context to the specified window. SwitchWindow(name string) error //關閉窗口 // CloseWindow closes the specified window. CloseWindow(name string) error //設置最大化窗口 // MaximizeWindow maximizes a window. If the name is empty, the current // window will be maximized. MaximizeWindow(name string) error //設置窗口尺寸 // ResizeWindow changes the dimensions of a window. If the name is empty, the // current window will be maximized. ResizeWindow(name string, width, height int) error //經過url導航至相應界面。主要選項,就是打開url地址。 // Get navigates the browser to the provided URL. Get(url string) error //向前翻 // Forward moves forward in history. Forward() error //向後翻 // Back moves backward in history. Back() error //刷新 // Refresh refreshes the page. Refresh() error //查找定位一個html元素。 // FindElement finds exactly one element in the current page's DOM. FindElement(by, value string) (WebElement, error) //查找定位多個的html元素 // FindElement finds potentially many elements in the current page's DOM. FindElements(by, value string) ([]WebElement, error) //獲取當前焦點元素 // ActiveElement returns the currently active element on the page. ActiveElement() (WebElement, error) //解碼元素響應 // DecodeElement decodes a single element response. DecodeElement([]byte) (WebElement, error) //解碼多個元素響應 // DecodeElements decodes a multi-element response. DecodeElements([]byte) ([]WebElement, error) //獲取全部cookie // GetCookies returns all of the cookies in the browser's jar. GetCookies() ([]Cookie, error) //獲取指定cookie // GetCookie returns the named cookie in the jar, if present. This method is // only implemented for Firefox. GetCookie(name string) (Cookie, error) //添加cookie到jar // AddCookie adds a cookie to the browser's jar. AddCookie(cookie *Cookie) error //刪除全部cookie // DeleteAllCookies deletes all of the cookies in the browser's jar. DeleteAllCookies() error //刪除指定cookie // DeleteCookie deletes a cookie to the browser's jar. DeleteCookie(name string) error //敲擊鼠標按鈕 // Click clicks a mouse button. The button should be one of RightButton, // MiddleButton or LeftButton. Click(button int) error //雙擊鼠標按鈕 // DoubleClick clicks the left mouse button twice. DoubleClick() error //按下鼠標 // ButtonDown causes the left mouse button to be held down. ButtonDown() error //擡起鼠標 // ButtonUp causes the left mouse button to be released. ButtonUp() error //發送更改到活動元素(已丟棄) // SendModifier sends the modifier key to the active element. The modifier // can be one of ShiftKey, ControlKey, AltKey, MetaKey. // // Deprecated: Use KeyDown or KeyUp instead. SendModifier(modifier string, isDown bool) error //將按鍵順序序列發送到活動元素 // KeyDown sends a sequence of keystrokes to the active element. This method // is similar to SendKeys but without the implicit termination. Modifiers are // not released at the end of each call. KeyDown(keys string) error //釋放發送的元素 // KeyUp indicates that a previous keystroke sent by KeyDown should be // release KeyUp(keys string) error //拍攝快照 // Screenshot takes a screenshot of the browser window. Screenshot() ([]byte, error) //日誌抓取 // Log fetches the logs. Log types must be previously configured in the // capabilities. // // NOTE: will return an error (not implemented) on IE11 or Edge drivers. Log(typ log.Type) ([]log.Message, error) //解除警報 // DismissAlert dismisses current alert. DismissAlert() error //接受警報 // AcceptAlert accepts the current alert. AcceptAlert() error //返回如今警報內容 // AlertText returns the current alert text. AlertText() (string, error) //發送警報內容 // SetAlertText sets the current alert text. SetAlertText(text string) error //執行腳本 // ExecuteScript executes a script. ExecuteScript(script string, args []interface{}) (interface{}, error) //異步執行腳本 // ExecuteScriptAsync asynchronously executes a script. ExecuteScriptAsync(script string, args []interface{}) (interface{}, error) //執行源腳本 // ExecuteScriptRaw executes a script but does not perform JSON decoding. ExecuteScriptRaw(script string, args []interface{}) ([]byte, error) //異步執行源腳本 // ExecuteScriptAsyncRaw asynchronously executes a script but does not // perform JSON decoding. ExecuteScriptAsyncRaw(script string, args []interface{}) ([]byte, error) //等待條件爲真 // WaitWithTimeoutAndInterval waits for the condition to evaluate to true. WaitWithTimeoutAndInterval(condition Condition, timeout, interval time.Duration) error //等待時間 // WaitWithTimeout works like WaitWithTimeoutAndInterval, but with default polling interval. WaitWithTimeout(condition Condition, timeout time.Duration) error //等待 //Wait works like WaitWithTimeoutAndInterval, but using the default timeout and polling interval. Wait(condition Condition) error } //對相關元素進行後續執行,接口類型,裏面是實現方法 type WebElement interface { // click選中的元素 // Click clicks on the element. Click() error //發送數據到選中元素 // SendKeys types into the element. SendKeys(keys string) error //提交按鈕 // Submit submits the button. Submit() error //清空按鈕 // Clear clears the element. Clear() error //移動元素到相應的座標 // MoveTo moves the mouse to relative coordinates from center of element, If // the element is not visible, it will be scrolled into view. MoveTo(xOffset, yOffset int) error // 查找子元素 // FindElement finds a child element. FindElement(by, value string) (WebElement, error) //查找多個子元素 // FindElement finds multiple children elements. FindElements(by, value string) ([]WebElement, error) //返回標籤名稱 // TagName returns the element's name. TagName() (string, error) //返回元素內容 // Text returns the text of the element. Text() (string, error) //元素被選中返回真 // IsSelected returns true if element is selected. IsSelected() (bool, error) //若是元素啓用返回真 // IsEnabled returns true if the element is enabled. IsEnabled() (bool, error) //若是元素顯示返回真 // IsDisplayed returns true if the element is displayed. IsDisplayed() (bool, error) //獲取元素的名稱 // GetAttribute returns the named attribute of the element. GetAttribute(name string) (string, error) //範圍元素的位置 // Location returns the element's location. Location() (*Point, error) //滾動後返回元素的位置 // LocationInView returns the element's location once it has been scrolled // into view. LocationInView() (*Point, error) //返回元素的大小 // Size returns the element's size. Size() (*Size, error) //返回css優先級 // CSSProperty returns the value of the specified CSS property of the // element. CSSProperty(name string) (string, error) //返回屬性滾動的快照 // Screenshot takes a screenshot of the attribute scroll'ing if necessary. Screenshot(scroll bool) ([]byte, error) }
可能須要瞭解Html,Css,JavaScript的基本概念。菜鳥教程
可能須要瞭解Dom結構。html Dom
可能須要瞭解XPATH,CSSSelector 。Xpath和CSS選擇器的使用詳解
能夠參考python中selenium操做實現,畢竟python案例多。selenim操做平常記錄
操做以前,先分享一個快速獲取CSS Selector和xpath的方法。
你們用chrome瀏覽器訪問網頁,按F12後,點擊調試頁左上角Elements箭頭,而後鼠標移動到目的位置,便可顯示頁面對應的HTML 元素。
右鍵選中的元素,選擇copy,此時能夠根據直接選擇ID,CLASS,CSS Selector或Xpath的地址.
參考別人的案例,寫了幾個小案例,僅供參考。亮代碼吧。
打開百度,自動搜索。
package main import ( "fmt" "github.com/tebeka/selenium" "time" ) const ( //設置常量 分別設置chromedriver.exe的地址和本地調用端口 seleniumPath = `H:\webdriver\chromedriver.exe` port = 9515 ) func main() { //1.開啓selenium服務 //設置selium服務的選項,設置爲空。根據須要設置。 ops := []selenium.ServiceOption{} service, err := selenium.NewChromeDriverService(seleniumPath, port, ops...) if err != nil { fmt.Printf("Error starting the ChromeDriver server: %v", err) } //延遲關閉服務 defer service.Stop() //2.調用瀏覽器 //設置瀏覽器兼容性,咱們設置瀏覽器名稱爲chrome caps := selenium.Capabilities{ "browserName": "chrome", } //調用瀏覽器urlPrefix: 測試參考:DefaultURLPrefix = "http://127.0.0.1:4444/wd/hub" wd, err := selenium.NewRemote(caps, "http://127.0.0.1:9515/wd/hub") if err != nil { panic(err) } //延遲退出chrome defer wd.Quit() //3.對頁面元素進行操做 //獲取百度頁面 if err := wd.Get("https://www.baidu.com/"); err != nil { panic(err) } //找到百度輸入框id we, err := wd.FindElement(selenium.ByID, "kw") if err != nil { panic(err) } //向輸入框發送「」 err = we.SendKeys("天下第一") if err != nil { panic(err) } //找到百度提交按鈕id we, err = wd.FindElement(selenium.ByID, "su") if err != nil { panic(err) } //點擊提交 err = we.Click() if err != nil { panic(err) } //睡眠20秒後退出 time.Sleep(20 * time.Second) }
內嵌iframe切換。
package main import ( "fmt" "github.com/tebeka/selenium" "time" ) const ( //設置常量 分別設置chromedriver.exe的地址和本地調用端口 seleniumPath = `H:\webdriver\chromedriver.exe` port = 9515 ) func main() { //1.開啓selenium服務 //設置selium服務的選項,設置爲空。根據須要設置。 ops := []selenium.ServiceOption{} service, err := selenium.NewChromeDriverService(seleniumPath, port, ops...) if err != nil { fmt.Printf("Error starting the ChromeDriver server: %v", err) } //延遲關閉服務 defer service.Stop() //2.調用瀏覽器 //設置瀏覽器兼容性,咱們設置瀏覽器名稱爲chrome caps := selenium.Capabilities{ "browserName": "chrome", } //調用瀏覽器urlPrefix: 測試參考:DefaultURLPrefix = "http://127.0.0.1:4444/wd/hub" wd, err := selenium.NewRemote(caps, "http://127.0.0.1:9515/wd/hub") if err != nil { panic(err) } //延遲退出chrome defer wd.Quit() //3.對頁面元素進行操做 //獲取測試網頁 if err := wd.Get("http://cdn1.python3.vip/files/selenium/sample2.html"); err != nil { panic(err) } //4.切換到相應的frame上去 //wd.SwitchFrame(能夠id或者frame獲取的webelement),咱們使用二種方式分別實現。 //4.1 經過frame的id查找 此時id=frame1 /* err = wd.SwitchFrame("frame1") if err != nil { panic(err) } // 此時定位到iframe的html中,再像使用bycssselector便可 // 由於animal包含多個對象,咱們使用findelements wes, err := wd.FindElements(selenium.ByCSSSelector, ".animal") if err != nil { panic(err) } //循環獲取每一個元素的信息 for _,we := range wes { text, err := we.Text() if err != nil { panic(err) } fmt.Println(text) } */ //4.2 frame獲取的webelement,經過切換webelement實現。 // 找到ifname的webelement對象 element, err := wd.FindElement(selenium.ByCSSSelector, "#frame1") // 不一樣的獲取element方式 //element, err := wd.FindElement(selenium.ByCSSSelector, `iframe[name="innerFrame"]`) if err != nil { panic(err) } //切換到iframe中 err = wd.SwitchFrame(element) if err != nil { panic(err) } // 此時定位到iframe的html中,再像使用bycssselector便可 // 由於animal包含多個對象,咱們使用findelements wes, err := wd.FindElements(selenium.ByCSSSelector, ".animal") if err != nil { panic(err) } //循環獲取每一個元素的信息 for _, we := range wes { text, err := we.Text() if err != nil { panic(err) } fmt.Println(text) } //5.切換回頂層frame,由於切換中frame中是不能操做外層值元素的,因此咱們要切換出來 //frame=nil是切換回頂層frame err = wd.SwitchFrame(nil) if err != nil { panic(err) } //根據class name選擇元素 we, err := wd.FindElement(selenium.ByCSSSelector, ".baiyueheiyu") if err != nil { panic(err) } //查看頂層元素的內容 fmt.Println(we.Text()) //睡眠20秒後退出 time.Sleep(20 * time.Second) }
多windows切換。
package main import ( "fmt" "github.com/tebeka/selenium" "strings" "time" ) const ( //設置常量 分別設置chromedriver.exe的地址和本地調用端口 seleniumPath = `H:\webdriver\chromedriver.exe` port = 9515 ) func main() { //1.開啓selenium服務 //設置selenium服務的選項,設置爲空。根據須要設置。 ops := []selenium.ServiceOption{} service, err := selenium.NewChromeDriverService(seleniumPath, port, ops...) if err != nil { fmt.Printf("Error starting the ChromeDriver server: %v", err) } //延遲關閉服務 defer service.Stop() //2.調用瀏覽器實例 //設置瀏覽器兼容性,咱們設置瀏覽器名稱爲chrome caps := selenium.Capabilities{ "browserName": "chrome", } //調用瀏覽器urlPrefix: 測試參考:DefaultURLPrefix = "http://127.0.0.1:4444/wd/hub" wd, err := selenium.NewRemote(caps, "http://127.0.0.1:9515/wd/hub") if err != nil { panic(err) } //延遲退出chrome defer wd.Quit() //3.打開多頁面chrome實例 //目前就想到兩種方式能夠打開, //第一種就是頁面中有url鏈接,經過click()方式打開 //第二種方式就是經過腳本方式打開。wd.ExecuteScript if err := wd.Get("http://cdn1.python3.vip/files/selenium/sample3.html"); err != nil { panic(err) } //第一種方式,找到頁面中的url地址,進行頁面跳轉 we, err := wd.FindElement(selenium.ByTagName, "a") if err != nil { panic(err) } we.Click() //第二種方式,經過運行通用的js腳本打開新窗口,由於咱們暫時不須要操做獲取的結果,全部不獲取返回值。 wd.ExecuteScript(`window.open("https://www.qq.com", "_blank");`, nil) wd.ExecuteScript(`window.open("https://www.runoob.com/jsref/obj-window.html", "_blank");`, nil) //這一行是發送警報信息,寫這一行的目的,主要是看當前主窗口是哪個 wd.ExecuteScript(`window.alert(location.href);`, nil) //查看當前窗口的handle值 handle, err := wd.CurrentWindowHandle() if err != nil { panic(err) } fmt.Println(handle) fmt.Println("--------------------------") //查看全部網頁的handle值 handles, err := wd.WindowHandles() if err != nil { panic(err) } for _, handle := range handles { fmt.Println(handle) } fmt.Println("--------------------------") //4.跳轉到指定的網頁 //咱們雖然打開了多個頁面,可是咱們當前的handle值,仍是第一個頁面的,咱們要想辦法搞定它。 //記得保存當前主頁面的handle值 //mainhandle := handle //經過判斷條件進行相應的網頁 //獲取全部handle值 handles, err = wd.WindowHandles() if err != nil { panic(err) } //遍歷全部handle值,經過url找到目標頁面,判斷相等時,break出來,就是停到相應的頁面了。 for _, handle := range handles { wd.SwitchWindow(handle) url, _ := wd.CurrentURL() if strings.Contains(url, "qq.com") { break } } //查看此頁面的handle handle, err = wd.CurrentWindowHandle() if err != nil { panic(err) } fmt.Println(handle) //這一行是發送警報信息,寫這一行的目的,主要是看當前主窗口是哪個 wd.ExecuteScript(`window.alert(location.href);`, nil) //切換回第一個頁面 //wd.SwitchWindow(mainhandle) //睡眠20秒後退出 time.Sleep(20 * time.Second) }
單選,多選框操做。
package main import ( "fmt" "github.com/tebeka/selenium" "time" ) const ( //設置常量 分別設置chromedriver.exe的地址和本地調用端口 seleniumPath = `H:\webdriver\chromedriver.exe` port = 9515 ) func main() { //1.開啓selenium服務 //設置selenium服務的選項,設置爲空。根據須要設置。 ops := []selenium.ServiceOption{} service, err := selenium.NewChromeDriverService(seleniumPath, port, ops...) if err != nil { fmt.Printf("Error starting the ChromeDriver server: %v", err) } //延遲關閉服務 defer service.Stop() //2.調用瀏覽器實例 //設置瀏覽器兼容性,咱們設置瀏覽器名稱爲chrome caps := selenium.Capabilities{ "browserName": "chrome", } //調用瀏覽器urlPrefix: 測試參考:DefaultURLPrefix = "http://127.0.0.1:4444/wd/hub" wd, err := selenium.NewRemote(caps, "http://127.0.0.1:9515/wd/hub") if err != nil { panic(err) } //延遲退出chrome defer wd.Quit() // 3單選radio,多選checkbox,select框操做(功能待完善,https://github.com/tebeka/selenium/issues/141) if err := wd.Get("http://cdn1.python3.vip/files/selenium/test2.html"); err != nil { panic(err) } //3.1操做單選radio we, err := wd.FindElement(selenium.ByCSSSelector, `#s_radio > input[type=radio]:nth-child(3)`) if err != nil { panic(err) } we.Click() //3.2操做多選checkbox //刪除默認checkbox we, err = wd.FindElement(selenium.ByCSSSelector, `#s_checkbox > input[type=checkbox]:nth-child(5)`) if err != nil { panic(err) } we.Click() //選擇選項 we, err = wd.FindElement(selenium.ByCSSSelector, `#s_checkbox > input[type=checkbox]:nth-child(1)`) if err != nil { panic(err) } we.Click() we, err = wd.FindElement(selenium.ByCSSSelector, `#s_checkbox > input[type=checkbox]:nth-child(3)`) if err != nil { panic(err) } we.Click() //3.3 select多選 //刪除默認選項 //選擇默認項 we, err = wd.FindElement(selenium.ByCSSSelector, `#ss_multi > option:nth-child(3)`) if err != nil { panic(err) } we.Click() we, err = wd.FindElement(selenium.ByCSSSelector, `#ss_multi > option:nth-child(2)`) if err != nil { panic(err) } we.Click() //睡眠20秒後退出 time.Sleep(20 * time.Second) }
我的理解,僅供參考。若有錯誤,歡迎指正。
一直在路上,默默前行。