文章目录
- [一、为什么 Selenium 需要执行 JavaScript](#一、为什么 Selenium 需要执行 JavaScript)
- [二、Selenium 中执行 JavaScript](#二、Selenium 中执行 JavaScript)
- [三、execute_script() 的参数传递](#三、execute_script() 的参数传递)
- [四、JavaScript 的返回值处理](#四、JavaScript 的返回值处理)
- 五、掌握滚动条操作的几种方式
- 六、处理页面无限滚动和懒加载
- 七、结合等待机制使用滚动条操作
-
- [1. 显式等待元素出现](#1. 显式等待元素出现)
- [2. 滚动后等待新元素加载](#2. 滚动后等待新元素加载)
- 八、常见问题
-
- [1. 为什么 `scrollTo` 后页面没变化?](#1. 为什么
scrollTo后页面没变化?) - [2. 为什么滚动后内容没有加载?](#2. 为什么滚动后内容没有加载?)
- [3. 为什么用 `click()` 失败,但 JS 点击成功?](#3. 为什么用
click()失败,但 JS 点击成功?) - [4. 为什么修改输入框 value 后页面没反应?](#4. 为什么修改输入框 value 后页面没反应?)
- [1. 为什么 `scrollTo` 后页面没变化?](#1. 为什么
一、为什么 Selenium 需要执行 JavaScript
Selenium 的核心思想是模拟用户行为,但真实浏览器中的很多功能,浏览器本身是通过 JavaScript 驱动的。页面中常见的这些情况,往往需要 JavaScript 配合:
- 触发一些 Selenium 直接不好操作的前端行为。
- 修改页面内容,例如隐藏、显示、删除 DOM。
- 获取页面中动态生成的数据。
- 处理滚动条、懒加载、无限下拉加载。
- 绕过某些无法直接点击的遮挡元素。
- 获取页面里更精细的状态,例如
document.readyState。
也就是说,Selenium 负责"操作浏览器",JavaScript 负责"深入浏览器内部直接控制页面"。
二、Selenium 中执行 JavaScript
在 Python 版 Selenium 中,通常通过 execute_script() 方法执行 JavaScript。
1. 基本语法
python
driver.execute_script(js代码, 参数1, 参数2, ...)
其中:
js代码:要执行的 JavaScript 字符串- 后面的参数:会传入 JavaScript 中,作为
arguments[0]、arguments[1]等使用
2. 示例
python
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://www.example.com")
title = driver.execute_script("return document.title;")
print(title)
说明
return document.title;会返回当前页面标题- 在 Python 中,
execute_script()返回 JavaScript 的结果 - 这里返回的是字符串
这说明,execute_script() 不只是"执行",它还可以"执行并获取结果"。
3. 执行没有返回值的 JavaScript
python
driver.execute_script("alert('Hello Selenium');")
说明
- 这种方式会直接执行弹窗
- 如果不写
return,Python 端通常得到的是None
三、execute_script() 的参数传递
很多人初学时容易忽略一个关键点:Selenium 执行 JavaScript 时,可以直接把 Python 中的对象传进去。
1. 传入普通参数
python
name = "Selenium"
driver.execute_script("console.log(arguments[0]);", name)
说明
在 JavaScript 中:
arguments[0]对应 Python 传入的第一个参数arguments[1]对应第二个参数- 依此类推
2. 传入 WebElement 元素
这是非常实用的技巧。你可以先通过 Selenium 定位元素,再把元素传给 JavaScript。
python
from selenium.webdriver.common.by import By
element = driver.find_element(By.ID, "submit")
driver.execute_script("arguments[0].style.border='2px solid red';", element)
说明
这段代码会给元素加一个红色边框,常用于调试页面元素是否定位正确。
实战用途
- 高亮元素
- 改变元素样式
- 模拟点击
- 获取元素尺寸、位置
四、JavaScript 的返回值处理
Selenium 中执行 JS 最大的优势之一,就是可以拿到页面内部数据。
1. 返回字符串、数字、布尔值
python
title = driver.execute_script("return document.title;")
print(title)
height = driver.execute_script("return document.body.scrollHeight;")
print(height)
is_loaded = driver.execute_script("return document.readyState === 'complete';")
print(is_loaded)
常见返回值
- 字符串:页面标题、文本内容
- 数字:宽高、滚动距离
- 布尔值:是否加载完成、元素是否存在
2. 返回数组和对象
python
data = driver.execute_script("""
return {
title: document.title,
url: location.href,
height: document.body.scrollHeight
};
""")
print(data)
在 Python 里,通常会变成字典对象。
示例输出
python
{
'title': 'Example Domain',
'url': 'https://www.example.com/',
'height': 780
}
五、掌握滚动条操作的几种方式
滚动条操作是 Selenium 中最常见的 JavaScript 场景之一。很多网页只有滚动后才会加载内容。
1. 滚动到页面底部
python
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
说明
window.scrollTo(x, y)让页面滚动到指定位置document.body.scrollHeight表示整个页面总高度- 常用于懒加载、无限滚动页面
2. 滚动到页面顶部
python
driver.execute_script("window.scrollTo(0, 0);")
使用场景
- 页面回到顶部
- 重新定位起始区域
- 做分页或截图前复位
3. 按固定距离向下滚动
有些页面一次滚到底部并不能触发全部加载,这时更适合分步滚动。
python
driver.execute_script("window.scrollBy(0, 500);")
说明
- 每次向下滚动 500 像素
- 可以配合循环使用,模拟用户逐步下拉
4. 按固定距离向上滚动
python
driver.execute_script("window.scrollBy(0, -300);")
场景
- 回看页面上方内容
- 撤回误滚动
- 触发某些"滚动回调"
5. 滚动到指定元素位置
这是非常常用且非常稳定的方法。很多时候你不是想滚动到某个坐标,而是想让元素出现在视口中。
python
element = driver.find_element(By.ID, "target")
driver.execute_script("arguments[0].scrollIntoView();", element)
说明
scrollIntoView()会让元素滚动到可见区域- 比直接计算坐标更稳定
- 适合点击前置处理
6. 滚动到元素居中位置
默认的 scrollIntoView() 可能把元素顶到页面顶部,不够友好。可以让它居中显示。
python
driver.execute_script("""
arguments[0].scrollIntoView({
behavior: 'smooth',
block: 'center',
inline: 'nearest'
});
""", element)
作用
behavior: 'smooth':平滑滚动block: 'center':元素滚到视口中间- 更适合需要点击的元素
六、处理页面无限滚动和懒加载
很多电商、新闻、社交页面都不是一次性加载全部数据,而是"滚动到底部再加载下一批"。
1. 基本思路
核心思路通常是:
- 记录当前页面高度
- 向下滚动到底部
- 等待数据加载
- 再次获取页面高度
- 如果页面高度没有变化,说明可能加载结束
2. 实战示例:循环下拉直到页面不再变化
python
import time
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://example.com")
last_height = driver.execute_script("return document.body.scrollHeight")
while True:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2)
new_height = driver.execute_script("return document.body.scrollHeight")
if new_height == last_height:
break
last_height = new_height
print("页面已滚动到底部,加载结束")
说明
sleep(2)是为了等待前端加载数据- 通过比较高度判断是否还有新内容
- 适用于评论区、信息流、商品列表等场景
3. 加入元素数量判断
单纯看页面高度并不总是可靠。某些前端高度变化不明显,但元素已经加载了。可以改为统计元素数量。
python
import time
from selenium.webdriver.common.by import By
items = driver.find_elements(By.CSS_SELECTOR, ".item")
last_count = len(items)
while True:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2)
items = driver.find_elements(By.CSS_SELECTOR, ".item")
current_count = len(items)
if current_count == last_count:
break
last_count = current_count
print("数据加载完成,当前数量:", current_count)
优点
- 比页面高度更贴近业务数据
- 适合列表页、卡片页、流式加载页面
七、结合等待机制使用滚动条操作
滚动后页面通常不会立刻加载完成,因此执行 JavaScript 时不能只会滚,还要会等。
1. 显式等待元素出现
python
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".item"))
)
说明
滚动后,等待新元素出现在 DOM 中,再继续操作。
2. 滚动后等待新元素加载
python
import time
from selenium.webdriver.common.by import By
before = len(driver.find_elements(By.CSS_SELECTOR, ".item"))
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2)
after = len(driver.find_elements(By.CSS_SELECTOR, ".item"))
print("滚动前:", before)
print("滚动后:", after)
八、常见问题
1. 为什么 scrollTo 后页面没变化?
可能原因有:
- 页面不是
window级别滚动,而是某个容器滚动 - 页面加载未完成
- 目标页面禁用了滚动
- 需要在 iframe 中操作
解决办法是先确认滚动容器是否正确,再检查是否需要切换到 iframe。
2. 为什么滚动后内容没有加载?
可能原因有:
- 需要触发更慢的滚动行为
- 页面要求鼠标事件或滚动事件被监听
- 加载时间比预期长
- 网站使用了反爬机制
可尝试:
- 增加等待时间
- 分段滚动
- 先滚一点,再继续滚
- 结合显式等待
3. 为什么用 click() 失败,但 JS 点击成功?
因为 JS 点击是直接操作 DOM,不依赖真实鼠标动作。它可以绕过:
- 元素遮挡
- 不可见
- 元素未滚入视口
- 页面浮层
但也要注意,JS 点击有时会绕过前端真实交互流程,不一定完全等同于用户点击。
4. 为什么修改输入框 value 后页面没反应?
因为很多现代前端框架并不是只看 DOM 的 value,还依赖事件机制。解决办法是手动触发 input、change 事件。
python
driver.execute_script("""
arguments[0].value = 'test';
arguments[0].dispatchEvent(new Event('input', { bubbles: true }));
arguments[0].dispatchEvent(new Event('change', { bubbles: true }));
""", element)