Selenium項目快速入門(基於Python)

来源:https://www.cnblogs.com/trotl/archive/2019/11/14/11863618.html
-Advertisement-
Play Games

Selenium是一個自動化測試工具,利用它我們可以驅動瀏覽器執行特定的動作,如點擊、下拉等操作。 本文將從環境部署到項目開發一步步講解,包括這個過程所可能遇到的一些問題,都會一一解答,有不會的問題可以在下方評論留言一起思考解決。 一.環境部署 環境部署包括mac和linux 1.安裝Seleniu ...


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

一.環境部署

環境部署包括mac和linux

1.安裝Selenium

pip3 install selenium

這裡推薦大家使用Anaconda管理python包及環境,Anaconda是一個方便的python包管理和環境管理軟體,一般用來配置不同的項目環境。如果你的電腦只能安裝一個環境,而兩個項目卻用著不同的環境,那麼你可以使用Anaconda創建多個互不幹擾的環境,分別運行不同版本的軟體包,以達到相容的目的。

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

Anaconda的安裝流程及使用

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

2.安裝ChromeDriver

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

方法一 :

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

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

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

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。

如果覺得不錯,請留下您的大拇指哦

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ### default過濾器: 使用方式:{{ value|default('預設值') }} 如果value這個“key”不存在,那麼就會使用default過濾器提供的預設值。如果你想使用類似python中判斷一個值是否為False(例如:None、空字元串、空列表、空字典等),那麼就必須要傳遞另 ...
  • ### 什麼是過濾器,語法是什麼: 1.有時候我們想要在模板中對一些變數進行處理,那麼就需要類似python中的函數一樣,可以將這個值傳到函數中,然後做一些操作。在模板中,過濾器相當於是一個函數,把當前的過濾器傳到變數中,然後過濾器根據自己的功能,再返回相應的值,之後再將結果渲染到頁面中。 2.基本 ...
  • ### url_for筆記: 模板中的“url_for”跟我們視圖函數中的“url_for”使用起來基本是一摸一樣的。也是傳遞視圖函數的名字,也是傳遞參數,使用的時候,用{{}}闊起來: 例如:{{ url_for('fun') }} app.py: from flask import Flask, ...
  • app.py: from flask import Flask, render_template app = Flask(__name__) @app.route('/') def hello_world(): context = { 'user': 'nvshen', 'age': 19, 'co ...
  • ### 模板預熱筆記: 1.在渲染模板的時候,預設會從項目根目錄下的“templetes”目錄下查找模板。 2.如果不想把模板文件放在“templetes”目錄下,那麼可以在flask初始化的時候指定"templete_folder"來指定模板的路徑。 代碼示例: from flask import ...
  • ### 視圖函數中可以返回哪些值: 1.可以返回字元串:返回的字元串其實底層將這個字元串包裝成了一個“Response”對象。 2.可以返回元組:元組的形式是(響應體,狀態碼,頭部信息),也不一定三個都要寫,寫兩個也是可以的,返回的元組,其實在底層也是包裝成了一個“Response”對象。 3.可以 ...
  • 向指定文件寫入數據,如果文件不存在,則創建文件,寫入數據之前清空文件 ...
  • 一.什麼是分散式配置中心? 就是為微服務架構中的微服務提供集中化的外部配置支持,配置中心為各個微服務應用的所有環境提供了中心化的外部配置(可能比較難理解,想知道是什麼意思就要知道為什麼這麼配置:這麼配置就是為瞭解決微服務中很多個provider中的application.properties配置管理 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...