Selenium網頁自動登陸項目(基於Python從0到1)

Selenium是一個自動化測試工具,利用它咱們能夠驅動瀏覽器執行特定的動做,如點擊、下拉等操做。
本文講述的是經過自動化的方式登錄某一網站,其中包含Selenium+python自動化項目環境如何部署, 獲取圖形驗證碼登陸,元素獲取方法,項目中遇到的問題,看完你會發現原來Selenium自動化輕鬆入門,是多麼的簡單,Selenium+python也能夠用於爬蟲。
本文將從環境部署到項目開發一步步講解,包括這個過程所可能遇到的一些問題,都會一一解答,有不會的問題能夠在下方評論留言一塊兒思考解決。css

一.環境部署

環境部署包括mac和linuxhtml

1.安裝Selenium

pip3 install selenium

這裏推薦你們使用Anaconda管理python包及環境,Anaconda是一個方便的python包管理和環境管理軟件,通常用來配置不一樣的項目環境。若是你的電腦只能安裝一個環境,而兩個項目卻用着不一樣的環境,那麼你可使用Anaconda建立多個互不干擾的環境,分別運行不一樣版本的軟件包,以達到兼容的目的。python

Anaconda經過管理工具包、開發環境、Python版本,大大簡化了你的工做流程。不只能夠方便地安裝、更新、卸載工具包,並且安裝時能自動安裝相應的依賴包,同時還能使用不一樣的虛擬環境隔離不一樣要求的項目。linux

Anaconda的安裝流程及使用git

https://www.cnblogs.com/trotl/p/11863544.htmlgithub

2.安裝ChromeDriver

2.1.查看瀏覽器版本
2.2.在瀏覽器的幫助/關於Google Chrome 查看瀏覽器版本
2.3.下載相應的ChromeDriver(兩種方法)

方法一 :web

  1. 打開ChromeDriver官方網站,根據上面的瀏覽器版本,下載相應版本的ChromeDriver
  2. 將解壓好的文件放入/usr/local/bin目錄中,因爲mac的不少目錄都是隱藏的,因此咱們按快捷鍵command+shift+g,在彈出的窗口輸入/usr/local/bin,就能夠打開這個目錄,接着將解壓好的驅動放入此目錄便可。
  3. 進行測試(在終端輸入: chromedriver --version,能夠查看到版本)

方法二 :
1.安裝brew及使用可能遇到的問題chrome

https://www.cnblogs.com/trotl/p/11862796.htmlwindows

2.下載chromedriver數組

經過命令brew cask install chromedriver去下載

3.測試

在終端輸入: chromedriver --version,能夠查看到版本

3.安裝識別驗證碼的包

1.用homebrew 在電腦上安裝tesseract庫

brew install tesseract

2.用pip安裝支持python的tesseract

pip install pytesseract

若是是識別中文
去往https://github.com/tesseract-ocr/tessdata下載中文數據集chi_sim.traineddata,把它放到這目錄下:
/usr/local/Cellar/tesseract/3.05.01/share/tessdata

3.安裝容易遇到的問題:

  • 提示brew update,表明homebrew須要更新
  • 提示must be writable!或者Permission denied之類問題,試試前面加sudo
  • 提示Please check the permissions and owner of that directory,說明權限有問題,那麼使用sudo chown root 文件路徑命令得到臨時root權限
  • 提示Xcode alone is not sufficient on Sierra,使用xcode-select --install

二.實現邏輯

開始想的邏輯是,獲取到驗證碼的地址,而後爬取下來並請求,下載驗證碼圖片並識別再填上去,發現這樣行不通,每次請求得到的驗證碼圖片不一致,這得從會話角度去解決問題。這裏我換了種思惟更簡單的去解決這個問題,經過截圖的方式把頁面上的驗證碼截圖下來保存爲圖片並識別出文字。

1. 實現中所遇到的問題

  1. chromedriver的截圖只能截取當前頁面的圖片,不能獲得整個頁面的圖片,這樣就不能經過定位驗證碼圖片的位置去截取驗證碼圖片,對於頁面有滑動的只能手動調試位置。

  2. 處理驗證碼失敗的提示框
  3. 當從a頁面跳轉到b網頁,而後獲取b頁面的某個元素時,容易出錯。由於代碼執行速度比網頁加載速度快,一般會出現沒法找到該元素的錯誤。遇到沒法找到頁面元素的狀況,要考慮是不是代碼加載過快的緣由,處理方法:在獲取元素前➕time.sleep(2)
  4. 快速獲取元素路徑的方式:網頁->檢查->選中對應標籤->右鍵選擇copy->copy xpath

2. 用到的一些方法

2.1 處理Windows彈出框(三種狀況)

使用 driver.switch_to.alert 切換到Windows彈出框
Alert類提供了一系列操做方法:
accept() 肯定
dismiss() 取消
text() 獲取彈出框裏面的內容
send_keys(keysToSend) 輸入字符串

A.定位alert彈出框

#點擊頁面元素,觸發alert彈出框
driver.find_element_by_xpath('//*[@id="alert"]').click()
time.sleep(3)
#等待alert彈出框可見
WebDriverWait(driver,20).until(EC.alert_is_present())
#從html頁面切換到alert彈框 
alert = driver.switch_to.alert
#獲取alert的文本內容
print(alert.text)
#接受--選擇「肯定」
alert.accept()

B.定位confirm彈出框

driver.find_element_by_xpath('//*[@id="confirm"]').click()
time.sleep(3)
WebDriverWait(driver,20).until(EC.alert_is_present())
alert =driver.switch_to.alert
print(alert.text)
# 接受--選擇「取消」
alert.dismiss()

C.定位prompt彈出框

driver.find_element_by_id("prompt").click()
time.sleep(3)
WebDriverWait(driver,20).until(EC.alert_is_present())
alert =driver.switch_to.alert
alert.send_keys("jaja")
time.sleep(5)
print(alert.text)
# alert.dismiss()
alert.accept()
2.2 python+selenium調用js方法
from selenium import webdriver
js = '''var str="聯想詞:%s===>車系:%s";window.alert(str);''' % (alias, name)
driver.execute_script(js)

execute_script(js)和execute_async_script(js)分別是是同步和異步方法,前者會等待js代碼執行完畢後主線程執行,後者它不會阻塞主線程執行。
execute_script(js) 方法若是有返回值,有如下幾種狀況:
    * 若是返回一個頁面元素(document element), 這個方法就會返回一個WebElement
    * 若是返回浮點數字,這個方法就返回一個double類型的數字
    * 返回非浮點數字,方法返回Long類型數字
    * 返回boolean類型,方法返回Boolean類型
    * 若是返回一個數組,方法會返回一個List<Object>
    * 其餘狀況,返回一個字符串
    * 若是沒有返回值,此方法就會返回null
2.3selenium+python的經常使用方法
1.建立webdriver對象
browser=webdriver.Chrome()
2.打開百度頁面
browser.get('https://www.baidu.com')
3.獲取網頁源碼
browser.page_source
4.在百度頁面id爲kw的輸入框中輸入book
driver.find_element_by_id('kw').send_keys('book’)
5.在百度頁面id爲kw的輸入框中清除book
driver.find_element_by_id('kw’).clear()
6.在百度頁面id爲search的按鈕點擊搜索
a.driver.find_element_by_id('search').click()
b.action3 = self.driver.find_element_by_class_name('next')
  ActionChains(self.driver).move_to_element(action3).double_click(action3).perform()
7.向前跳轉回上一個頁面
driver.back()
8.向後跳轉回上一個頁面
driver.forward()
9.關閉瀏覽器
browser.close()   關閉當前窗口
browser.quit()   退出並關閉窗口的每個相關的驅動程序
10.獲取某個元素的文本內容
driver.find_element_by_class_name("loading_btn").text
11.將瀏覽器窗口最大化顯示
driver.maximize_window() 
12.設置瀏覽器寬480、高800顯示:
driver.set_window_size(480, 800)
13.獲取驗證碼圖片的大小
codeEelement = driver.find_element_by_id(‘code')
imgSize = codeEelement.size   
14.獲取驗證碼元素座標
imgLocation = imgElement.location 
15.計算驗證碼總體座標
rangle = (int(imgLocation['x']),int(imgLocation['y']),int(imgLocation['x'] + imgSize['width']),int(imgLocation['y']+imgSize['height']))

注意:submit和click的區別。Click方法只適用於button,而submit能夠用於提交表單。

2.4 獲取元素的方法之find_element_by_css_selector
-----------------經過類class獲取---------------
<h1 class="important">This heading is very important.</h1>
<p class="important">This paragraph is very important.</p>
<p class="important warning">This paragraph is a very important warning.</p>
1.獲取class值爲important的h1標籤
find_element_by_css_selector(h1.importane)
2.獲取全部class值爲important的標籤
find_element_by_css_selector(*.importane)或者find_element_by_css_selector(.importane)
3.獲取class值爲important warning的標籤
find_element_by_css_selector(.importane.warning)

-----------------經過類ID獲取---------------
<p id="intro">This is a paragraph of introduction.</p>
 find_element_by_css_selector(#"intro")
 
 -----------------屬性選擇器---------------
1.<a title="W3School Home" href="http://w3school.com.cn">W3School</a>
 屬性中包含了title和href,find_element_by_css_selector('a[title][href]’)
2<a href="http://www.w3school.com.cn/about_us.asp">About W3School</a>
 定位屬性中href="http://www.w3school.com.cn/about_us.asp"的元素,
find_element_by_css_selector('a[href="http://www.w3school.com.cn/about_us.asp"]’)
3.<a href="http://www.w3school.com.cn/" title="W3School">W3School</a>
 經過href和title來定位
find_element_by_css_selector("a[href='http://www.w3school.com.cn/about_us.asp'][title='W3School']」)

 -----------------部分屬性定位---------------
<h1>能夠應用樣式:</h1>
<img title="Figure 1" src="/i/figure-1.gif" />
<img title="Figure 2" src="/i/figure-2.gif" />
 
<hr />
 
<h1>沒法應用樣式:</h1>
<img src="/i/figure-1.gif" />
<img src="/i/figure-2.gif" />
 定位title中包含有figure的元素:
find_element_by_css_selector("image[title~='figure']")

-----------------其餘-------------------
[abc^="def"]  選擇 abc 屬性值以 "def" 開頭的全部元素
[abc$="def"]   選擇 abc 屬性值以 "def" 結尾的全部元素
[abc*="def"]  選擇 abc 屬性值中包含子串 "def" 的全部元素

-----------------後代選擇器--------------
<h1>This is a <em>important</em> heading</h1>
<p>This is a <em>important</em> paragraph.</p>
 find_element_by_css_selector("h1 em")
2.5 獲取元素的方法之find_element_by_xpath

這個方法是很是強大的元素查找方式,使用這種方法幾乎能夠定位到頁面上的任意元素。在正式開始使用XPath進行定位前,咱們先了解下什麼是XPath。XPath是XML Path的簡稱,因爲HTML文檔自己就是一個標準的XML頁面,因此咱們可使用XPath的語法來定位頁面元素。
  Xpath經過路徑來定位控件,分爲絕對路徑和相對路徑。絕對路徑以單/號表示,相對路徑則以//表示。當xpath的路徑以/開頭時,表示讓Xpath解析引擎從文檔的根節點開始解析。當xpath路徑以//開頭時,則表示讓xpath引擎從文檔的任意符合的元素節點開始進行解析。而當/出如今xpath路徑中時,則表示尋找父節點的直接子節點,當//出如今xpath路徑中時,表示尋找父節點下任意符合條件的子節點。弄清這個原則,就能夠理解其實xpath的路徑能夠絕對路徑和相對路徑混合在一塊兒來進行表示,想怎麼玩就怎麼玩。

快速獲取你想要的元素xpath方式:
網頁->檢查->選中對應標籤->右鍵選擇copy->copy xpath
在這裏插入圖片描述

絕對路徑寫法(只有一種),寫法以下:
引用頁面上的form元素(即源碼中的第3行):/html/body/form
下面是相對路徑的引用寫法:
查找頁面根元素:
//
查找頁面上全部的input元素:
//input
查找頁面上第一個form元素內的直接子input元素(即只包括form元素的下一級input元素):
//form/input
查找頁面上第一個form元素內的全部子input元素(只要在form元素內的input都算,無論還嵌套了多少個其餘標籤,使用相對路徑表示,雙//號):
//form//input
查找頁面上第一個form元素:
//form
查找頁面上id爲loginForm的form元素:
//form[@id='loginForm']
查找頁面上具備name屬性爲username的input元素:
//input[@name='username']
查找頁面上id爲loginForm的form元素下的第一個input元素:
//form[@id='loginForm']/input[1]
查找頁面具備name屬性爲contiune而且type屬性爲button的input元素:
//input[@name='continue'][@type='button']
查找頁面上id爲loginForm的form元素下第4個input元素:
//form[@id='loginForm']/input[4]
以百度主頁爲例,搜索框的HTML示例代碼以下,其xpath爲//*[@id=''kw]。

獲取元素的方法之find_element_by_css_selector
獲取元素的方法之find_element_by_xpath
這兩種方法來自於百度,方便你們更好的學習,我在這裏借花獻佛總結了一下放在了這裏,由於我在寫項目的時候記錄筆記到了其餘地方,具體的地址忘了,若是原創做者看到了,請留下你的地址。

三.代碼展現

import re
import time

import pandas as pd
import pytesseract
from PIL import Image
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.support.wait import WebDriverWait


class CrackTouClick(object):
    def __init__(self):
        self.url = ""
        self.search_url = ""
        self.driver = webdriver.Chrome()
        self.wait = WebDriverWait(self.driver, 20)
        self.j_username = laosiji_username
        self.j_password = laosiji_password

    def open(self):
        self.driver.get(self.url)
        self.driver.find_element_by_name("j_username").send_keys(self.j_username)
        self.driver.find_element_by_name("j_password").send_keys(self.j_password)
        action3 = self.driver.find_element_by_id("code")
        ActionChains(self.driver).move_to_element(action3).double_click(action3).perform()

    def get_window_png(self):
        ele = self.driver.find_element_by_class_name('logo')
        ele.screenshot('ele.png')

    def verification_code(self):
        self.driver.maximize_window()
        self.driver.save_screenshot('./element.png')  # 截取當前網頁,該網頁有咱們須要的驗證碼
        rangle = (1434, 961, 1598, 1017)  # 寫成咱們須要截取的位置座標
        element = Image.open("./element.png")  # 打開截圖
        frame4 = element.crop(rangle)  # 使用Image的crop函數,從截圖中再次截取咱們須要的區域
        frame4.save('./code.png')
        code = Image.open('./code.png')
        text = pytesseract.image_to_string(code)  # 使用image_to_string識別驗證碼
        return text

    def write(self):
        while True:
            code = self.verification_code()
            # 判斷驗證碼是否識別到且爲4位數字與字母的字符串
            if len(code.strip()) == 4 and code.isalnum():
                self.driver.find_element_by_name("rand").send_keys(code)
                break
            else:
                action3 = self.driver.find_element_by_id("rand_img")
                ActionChains(self.driver).move_to_element(action3).double_click(action3).perform()

    def login(self):
        self.write()
        login_action = self.driver.find_element_by_class_name("btn")
        ActionChains(self.driver).move_to_element(login_action).double_click(login_action).perform()

    # 判斷是否有彈出框
    def alert_is_present(self):
        try:
            alert = self.driver.switch_to.alert
            print(alert)
            return alert
        except:
            return False

    def read(self):
        while True:
            self.login()
            time.sleep(1)

            # 若是有彈出框 點擊肯定
            if self.alert_is_present():
                self.driver.switch_to.alert.accept()
                self.driver.switch_to.alert.accept()
                time.sleep(1)
            else:
                break

        time.sleep(1)
        self.driver.get(self.search_url)
        self.driver.quit()

三.開發中遇到的BUG

1.運行時chrome報錯,終端打不開

File "/usr/local/python3/lib/python3.6/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: unknown error: Chrome failed to start: exited abnormally
  (unknown error: DevToolsActivePort file doesn't exist)
  (The process started from chrome location /usr/bin/google-chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.)
  (Driver info: chromedriver=70.0.3538.97 (d035916fe243477005bc95fe2a5778b8f20b6ae1),platform=Linux 3.10.0-862.14.4.el7.x86_64 x86_64)

緣由:運行過程當中開啓的進程太多
解決方法:若是你是mac,按 Command + 空格鍵來調出 Spotlight,輸入 Activity Monitor 即可啓動活動監視器。若是手動關閉幾個名稱爲chromedriver的進程,而後再嘗試打開終端,按進程名殺死進程輸入killall chromedriver。

若是以爲不錯,請留下您的大拇指哦👍
若是有什麼疑問,請留下您的評論哦👍

相關文章
相關標籤/搜索