【Selenium 执行 JavaScript】

文章目录

  • [一、为什么 Selenium 需要执行 JavaScript](#一、为什么 Selenium 需要执行 JavaScript)
  • [二、Selenium 中执行 JavaScript](#二、Selenium 中执行 JavaScript)
    • [1. 基本语法](#1. 基本语法)
    • [2. 示例](#2. 示例)
    • [3. 执行没有返回值的 JavaScript](#3. 执行没有返回值的 JavaScript)
  • [三、execute_script() 的参数传递](#三、execute_script() 的参数传递)
    • [1. 传入普通参数](#1. 传入普通参数)
    • [2. 传入 WebElement 元素](#2. 传入 WebElement 元素)
  • [四、JavaScript 的返回值处理](#四、JavaScript 的返回值处理)
    • [1. 返回字符串、数字、布尔值](#1. 返回字符串、数字、布尔值)
    • [2. 返回数组和对象](#2. 返回数组和对象)
  • 五、掌握滚动条操作的几种方式
    • [1. 滚动到页面底部](#1. 滚动到页面底部)
    • [2. 滚动到页面顶部](#2. 滚动到页面顶部)
    • [3. 按固定距离向下滚动](#3. 按固定距离向下滚动)
    • [4. 按固定距离向上滚动](#4. 按固定距离向上滚动)
    • [5. 滚动到指定元素位置](#5. 滚动到指定元素位置)
    • [6. 滚动到元素居中位置](#6. 滚动到元素居中位置)
  • 六、处理页面无限滚动和懒加载
    • [1. 基本思路](#1. 基本思路)
    • [2. 实战示例:循环下拉直到页面不再变化](#2. 实战示例:循环下拉直到页面不再变化)
    • [3. 加入元素数量判断](#3. 加入元素数量判断)
  • 七、结合等待机制使用滚动条操作
    • [1. 显式等待元素出现](#1. 显式等待元素出现)
    • [2. 滚动后等待新元素加载](#2. 滚动后等待新元素加载)
  • 八、常见问题
    • [1. 为什么 `scrollTo` 后页面没变化?](#1. 为什么 scrollTo 后页面没变化?)
    • [2. 为什么滚动后内容没有加载?](#2. 为什么滚动后内容没有加载?)
    • [3. 为什么用 `click()` 失败,但 JS 点击成功?](#3. 为什么用 click() 失败,但 JS 点击成功?)
    • [4. 为什么修改输入框 value 后页面没反应?](#4. 为什么修改输入框 value 后页面没反应?)

一、为什么 Selenium 需要执行 JavaScript

Selenium 的核心思想是模拟用户行为,但真实浏览器中的很多功能,浏览器本身是通过 JavaScript 驱动的。页面中常见的这些情况,往往需要 JavaScript 配合:

  1. 触发一些 Selenium 直接不好操作的前端行为。
  2. 修改页面内容,例如隐藏、显示、删除 DOM。
  3. 获取页面中动态生成的数据。
  4. 处理滚动条、懒加载、无限下拉加载。
  5. 绕过某些无法直接点击的遮挡元素。
  6. 获取页面里更精细的状态,例如 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. 基本思路

核心思路通常是:

  1. 记录当前页面高度
  2. 向下滚动到底部
  3. 等待数据加载
  4. 再次获取页面高度
  5. 如果页面高度没有变化,说明可能加载结束

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,还依赖事件机制。解决办法是手动触发 inputchange 事件。

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)
相关推荐
一锤捌拾5 小时前
V8引擎精品漫游指南--Ignition篇(下 一) 动态执行前的事情
前端·javascript
Elastic 中国社区官方博客6 小时前
用于 JavaScript 和 TypeScript 的 ES|QL 查询构建器:流式、类型安全的查询构建
大数据·javascript·数据库·elasticsearch·搜索引擎·typescript·全文检索
蜡台7 小时前
使用 html javascript 实现 金币落袋效果
前端·javascript·html
李白的天不白7 小时前
VUE依赖配置问题
前端·javascript·vue.js
llilian_167 小时前
晶体频率测试仪 破解晶振品控核心难题:晶体频率网络测试仪深度解析 晶体网络分析仪
网络·功能测试·单片机·嵌入式硬件·测试工具·51单片机
深念Y7 小时前
从 Playwright/Selenium 到指纹浏览器:浏览器自动化技术的进阶之路
selenium·测试工具·自动化·浏览器·账号·无头浏览器·指纹浏览器
ZC跨境爬虫7 小时前
跟着 MDN 学 HTML day_7:(进阶文本语义标签全覆盖)
前端·javascript·css·ui·html
冰暮流星7 小时前
javascript之事件冒泡与事件捕获
开发语言·前端·javascript
小智社群8 小时前
获取贝壳新房列表
前端·javascript·vue.js