Python-Selenium詳解


  • Selenium 環境配置好之后,我們就可以使用 Selenium 來操作瀏覽器,做一些我們想做的事情了。
  • 在我們爬取網頁過程中,經常發現我們想要獲得的數據並不能簡單的通過解析 HTML 代碼獲取,這些數據是通過 AJAX 異步加載方式或經過 JS 渲染后才呈現在頁面上顯示出來。
  • 這種情況下我們就可以使用 Selenium 來模擬瀏覽器瀏覽頁面,進而解決 JavaScript 渲染的問題。
  • 瀏覽器設置

    打開瀏覽器

  • 我們用最簡潔的代碼來打開 Chrome 瀏覽器,並訪問 http://www.baidu.com 這個網站:
  • from selenium import webdriver
    
    # 聲明瀏覽器對象
    driver = webdriver.Chrome()
    # 訪問頁面
    driver.get("http://www.baidu.com")

     

  • 我們可以看到桌面會彈出一個瀏覽器窗口,並打開了百度的首頁,如下圖:
  •  

     

  • 注意紅框圈住的部分,這表示這個窗口是我們程序打開的,現在瀏覽器的控制權在我們的程序中,我們可以用代碼讓瀏覽器擺出各種姿勢了!
  • 設置瀏覽器參數

  • 為了避免每次運行程序都打開一個窗口,我們也可以設置無窗口訪問,只需添加瀏覽器參數即可:
  • from selenium import webdriver
    
    # 設置無窗口
    chrome_options = webdriver.ChromeOptions()
    chrome_options.add_argument('--headless')
    
    # 聲明瀏覽器對象
    driver = webdriver.Chrome(options=chrome_options)
    
    # 訪問頁面
    driver.get("http://www.baidu.com")

     

  • 常見的瀏覽器參數還有:
  • # 啟動就最大化
    --start-maximized
    
    # 指定用戶文件夾 User Data 路徑,可以把書簽這樣的用戶數據保存在系統分區以外的分區
    –-user-data-dir=”[PATH]”
    
    # 指定緩存Cache路徑
    –-disk-cache-dir=”[PATH]“
    
    # 指定Cache大小,單位Byte
    –-disk-cache-size=100
    
    # 隱身模式啟動
    –-incognito
    
    # 禁用Javascript
    –-disable-javascript
    
    # 禁止加載所有插件,可以增加速度
    --disable-plugins
    
    # 禁用JavaScript
    --disable-javascript
    
    # 禁用彈出攔截
    --disable-popup-blocking
    
    # 禁用插件
    --disable-plugins
    
    # 禁用圖像
    --disable-images

     

  • 還有其他好多參數,具體可參見 https://peter.sh/experiments/chromium-command-line-switches/ ,該網站羅列了所有的參數。
  • 設置代理

    設置代理很簡單,只需要添加一個瀏覽器參數就行:

  • chrome_options.add_argument('--proxy-server=http://{ip}:{port}')

     

  • 在參數里面加上代理的 IP 和端口號。
  • 獲取頁面元素

    獲取單個元素

    selenium 查找元素有兩種方法:第一種是指定使用哪種方法去查找元素,比如指定 CSS 選擇器或者根據 xpath 去查找;另一種是直接使用 find_element() ,傳入的第一個參數為需要使用的元素查找方法,第二個參數為查找值。來看下例:

  • from selenium import webdriver
    from selenium.webdriver.common.by import By
    
    # 聲明瀏覽器對象
    driver = webdriver.Chrome()
    # 訪問頁面
    driver.get("http://www.baidu.com")
    
    # 通過id查找
    element = driver.find_element_by_id("kw")
    print(element.tag_name)
    # 通過name查找
    element = driver.find_element_by_name("wd")
    print(element.tag_name)
    # 通過xpath查找
    element = driver.find_element_by_xpath('//*[@id="kw"]')
    print(element.tag_name)
    
    # 通過另一種方式查找
    element = driver.find_element(By.ID, "kw")
    print(element.tag_name)

     

  • 上面例子中,我們通過不同的方式來獲取百度的搜索框,並且打印 tag_name 屬性,最終的結果都是一樣的:input 。
  • 獲取多個元素

    我們也可以通過 find_elements() 方法獲取多個屬性,結果會以 list 的形式返回。我們來看例子:

  • from selenium import webdriver
    from selenium.webdriver.common.by import By
    
    # 聲明瀏覽器對象
    driver = webdriver.Chrome()
    # 訪問頁面
    driver.get("http://www.baidu.com")
    
    # 查找多個元素
    elements = driver.find_elements(By.CLASS_NAME, 'mnav')
    for e in elements:
        print(e.text)
    
    # 輸出結果
    新聞
    hao123
    地圖
    視頻
    貼吧
    學術

     

  • 上例中,我們通過 class_name 來獲取百度首頁上方的百度導航,接着將獲取到的導航欄的名稱打印了出來。
  • 頁面操作

    我們可以使用 selenium 來模擬頁面操作,例如鼠標點擊事件,鍵盤事件等。我們來看一下例子:

  • from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    import time
    
    # 聲明瀏覽器對象
    driver = webdriver.Chrome()
    # 訪問頁面
    driver.get("http://www.baidu.com")
    
    # 獲取百度搜索框元素
    element = driver.find_element_by_id("kw")
    # 在搜索框中輸入關鍵詞selenium
    element.send_keys("selenium")
    # 點擊"百度一下"按鈕
    driver.find_element_by_xpath('//*[@id="su"]').click()
    
    time.sleep(5)
    
    # 清空搜索框關鍵詞
    element.clear()
    
    time.sleep(2)
    
    # 在搜索框中輸入關鍵詞python,並模擬鍵盤的enter操作
    element.send_keys("python", Keys.ENTER)
    
    time.sleep(5)
    
    driver.close()

     

  • 在例子中,我們先是找到百度的搜索框對應的元素,然后模擬在搜索框中輸入關鍵詞 “selenium”,接下來模擬點擊"百度一下"按鈕,我們可以看到頁面中出現了搜索 “selenium” 的結果。

    接着我們使用 clear() 方法清空了搜索框,然后模擬輸入關鍵詞 “python” 並且模擬鍵盤的 enter 鍵操作,同樣獲得了搜索 “python” 的結果。

    當然,我們還可以模擬鼠標右擊、雙擊、拖拽等操作,就留給大家自己去探索了。

  • 瀏覽器操作

    等待加載

    請求網頁時,可能會存在 AJAX 異步加載的情況。而 selenium 只會加載主網頁,並不會考慮到 AJAX 的情況。因此,使用時需要等待一些時間,讓網頁加載完全后再進行操作。

    隱式等待

    使用隱式等待時,如果 webdriver 沒有找到指定的元素,將繼續等待指定元素出現,直至超出設定時間,如果還是沒有找到指定元素,則拋出找不到元素的異常。默認等待時間為 0。隱式等待是對整個頁面進行等待。需要特別說明的是:隱性等待對整個 driver 的周期都起作用,所以只要設置一次即可。

  • from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    
    # 聲明瀏覽器對象
    driver = webdriver.Chrome()
    
    # 設置隱式等待時間,單位為秒
    driver.implicitly_wait(0)
    
    # 訪問頁面
    driver.get("https://www.baidu.com/")
    
    # 設置搜索關鍵詞
    element = driver.find_element_by_id("kw")
    element.send_keys("Selenium", Keys.ENTER)
    
    # 頁面右邊的"相關術語"
    element2 = driver.find_element_by_class_name("opr-recommends-merge-p")
    print(element2)

     

  • 先打開瀏覽器訪問百度首頁,然后在搜索框輸入 “Selenium” 關鍵字,再回車查詢。百度會根據輸入的關鍵詞在頁面的右邊展示“相關術語”,這一步是異步加載,需要時間來查詢和傳輸,而我們設置的等待時間是 0,所以肯定會超時。運行后我們會看到報錯:
  • # 報錯信息
    selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":".opr-recommends-merge-p"}
      (Session info: chrome=77.0.3865.120)

     

  • 當我們把等待時間設置為 10 秒時,我們會看到控制台的正確打印了。
  • 顯式等待

    顯式等待是對指定的元素進行等待。首先判定等待條件是否成立,如果成立,則直接返回;如果條件不成立,則等待最長時間為設置的等待時間,如果超過等待時間后仍然沒有滿足等待條件,則拋出異常。

  • from selenium import webdriver
    from selenium.webdriver.common.by import By
    from selenium.webdriver.common.keys import Keys
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    # 聲明瀏覽器對象
    driver = webdriver.Chrome()
    
    # 訪問頁面
    driver.get("https://www.baidu.com/")
    
    # 設置搜索關鍵詞
    element = driver.find_element_by_id("kw")
    element.send_keys("selenium", Keys.ENTER)
    
    # 此時頁面右邊的"相關術語"還沒有加載出來,肯定會報錯
    #element1 = driver.find_element_by_class_name("opr-recommends-merge-p")
    #print(element1)
    
    # 顯示等待10秒,直到頁面右邊的"相關術語"出現
    WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CLASS_NAME, "opr-recommends-merge-p")))
    
    # 獲取頁面右邊的"相關術語"
    element2 = driver.find_element_by_class_name("opr-recommends-merge-p")
    print(element2)

     

  • 運行這段代碼,在打印 element1 的時候肯定會報錯,因為此時頁面右邊的“相關術語”還沒加載出來。我們注釋掉獲取和打印 element1 的這兩行,然后設置一個顯式的等待條件和 10 秒的等待時間,element2 就可以順利打印出來了。
  • 瀏覽器前進和后退

    我們可以通過 selenium 來操縱瀏覽器的前進和后退,方法很簡單,分別是 back() 和 forward()。來看下例:

  • from selenium import webdriver
    import time
    
    # 聲明瀏覽器對象
    driver = webdriver.Chrome()
    # 訪問百度
    driver.get("http://www.baidu.com")
    time.sleep(2)
    # 訪問微博
    driver.get("https://weibo.com")
    time.sleep(2)
    # 訪問知乎
    driver.get("http://www.zhihu.com")
    time.sleep(2)
    # 返回上個頁面
    driver.back()
    time.sleep(2)
    # 前進到下個頁面
    driver.forward()
    
    # 退出
    driver.close()

     

  • 首先依次打開百度、微博和知乎三個網站(中間設置的等待時間是為了更好地看演示效果)。然后我們調用返回上個頁面方法,可以看到瀏覽器返回到了微博頁面,接着我們調用前進到下個頁面方法,可以看到瀏覽器回到了知乎頁面。
  • 操作 Cookie

    我們可以通過 selenium 來設置瀏覽器的 cookie,包括添加 cookie ,刪除 cookie ,獲取 cookie 等操作。我們來看個例子:

  • from selenium import webdriver
    
    # 聲明瀏覽器對象
    driver = webdriver.Chrome()
    
    # 訪問百度
    driver.get("http://www.baidu.com")
    
    # 獲取當前的cookie
    print(driver.get_cookies())
    
    # 添加cookie
    driver.add_cookie({'name': 'mycookie', 'value': 'world'})
    
    # 獲取設置的cookie
    print(driver.get_cookie('mycookie'))
    
    # 刪除設置的cookie
    driver.delete_cookie('mycookie')
    
    # 再次獲取設置的cookie
    print(driver.get_cookie('mycookie'))
    
    # 清除所有cookie
    driver.delete_all_cookies()
    
    # 再次獲取cookie
    print(driver.get_cookies())
    
    # 退出
    driver.close()

    # 輸出信息[{'domain': '.baidu.com', 'httpOnly': False, 'name': 'H_PS_PSSID', 'path': '/', 'secure': False, 'value': '1422_21106_29721_29568_29221_26350_29589'}, {'domain': '.baidu.com', 'expiry': 1570877928.79997, 'httpOnly': False, 'name': 'BDORZ', 'path': '/', 'secure': False, 'value': 'B490B5EBF6F3CD402E515D22BCDA1598'}, {'domain': 'www.baidu.com', 'expiry': 1571655528, 'httpOnly': False, 'name': 'BD_UPN', 'path': '/', 'secure': False, 'value': '123253'}, {'domain': 'www.baidu.com', 'httpOnly': False, 'name': 'BD_HOME', 'path': '/', 'secure': False, 'value': '0'}, {'domain': '.baidu.com', 'expiry': 3718275175.123787, 'httpOnly': False, 'name': 'PSTM', 'path': '/', 'secure': False, 'value': '1570791528'}, {'domain': '.baidu.com', 'httpOnly': False, 'name': 'delPer', 'path': '/', 'secure': False, 'value': '0'}, {'domain': '.baidu.com', 'expiry': 3718275175.123763, 'httpOnly': False, 'name': 'BIDUPSID', 'path': '/', 'secure': False, 'value': '5A2BAF0B0AE83FA189BE38C65DC65395'}, {'domain': 'www.baidu.com', 'expiry': 1570791529.123808, 'httpOnly': False, 'name': 'BD_LAST_QID', 'path': '/', 'secure': False, 'value': '10847283847030224144'}, {'domain': '.baidu.com', 'expiry': 3718275175.123643, 'httpOnly': False, 'name': 'BAIDUID', 'path': '/', 'secure': False, 'value': '5A2BAF0B0AE83FA189BE38C65DC65395:FG=1'}]{'domain': 'www.baidu.com', 'httpOnly': False, 'name': 'mycookie', 'path': '/', 'secure': True, 'value': 'world'}None[]

     

  • 我們通過 add_cookie() 方法,來設置 cookie 的名稱和值,通過給 delete_cookie() 方法傳遞 cookie 的名稱來刪除 cookie,還可以通過 get_cookies() 和 delete_all_cookies() 來獲取所有 cookie 以及刪除所有 cookie 。
  • 標簽管理

    有些時候我們需要在瀏覽器里切換標簽頁,或者增加一個新標簽頁,或者刪除一個標簽頁,都可以使用 selenium 來實現。我們來看例子:

  • from selenium import webdriver
    import time
    
    # 聲明瀏覽器對象
    driver = webdriver.Chrome()
    
    # 訪問百度
    driver.get("http://www.baidu.com")
    
    time.sleep(2)
    
    # 新增一個標簽頁
    driver.execute_script('window.open()')
    
    time.sleep(2)
    
    # 打印標簽頁
    print(driver.window_handles)
    
    # 切換至標簽頁1(當前標簽頁為0)
    driver.switch_to.window(driver.window_handles[1])
    
    time.sleep(2)
    
    # 在當前標簽頁訪問知乎
    driver.get("http://www.zhihu.com")
    
    time.sleep(2)
    
    # 切換至標簽頁0
    driver.switch_to.window(driver.window_handles[0])
    
    time.sleep(2)
    
    # 在標簽頁0訪問微博
    driver.get("http://www.weibo.com")
    
    time.sleep(2)
    
    # 關閉
    driver.close()
    
    # 退出
    driver.quit()

     

  • 大家運行代碼就可以體會到切換標簽頁和訪問網頁的變化,中間加了等待是為了延遲變化。另外,注意標簽頁從左往右是從 0 開始編號的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM