Beijing: ☁️ 🌡️+18°C 🌬️↓4km/h

写在前面

日常工作中,在使用网页爬虫抓取网页数据受到限制时,我们可能考虑会对一些无需登录验证的网页,使用模拟浏览器点击,例如获取网页的检索结果、批量下载文件等,Selenium 模块提供 API 调用 webdriver,可以在一定程度上满足我们的需求,但同时需要下载设置路径等操作,因此还需要配合 webdrvier Manager 才可以对 webdriver 进行便捷化管理。

通过 pip install selenium webdriver-manager 完成相关 Python 库的安装。

driver 安装

Chrome 安装

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

driver = webdriver.Chrome(ChromeDriverManager().install())

Firefox 安装

from selenium import webdriver
from webdriver_manager.firefox import GeckoDriverManager
from selenium.webdriver.firefox.service import Service

ser = Service(GeckoDriverManager().install())
driver = webdriver.Firefox(service=ser)

Edge 安装

from selenium import webdriver
from webdriver_manager.microsoft import EdgeChromiumDriverManager

driver = webdriver.Edge(EdgeChromiumDriverManager().install())

在多次尝试使用过程中,Firefox体验相对较好。

基本使用

获取 driver 后,我们需要使用 driver.get(url) 使得浏览器访问我们需要的页面,结束时使用 driver.close() 关闭即可。

定位元素

在对网页的元素定位中,最常使用的是 xpath,因为我们只要确定浏览器网页的操作顺序,进入浏览器开发者模式,复制对应的页面元素 xpath 路径即可,例如:

# 通过xpath定位并点击元素
driver.find_element('xpath', '//*[@id="exportToExcelButton"]').click()

页面交互

有时候我们在选择对应的页面元素后,还需要填写相应的内容或敲击对应的键盘按键,这里使用比较直接的键盘输入方法:

from selenium.webdriver.common.keys import Keys

# 找到对应元素并敲击对应按键
start = driver.find_element('name', 'markFrom')
start.send_keys(Keys.BACKSPACE)

# 填写对应的文本内容
driver.find_element('name', 'markFrom').send_keys('123456')

时间等待

当今许多页面加载中使用 AJAX 技术,当网页在浏览器中载入时,其中的许多元素并非是同一时间段进行加载,因此需要经过等待,slenium 提供了 Explicit Waits 以及 Implicit Waits 两种方式。

显式等待(Explicit Waits)

代码在执行前必须满足某一条件,否则将抛出异常。下面这段代码表示给予 driver 最多 10 秒时间去定位 ID 为 myDynamicElement 的元素(PS:即使网页其它元素未加载完成也会继续执行下一步),如果 10 秒内未能定位到,则抛出异常。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delays_loading")
try:
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "myDynamicElement"))
    )
finally:
    driver.quit()

隐式等待(Implicit Waits)

是的 driver 作用于全局,webdriver 被要求等待一段特定的时间直至整个页面加载完成,然后进行下一步操作。

from selenium import webdriver
from webdriver_manager.firefox import GeckoDriverManager
from selenium.webdriver.firefox.service import Service

ser=Service(GeckoDriverManager().install())
driver = webdriver.Firefox(service=ser)

driver.implicitly_wait(1) # seconds
driver.get("https://www.baidu.com/")

driver.find_element('xpath', '/html/body/div[1]/div[1]/div[5]/div/div/div[3]/div/a[2]/span').click()
driver.quit()

多进程

通常我们会有同时打开多个浏览器窗口的需求,这里我们结合 Python multiprocessing 模块进行演示:

import time
import os
from multiprocessing import Pool
from selenium import webdriver
from webdriver_manager.firefox import GeckoDriverManager
from selenium.webdriver.firefox.service import Service

def browser():
    driver = webdriver.Chrome()
    return driver

def task(url):
    driver = browser()
    driver.get(url)
    time.sleep(3)
    driver.close()

if __name__ =='__main__':
    links = ['https://www.baidu.com', 'https://bilibili.com']
    print('Parent process %s.' % os.getpid())
    pool = Pool(processes=4)
   
    for i in range(len(links)):
        pool.apply_async(task, args={links[i]})

    print('Waiting for all subprocesses done...')
    pool.close()
    pool.join()
    print('All subprocesses done.')

📖 参考文献

  1. Se Document
  2. Easily Manage Install Webdrivers for Selenium
  3. What are the differences between implicit and explicit waits in Selenium with python?
  4. 廖雪峰 Python 教程——多进程
  5. How To use multiprocess pool With Python Selenium