2018年5月22日 星期二

Python 學習筆記 : Selenium 模組瀏覽器自動化測試 (一)

最近從市圖借到下面這本書 :

# 不只是測試-Python 網路爬蟲王者 Slenium


Source : 金石堂


Selenium 是跨平台網站應用程式測試自動化工具, 但其用途不僅止於此, 它同時也是功能強大的瀏覽器自動化軟體, 可完全模擬人類開啟與操作瀏覽器的行為, 支援各種瀏覽器如 Chrome, Firefox, Opera, IE, Safari 等, 可實作以瀏覽器為基礎之網路爬蟲. Selenium 不僅跨平台, 跨瀏覽器, 還跨語言, 支援 Python, Java, C#, R, PHP, Javascript, Perl 等, 參考 Selenium 官網 :

https://www.seleniumhq.org
https://www.seleniumhq.org/about/platforms.jsp#browsers

讓我驚訝的是, 這本書的 4.12.2 節竟然也介紹了我最近在複習並重新整理筆記的 AutoIt, 這是以 BASIC 語法為基礎的自動化工具.

除了上面這本專著外, 下面幾本書也有介紹 Selenium 的章節 :
  1.  Python 網路爬蟲實戰 (松崗, 胡松濤) 第 8 章
  2.  Python 自動化的樂趣 (碁峰, AL Sweigart) 第 11 章
  3.  Python 程式設計實務 (博碩, 何敏煌) 第 10-3 節
  4.  Python 初學特訓班 (碁峰, 文淵閣工作室) 第 6-3, 6.4 節
本系列之前的文章參考 :

Python 學習筆記 : 安裝執行環境與 IDLE 基本操作
Python 學習筆記 : 檔案處理
Python 學習筆記 : 日誌 (logging) 模組測試
Python 學習筆記 : 資料庫存取測試 (一) SQLite
Python 學習筆記 : 資料庫存取測試 (二) MySQL

在網路爬蟲方面, Python 的第三方模組 requests, bs4 (BeautifulSoup), 以及 Scraper 的功能就已強大到可擷取絕大部分的網頁內容. 但是對於利用 Javascript 渲染 (Render) 產生的網頁而言, Python 的支援不足, 解決辦法就是利用第三方的 Selenium 套件建立一個模擬瀏覽器, 透過 Python 指令操控模擬瀏覽器來擷取網站資料.


1. 安裝 Selenium 套件 :

D:\Python\test>pip3 install selenium 
Collecting selenium
  Downloading https://files.pythonhosted.org/packages/57/bc/17164fd471ccdf0df3a992c710c0c3c47743462ff41ab72a02c6ede96e90/selenium-3.12.0-py2.py3-none-any.whl (946kB)
Installing collected packages: selenium
Successfully installed selenium-3.12.0

如果是離線安裝, 可先到 Pypi 網站下載 whl 檔後再用 pip3 安裝 :

https://pypi.org/project/selenium/#files


D:\Python\test>pip3 install selenium-3.12.0-py2.py3-none-any.whl 
Processing d:\python\test\selenium-3.12.0-py2.py3-none-any.whl
Installing collected packages: selenium
Successfully installed selenium-3.12.0


2. 下載 Chrome 驅動程式 :

上面第一步驟只是安裝 Selenium 模組而已, 要讓 Selenium 能操控瀏覽器還需要下載瀏覽器之驅動程式, 視需要操控的是 Chrome 或 FireFox 瀏覽器分別下載對應的驅動程式, Chrome 的驅動程式下載網址為 :

http://chromedriver.chromium.org/downloads
https://sites.google.com/a/chromium.org/chromedriver/downloads/

按 Latest Release 後面的超連結, 再點 chromedriver_win32.zip 超連結下載 :






將解壓縮後的 chromedriver.exe 檔複製到 Pyhton 安裝目錄下, 例如我的 Python 3 是安裝在 C:\Python36, 因此驅動程式應該放在 C:\Python36\Scripts 下 :




然後必須將 C:\Python36\Scripts 加入系統變數 Path 裡面 :




經過上面兩個程序後, 就可以用 Selenium 來操控瀏覽器了. 首先須從 Selenium 套件匯入 webdriver 模組, 然後呼叫 Chrome() 函數產生瀏覽器物件, 再呼叫瀏覽器物件的 get() 方法開啟網頁, 例如 :

Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> from selenium import webdriver              #載入 webdriver 模組
>>> browser=webdriver.Chrome()                   #建立瀏覽器物件
>>> type(browser)                                              #傳回 WebDriver 物件
<class 'selenium.webdriver.chrome.webdriver.WebDriver'>      
>>> browser.get("http://www.google.com")    #開啟 Google 首頁

呼叫 webdriver.Chrome() 會開啟兩個視窗, 一個是執行驅動程式的 chromedriver 程式視窗, 另一個是模擬的 Chrome 瀏覽器視窗, IDLE 會停住, 等到網頁全部載入才顯示提示號 :




呼叫 browser 物件的 quit() 方法會同時關閉模擬之 Chrome 瀏覽器與驅動程式視窗 :

>>> browser.quit()                   #關閉模擬瀏覽器及其驅動程式

也可以呼叫 close() 方法, 但此方法只會關閉模擬瀏覽器而已, 驅動程式視窗則不會關掉, 因此最好還是呼叫 quit() 方法來關閉瀏覽器.

注意, 如果驅動程式 chromedriver.exe 不是放在 Scripts 子目錄下, 而是放在上一層的 Python 安裝目錄下的話, 雖然能正常開啟 Chrome, 但 chromedriver 視窗會出現如下 ERROR 訊息 :




[4152:4912:0520/201941.632:ERROR:persistent_memory_allocator.cc(845)] Corruption detected in shared-memory segment.

DevTools listening on ws://127.0.0.1:12286/devtools/browser/bcd0ee1f-7636-45d1-b067-41729b6811e4
[4152:2044:0520/201948.345:ERROR:persistent_memory_allocator.cc(845)] Corruption detected in shared-memory segment.
[4152:2044:0520/201949.483:ERROR:persistent_memory_allocator.cc(845)] Corruption detected in shared-memory segment.
[4152:2044:0520/201949.923:ERROR:persistent_memory_allocator.cc(845)] Corruption detected in shared-memory segment.
[4152:2044:0520/201950.667:ERROR:persistent_memory_allocator.cc(845)] Corruption detected in shared-memory segment.
[4152:2044:0520/201950.955:ERROR:persistent_memory_allocator.cc(845)] Corruption detected in shared-memory segment.
[4152:6920:0520/201951.128:ERROR:persistent_memory_allocator.cc(845)] Corruption detected in shared-memory segment.
[4152:6920:0520/201951.363:ERROR:persistent_memory_allocator.cc(845)] Corruption detected in shared-memory segment.
[4152:6920:0520/201951.615:ERROR:persistent_memory_allocator.cc(845)] Corruption detected in shared-memory segment.
[4152:6920:0520/201952.443:ERROR:persistent_memory_allocator.cc(845)] Corruption detected in shared-memory segment.
[4152:6920:0520/201952.687:ERROR:persistent_memory_allocator.cc(845)] Corruption detected in shared-memory segment.
[4152:6920:0520/201952.858:ERROR:persistent_memory_allocator.cc(845)] Corruption detected in shared-memory segment.

只要把瀏覽器驅動程式移到在 Python 安裝目錄的 Scripts 子目錄下就不會出現 "Corruption detected in shared-memory segment" 了, 事實上所有瀏覽器驅動程式都應該放在 Scripts 目錄下, 參考 :

Chrome webdriver selenium memory error- python 3


Selenium 支援多種瀏覽器, 例如 Firefox, Chrome, Safari, Opera, IE, Edge 等等, 可用 help(webdriver) 指令查詢 :

>>>  help(webdriver)                               #查詢 Selenium 支援的瀏覽器
Help on package selenium.webdriver in selenium:

NAME
    selenium.webdriver

DESCRIPTION
    # Licensed to the Software Freedom Conservancy (SFC) under one
    # or more contributor license agreements.  See the NOTICE file
    # distributed with this work for additional information
    # regarding copyright ownership.  The SFC licenses this file
    # to you under the Apache License, Version 2.0 (the
    # "License"); you may not use this file except in compliance
    # with the License.  You may obtain a copy of the License at
    #
    #   http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing,
    # software distributed under the License is distributed on an
    # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    # KIND, either express or implied.  See the License for the
    # specific language governing permissions and limitations
    # under the License.

PACKAGE CONTENTS
    android (package)
    blackberry (package)
    chrome (package)
    common (package)
    edge (package)
    firefox (package)
    ie (package)
    opera (package)
    phantomjs (package)
    remote (package)
    safari (package)
    support (package)
    webkitgtk (package)

VERSION
    3.9.0

FILE
    c:\python36\lib\site-packages\selenium\webdriver\__init__.py

其中值得注意的是 PhantomJS, 這是一個基於 Webkit 的伺服端無使用者介面之 Javascript API, 全面支援 Web 標準 (DOM, CSS, JSON, Canvas, SVG 等), 主要用於網頁測試自動化, 網路爬蟲與網路監測, 完全不需要依靠瀏覽器. 由於無使用者介面, 故占用記憶體少, 執行速度快, 在爬行 Javascript 渲染的網頁時, PhantomJS 與 Selenium 是絕配, 參考 :

https://hiskio.com/courses/76/lectures/1883 (寫得好)

有空再來研究 PhantomJS, 以下針對常用的 Firefox, Edge, 以及 Opera 進行測試.


3. 下載 Firefox 驅動程式 :

Firefox 的驅動程式 geckodriver 下載網址如下 :

https://www.seleniumhq.org/download/
https://github.com/mozilla/geckodriver/releases




解壓縮後為 geckodriver.exe 檔, 同樣將此檔複製到 Python 安裝目錄的 Scripts 目錄下, 然後呼叫webdriver.Firefox() 方法建立瀏覽器物件, 它會同時開啟 geckodriver.exe 驅動程式與模擬的 Firefox 瀏覽器視窗, 再呼叫瀏覽器物件的 get() 方法開啟網頁, 例如 Yahoo 首頁 :

>>> from selenium import webdriver 
>>> browser=webdriver.Firefox() 
>>> browser.get("http://tw.yahoo.com") 




4. 下載 Opera 驅動程式 : 

Opera 的 WebDriver 驅動程式下載網址 :

https://github.com/operasoftware/operachromiumdriver/releases




我下載的是 64 位元版的 operadriver_win64.zip (for Opera 53 版), 解壓縮後得到 operadriver.exe, 複製到 Python 安裝目錄下的 Scripts 子目錄後呼叫 webdrive.Opera() 卻出現 "unknown error: cannot find Opera binary" 錯誤 :

>>> from selenium import webdriver 
>>> browser=webdriver.Opera() 
Traceback (most recent call last):
  File "<pyshell#28>", line 1, in <module>
    browser=webdriver.Opera()
  File "C:\Python36\lib\site-packages\selenium\webdriver\opera\webdriver.py", line 78, in __init__
    service_log_path=service_log_path)
  File "C:\Python36\lib\site-packages\selenium\webdriver\opera\webdriver.py", line 57, in __init__
    service_log_path=service_log_path)
  File "C:\Python36\lib\site-packages\selenium\webdriver\chrome\webdriver.py", line 75, in __init__
    desired_capabilities=desired_capabilities)
  File "C:\Python36\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 156, in __init__
    self.start_session(capabilities, browser_profile)
  File "C:\Python36\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 245, in start_session
    response = self.execute(Command.NEW_SESSION, parameters)
  File "C:\Python36\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 314, in execute
    self.error_handler.check_response(response)
  File "C:\Python36\lib\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: cannot find Opera binary 
  (Driver info: OperaDriver=2.36 (bf69a2a4687a45dedaabd6155fd52bb0b7eb10c5),platform=Windows NT 6.1.7601 SP1 x86_64)

檢查 Opera 版本確實是 v53.0 :




後來在這篇文章中找到解方 (duanzhijie861229), 原來是要用 webdriver.ChromeOptions() 取得  options 物件後指定 Opera 程式的所在位置, 參考 :

"Could not find Opera binary" error in Python




>>> from selenium import webdriver 
>>> options=webdriver.ChromeOptions()   
>>> options.binary_location="C:\Program Files (x86)\Opera\launcher.exe" 
>>> driver=webdriver.Opera(options=options)       
>>> browser=webdriver.Opera(options=options)   
>>> browser.get("http://tw.yahoo.com")   

這樣就可以開啟網頁了 :




雖然可以成功開啟網頁了, 但奇怪的是, IDLE 卻停住了, 沒有顯示提示號, 所以沒辦法呼叫 quit() 來關閉瀏覽器物件, 必須等到手動關閉模擬瀏覽器視窗, 這時 IDLE 才會出現提示號, 呼叫 quit() 即關閉 Opera 驅動程式.

我覺得還是 Chrome 比較好用.


參考 :

https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/

2 則留言 :

Kid 提到...

前輩你好
可以玩看看puppeteer
是Google釋出無介面Chrome控制API(使用nodejs)
簡單好上手

Tony Huang 提到...

感謝您的分享!