Python使用Selenium实现网页自动化之等待与高级操作
为什么需要等待?
现代网页大量使用 AJAX 技术,页面元素不是一次性加载完的:
- 先加载 HTML 骨架
- 再加载 CSS 样式
- 然后执行 JavaScript 动态渲染内容
- 最后可能还要异步请求数据(比如评论区、推荐内容)
如果你用 browser.get() 打开页面后立刻去抓元素,很可能抓不到——因为元素还没加载出来!
三种解决方案:
| 等待方式 | 特点 | 适用场景 |
|---|---|---|
| 强制等待 | 简单粗暴,睡几秒 | 调试时临时用 |
| 隐式等待 | 全局设置,智能等待 | 整个脚本统一配置 |
| 显式等待 | 精确控制,条件触发 | 特定元素需要等待 |
延时等待的三种方式
1. 强制等待(time.sleep)
最简单粗暴的方式:让程序睡几秒,不管页面有没有加载完。
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
s = Service(r'D:\driver\chromedriver.exe')
browser = webdriver.Chrome(service=s)
# 打开百度
browser.get(r'https://www.baidu.com')
# 强制等待5秒
# 不管页面有没有加载完,都等5秒
time.sleep(5)
# 这时候再去操作元素
browser.find_element(By.ID, 'kw').send_keys('python')
browser.quit()
优点: 简单,不用动脑 缺点:
- 浪费时间(页面1秒就加载完了,还要傻等4秒)
- 不靠谱(网络慢的时候5秒可能不够)
- 效率低,不适合大规模爬虫
建议: 调试时临时用,正式代码尽量不用。
2. 隐式等待(implicitly_wait)
全局设置一个最大等待时间,Selenium 会在找元素时自动等待:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
s = Service(r'D:\driver\chromedriver.exe')
browser = webdriver.Chrome(service=s)
# 隐式等待:设置最大等待时间10秒
# 找元素时,如果元素还没加载出来,会等一会儿再试
# 直到元素出现,或者超过10秒才报错
browser.implicitly_wait(10)
# 打开百度
browser.get(r'https://www.baidu.com')
# 这行代码会智能等待:
# - 如果搜索框已经加载出来了,立刻执行
# - 如果没加载出来,每隔一段时间检查一次
# - 最多等10秒,超时就报错
input_box = browser.find_element(By.ID, 'kw')
input_box.send_keys('python')
print(f"当前网址: {browser.current_url}")
print(f"页面标题: {browser.title}")
browser.quit()
工作原理:
找元素 → 元素出现了吗?
↓ 是
立刻返回元素
↓ 否
等一会儿(默认0.5秒)再试
↓ 超过最大等待时间
抛出 NoSuchElementException 异常
优点:
- 全局设置一次,所有找元素操作都生效
- 智能等待,元素提前出现就不用傻等
缺点:
- 只针对"找元素"操作,其他操作不等待
- 不够灵活,不能针对不同元素设置不同等待时间
3. 显式等待(WebDriverWait)
最灵活、最强大的等待方式。设置一个等待条件,每隔一段时间检查一次,条件满足就立刻继续:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.common.by import By
import time
s = Service(r'D:\driver\chromedriver.exe')
browser = webdriver.Chrome(service=s)
# 打开百度
browser.get(r'https://www.baidu.com')
# 创建显式等待对象
# 参数:浏览器驱动、最大等待时间(秒)
wait = WebDriverWait(browser, 10)
# 设置等待条件:等待 id='kw' 的元素加载出来
# presence_of_element_located:元素存在于 DOM 中即可(不一定可见)
input_box = wait.until(ec.presence_of_element_located((By.ID, 'kw')))
# 元素加载出来了,继续执行
input_box.send_keys('Python')
print("搜索框已找到并输入")
time.sleep(2)
browser.quit()
WebDriverWait 构造函数:
WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
| 参数 | 说明 | 默认值 |
|---|---|---|
driver |
浏览器驱动对象 | 必填 |
timeout |
最大等待时间(秒) | 必填 |
poll_frequency |
检查间隔(秒) | 0.5 |
ignored_exceptions |
忽略哪些异常 | None |
两种等待方式:
# until:条件成立时继续执行
wait.until(条件)
# until_not:条件不成立时继续执行(相反逻辑)
wait.until_not(条件)
4. 常用等待条件(expected_conditions)
Selenium 提供了很多内置的等待条件,不用自己写:
from selenium.webdriver.support import expected_conditions as ec
| 条件 | 说明 | 示例 |
|---|---|---|
title_is('标题') |
标题完全匹配 | 等待页面跳转完成 |
title_contains('关键字') |
标题包含关键字 | 等待页面加载 |
presence_of_element_located((By.ID, 'kw')) |
元素存在于 DOM | 等待元素加载 |
visibility_of_element_located((By.ID, 'kw')) |
元素可见 | 等待元素显示 |
invisibility_of_element_located((By.ID, 'loading')) |
元素不可见 | 等待加载动画消失 |
element_to_be_clickable((By.ID, 'btn')) |
元素可点击 | 等待按钮可用 |
text_to_be_present_in_element((By.ID, 'msg'), '成功') |
元素包含指定文本 | 等待提示信息 |
alert_is_present() |
弹窗出现 | 等待 alert 弹窗 |
frame_to_be_available_and_switch_to_it('iframe') |
iframe 可切换 | 等待 iframe 加载 |
实战示例:
from selenium.webdriver.support import expected_conditions as ec
# 等待标题包含"百度"
wait.until(ec.title_contains('百度'))
# 等待元素可见(不只是存在,还要显示出来)
wait.until(ec.visibility_of_element_located((By.ID, 'kw')))
# 等待按钮可点击
wait.until(ec.element_to_be_clickable((By.ID, 'su')))
# 等待加载动画消失
wait.until(ec.invisibility_of_element_located((By.CLASS_NAME, 'loading')))
三种等待方式对比:
| 对比项 | 强制等待 | 隐式等待 | 显式等待 |
|---|---|---|---|
| 设置方式 | time.sleep(n) |
implicitly_wait(n) |
WebDriverWait() |
| 作用范围 | 当前行 | 全局 | 特定元素 |
| 智能程度 | 傻等 | 较智能 | 最智能 |
| 灵活性 | 无 | 一般 | 高 |
| 推荐度 | ⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
最佳实践:
- 优先使用 显式等待
- 可以配合 隐式等待 做全局兜底
- 强制等待 只在调试时用
运行 JavaScript
Selenium 可以直接在页面中执行 JavaScript 代码,这是它的一个强大功能:
1. 滚动页面
很多网页是懒加载的,需要滚动到页面底部才会加载更多内容:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import time
s = Service(r'D:\driver\chromedriver.exe')
browser = webdriver.Chrome(service=s)
# 打开知乎发现页
browser.get('https://www.zhihu.com/explore')
time.sleep(2)
# 执行 JavaScript:滚动到页面底部
# document.body.scrollHeight 获取页面总高度
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
print("已滚动到页面底部")
# 弹出提示框
browser.execute_script('alert("已滚动到页面底部")')
time.sleep(5)
browser.quit()

常用滚动操作:
# 滚动到页面底部
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
# 滚动到页面顶部
browser.execute_script('window.scrollTo(0, 0)')
# 向下滚动 500 像素
browser.execute_script('window.scrollBy(0, 500)')
# 滚动到指定元素位置
element = browser.find_element(By.ID, 'target')
browser.execute_script('arguments[0].scrollIntoView();', element)
2. 获取页面信息
# 获取页面标题(和 browser.title 一样)
title = browser.execute_script('return document.title;')
# 获取页面 URL(和 browser.current_url 一样)
url = browser.execute_script('return document.URL;')
# 获取页面所有 cookie
cookies = browser.execute_script('return document.cookie;')
3. 修改页面元素
# 修改元素属性
browser.execute_script(
'arguments[0].setAttribute("value", "新值");',
element
)
# 隐藏元素
browser.execute_script(
'arguments[0].style.display = "none";',
element
)
# 点击元素(某些元素用 Selenium 的 click() 点不了时)
browser.execute_script('arguments[0].click();', element)
什么时候需要用 execute_script?
- 页面滚动(懒加载)
- Selenium 原生方法搞不定的点击
- 需要获取或修改页面内部状态
- 绕过某些前端限制
操作 Cookie
Cookie 是网站存储在用户浏览器里的小文件,用来记录登录状态、用户偏好等。Selenium 可以方便地操作 Cookie。
1. 获取 Cookie
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import time
s = Service(r'D:\driver\chromedriver.exe')
browser = webdriver.Chrome(service=s)
# 打开知乎
browser.get('https://www.zhihu.com/explore')
# 获取所有 Cookie
cookies = browser.get_cookies()
print(f'所有 Cookie:')
for cookie in cookies:
print(f" {cookie['name']}: {cookie['value'][:20]}...")
# 获取单个 Cookie
cookie = browser.get_cookie('name')
browser.quit()
Cookie 包含的字段:
| 字段 | 说明 |
|---|---|
name |
Cookie 名称 |
value |
Cookie 值 |
domain |
所属域名 |
path |
有效路径 |
expiry |
过期时间(时间戳) |
secure |
是否只在 HTTPS 传输 |
httpOnly |
是否禁止 JavaScript 访问 |
2. 添加 Cookie
# 添加一个 Cookie
browser.add_cookie({
'name': 'my_cookie',
'value': 'my_value',
'domain': '.zhihu.com',
'path': '/'
})
# 添加后查看
print(f'添加后的 Cookie:{browser.get_cookies()}')
注意: 添加 Cookie 前必须先访问过该域名,否则会报错!
3. 删除 Cookie
# 删除指定 Cookie
browser.delete_cookie('name')
# 删除所有 Cookie
browser.delete_all_cookies()
print(f'删除后 Cookie:{browser.get_cookies()}') # 空列表 []
4. Cookie 实战:保持登录状态
场景: 每次运行脚本都要重新登录,很麻烦。可以第一次手动登录后保存 Cookie,以后直接加载 Cookie 就能保持登录。
import json
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
s = Service(r'D:\driver\chromedriver.exe')
browser = webdriver.Chrome(service=s)
# 第一步:手动登录,保存 Cookie
browser.get('https://www.zhihu.com')
print("请手动登录...")
input("登录完成后按回车继续...")
# 保存 Cookie 到文件
cookies = browser.get_cookies()
with open('cookies.json', 'w') as f:
json.dump(cookies, f)
print("Cookie 已保存")
# 第二步:下次运行时加载 Cookie
browser.delete_all_cookies()
with open('cookies.json', 'r') as f:
cookies = json.load(f)
for cookie in cookies:
browser.add_cookie(cookie)
# 刷新页面,此时应该是登录状态
browser.refresh()
print("已使用 Cookie 登录")
browser.quit()
Cookie 的妙用:
- 保持登录 - 不用每次都扫码/输密码
- 绕过验证 - 加载已验证的 Cookie
- 多账号切换 - 保存多个账号的 Cookie
- 爬虫伪装 - 带上正常用户的 Cookie,降低被封概率
实战案例:自动登录代理网站
案例背景
写爬虫时经常需要代理 IP,很多网站提供代理 IP 服务。我们以自动登录一个代理网站为例,展示完整的自动化流程。
完整代码
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import time
s = Service(r'D:\driver\chromedriver.exe')
browser = webdriver.Chrome(service=s)
# 设置隐式等待
browser.implicitly_wait(10)
# 打开登录页面
browser.get('http://www.66daili.cn/UserManage/Login/')
# 输入账号
browser.find_element(By.ID, 'username').send_keys('youbafu')
# 输入密码
browser.find_element(By.ID, 'password').send_keys('youbafu123')
# 勾选"记住账号"
remember = browser.find_element(By.ID, 'remember')
# 判断是否已勾选,没勾选就点击
if not remember.get_attribute('checked'):
remember.click()
# 点击登录按钮
browser.find_element(By.ID, 'submit').click()
# 等待登录完成
time.sleep(2)
print("登录成功!")
# 保持页面打开,方便查看
browser.quit()

代码解析:
- 隐式等待 - 设置10秒,找元素时自动等待
- 输入账号密码 - 找到输入框,send_keys 输入
- 勾选记住账号 - 先判断是否已勾选,避免重复点击
- 点击登录 - 提交表单
- 等待 - 给页面跳转留时间
文档总结
一、核心知识点回顾
1. 三种等待方式
| 等待方式 | 代码 | 原理 | 适用场景 |
|---|---|---|---|
| 强制等待 | time.sleep(n) |
程序暂停 n 秒 | 调试时临时用 |
| 隐式等待 | implicitly_wait(n) |
找元素时最多等 n 秒 | 全局统一配置 |
| 显式等待 | WebDriverWait(driver, n) |
条件满足立刻继续 | 特定元素精确控制 |
选择建议:
- 优先用 显式等待(最灵活、最省时间)
- 可以配合 隐式等待 做兜底
- 强制等待 只在调试时用,正式代码避免
2. 显式等待的常用条件
from selenium.webdriver.support import expected_conditions as ec
# 元素相关
ec.presence_of_element_located((By.ID, 'kw')) # 元素存在于 DOM
ec.visibility_of_element_located((By.ID, 'kw')) # 元素可见
ec.element_to_be_clickable((By.ID, 'btn')) # 元素可点击
ec.invisibility_of_element_located((By.ID, 'loading')) # 元素消失
# 页面相关
ec.title_contains('百度') # 标题包含
ec.title_is('百度一下,你就知道') # 标题完全匹配
# 其他
ec.alert_is_present() # 弹窗出现
ec.text_to_be_present_in_element((By.ID, 'msg'), '成功') # 文本出现
记忆口诀:
presence= 存在(在 DOM 里就行)visibility= 可见(不仅要存在,还要显示出来)clickable= 可点击(可见 + 启用)
3. 运行 JavaScript
# 滚动页面
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
# 滚动到元素
element = browser.find_element(By.ID, 'target')
browser.execute_script('arguments[0].scrollIntoView();', element)
# 点击元素(Selenium 点不了时用)
browser.execute_script('arguments[0].click();', element)
什么时候用?
- 懒加载页面需要滚动
- Selenium 原生方法失效
- 需要获取/修改页面内部状态
4. Cookie 操作
# 获取
browser.get_cookies() # 所有 Cookie
browser.get_cookie('name') # 单个 Cookie
# 添加
browser.add_cookie({'name': 'xxx', 'value': 'yyy'})
# 删除
browser.delete_cookie('name') # 删除指定
browser.delete_all_cookies() # 删除所有
Cookie 的妙用:
- 保持登录状态(不用每次都登录)
- 多账号切换(保存多套 Cookie)
- 爬虫伪装(带上正常用户的 Cookie)
二、常见坑与解决方案
坑1:显式等待和隐式等待混用导致超时异常
原因:两者时间叠加,可能超过预期
解决:优先只用显式等待,或注意时间设置
坑2:添加 Cookie 报错
原因:没先访问对应域名
解决:先 browser.get('网址'),再 add_cookie()
坑3:execute_script 点击无效
原因:元素还没加载出来
解决:先等待元素出现,再执行 JS
坑4:Cookie 保存后加载还是未登录
原因:Cookie 过期了,或缺少关键字段
解决:检查 Cookie 的 expiry 时间,确保完整保存
三、学习建议
- 等待是重中之重 —— 80% 的 Selenium 问题都是等待问题
- 显式等待优先 —— 比强制等待高效,比隐式等待灵活
- Cookie 是神器 —— 学会保存和加载 Cookie,省去大量登录时间
- JS 是兜底方案 —— Selenium 搞不定的,试试 execute_script
- 多写多调 —— 网页结构经常变,代码要跟着调整
浙公网安备 33010602011771号