安装 selenium ,使用 requestium 来调用 selenium 程序更为简单,因此可一起安装:
sudo -E pip3 install selemium requestium
接下来主要是安装浏览器以及对应的驱动程序(即 driver )。系统环境为 ubuntu 20.04 和 Python 3.8。执行日期为 2024-01-11。
1、安装 Chrome 和 chromedriver
首先安装 Chrome :
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo dpkg -i google-chrome-stable_current_amd64.deb
下面的脚本可检查 Chrome 版本, 2024-01-11 时 Chrome 的 stable 版本是: Google Chrome 120.0.6099.216。
google-chrome --version
1.1、自动安装 ChromeDriver
接下来需要安装驱动 Chrome Driver ,它用于和 Google Chrome 交互,必须安装。 webdriver-manager 可以自动识别 Chrome 版本并安装相关驱动:
sudo -E pip3 install webdriver-manager
然后这么使用:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
options = Options()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(options, service)
driver.get("https://baidu.com")
print(driver.title)
driver.close()
但这里面有很多变数,主要是网络条件,包括是否可访问外网(相对局域网而言),是否可以访问外网(相对境内)。我测试就未成功。
1.2、手动安装 ChromeDriver
如果自动安装收到网络条件等因素不成功,我们只能手工安装 ChromeDriver。
按照大部分教程,我们可以在https://chromedriver.storage.googleapis.com/index.html这里找到对应版本的 driver 下载即可。但不幸的是,( 2024-01-11 )此处的最新版本只到 114.0.5735.90 ,并没有我们需要的 120.0.6099.216。(直接 apt 安装的 Chrome 版本又太低,同样在这里找不到对应的 driver )。
然后 Google 提供最新版本 Chrome 的页面https://googlechromelabs.github.io/chrome-for-testing/,其 stable 版本是 120.0.6099.109。120.0.6099.216 版本被标记为 stable(upcoming),其 driver 还不提供下载。
但经测试, 120.0.6099.109 的 ChromeDriver 驱动也可用于 120.0.6099.216 版的 Chrome 浏览器。所以我们安装 109 即可。直接下载解压缩到某个位置即可。
2、测试 requestium 效果(失败,略过)
requestium 集成了 request 和 selenium。标准测试代码:
from requestium import Session, Keys
# 创建一个新的session
s = Session(webdriver_path='./geckodriver',
browser='firefox',
default_timeout=15,
webdriver_options={'arguments': ['headless']})
# 访问登录页面
s.driver.get('https://baidu.org')
# 等待页面加载完成
s.driver.wait_for_page_load()
# 打印出当前页面的URL,确认是否登录成功
print(s.driver.title)
测试不成功,提示:
TypeError: __init__() got multiple values for argument 'options'
主要原因是 python 3.8 只能安装 requestium 0.2.x 版本,它只适配了 selenium 3.x。但最新的 selenium 4.x 改动了初始化方式,导致 Session 无法正常初始化。
3、测试 selenium 效果 以及教程
3.1、初始化 selenium
注意网上很多实例都是基于 selenium 3 或以下版本。4.0 版本改动很大,初始化方式也被改动了, Chrome 类不再接受 executable_path 的传入参数,必须通过 Service 对象传入:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
options = Options()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
# 这个路径要改成你下载的的chromedriver的存放地址
service = Service(executable_path="/opt/3rd/chromedriver-linux64/chromedriver")
driver = webdriver.Chrome(options, service)
driver.get("https://baidu.com")
print(driver.title)
另外, Service 会在本地建立一个服务,因此不能使用代理。包括环境变量https_proxy
、http_proxy
设置都必须取消,否则会提示无法访问端口。
另外注意,这样初始化的 driver 是单实例的,也就是每次只操作当前访问或跳转的网页。
3.2、填写登录信息
selenium 最重要的就是提供登录,可以模拟用户输入和点击
username = driver.find_element("name", "username")
username.send_keys("myname")
submit = driver.find_element("xpath", "//div[@class='btn']/a")
submit.click()
但我在一个网页的测试中,上述操作总是不成功,提示selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable
,也一直没找到原因。最后用间接方法实现:
driver.execute_script('arguments[0].value = "myname";', username)
driver.execute_script('arguments[0].click();', submit)
3.3、等待跳转
在点击登录后,有些网站会有多轮跳转,在完成跳转之前操作会出问题。因此需等待跳转完成。这时候可通过检查特定元素对象存在性,下面是检查一个 id 为 step 的元素是否存在,等待时间为 30 秒,超时将记录一个错误信息:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
try:
wait = WebDriverWait(driver, 30)
wait.until(EC.visibility_of_element_located(("id", 'step')))
except Exception as e:
log.error("登录后迟迟无法跳转到主页,错误:%s。当前页面:%s",
e, driver.page_source)
3.4、和 requests 的结合
requestium 集成了 requests 和 selenium。但 Python 3.8 下无法使用。暂时略过。
下面代码可以将 selenium 的 cookie 信息挪到 requests ,然后读取网页数据,由于不会渲染网页,速度比 driver.get 要快很多:
import requests
session = requests.Session()
for cookie in driver.get_cookies():
session.cookies.set(cookie['name'], cookie['value'])
content = session.get("url").content.decode()
print(content)
而且我们还可以把 cookies 存下来,下次直接读取,避免再次登录操作。
3.5、进阶操作
3.5.1、跳转打开新网页
driver.switch_to.window("windowName")
3.5.2、页面内的 iframe
driver.switch_to.frame("frameName")
3.6、selenium 的常用函数
基本操作和网页内容:
- driver.get(url):访问网页。
- driver.page_source :网页源码( html )
- driver.title :网页标题
- driver.current_url :当前网页地址
查找元素:
- driver.find_element(type, info): type 可以为"name", "id", "class name", "xpath", "css selector",用于查找页面上指定元素。可参考官方文档: Locating Elements。其中 css selector 最直观。
- driver.find_element 可以连着使用:
driver.find_element("id", "form").find_element("name", "username")
。 - driver.find_elements 类似,只是返回符合条件的多个元素的列表。
元素上操作:
- ele.send_keys("abc"):填写元素(通常是一个 input )的内容。
- ele.clear():清除元素(通常是一个 input )的内容。
- ele.click():点击元素。
- ele.select_by_index(index):选择选择项。还可以 select_by_value/select_by_visible_text。
- ele.get_attribute("value"):获取元素的属性。
操作 cookie (一个 cookie 是一个{name, value}
的字典):
- driver.add_cookie({name, value})
- driver.get_cookies():获取所有 cookie 列表。
- driver.get_cookie(name):获取指定 cookie
4、一些注意事项
- 不能设置环境代理,可能导致
driver = webdriver.Chrome()
初始化失败,提示: The remote host or network may be down. Please try the request again。
Q. E. D.