You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Selenium批量send_keys循环逐轮变慢原因及优化方案

问题背景

使用Selenium WebDriver开展网页爬取工作时,需要向网站指定输入字段提交总计19000条固定格式的登记编号,以下载对应信息的.csv文件。测试阶段编写的批量提交代码如下:

df = pd.read_csv('arMestre.csv')

x = 0
y = 200
i = 0

while i < 5:
        t1 = time.time()
        element.send_keys(df[x:y].to_string(header=False, index=False) + "\n")
        i += 1
        x = y+1
        y += 200
        t2 = time.time()
        print(t2-t1)

测试得到5轮循环(每轮提交200条数据)的执行耗时逐轮上升:

7.61 - first loop
13.44 - second loop 
23.53 - third loop 
28.70 - fourth loop
35.12 - fifith loop

待查询的登记编号为14位数字格式,样例如下:

93040132242591
93040132254075
93040132277390
93040132314829
93040132426137
93040132838473
93040134252423
93040134211776

循环速度逐轮下降的根本原因

核心问题出在输入框内容累计和send_keys的实现逻辑上,具体有三点:

  • 每次调用send_keys()都是在输入框已有内容的基础上追加文本,从未清空输入框。第一轮提交时输入框为空,仅需处理200条文本;第二轮提交时输入框已存200条内容,追加后总长度达到400条;到第五轮时输入框累计已有1000条文本。浏览器渲染输入框内容、响应输入事件的开销随文本总长度线性上涨,直接导致耗时逐轮增加。
  • send_keys()的底层逻辑是模拟真人逐字符敲击键盘输入,每输入一个字符都会触发输入框绑定的所有前端事件(比如格式校验、输入联想、内容统计等),输入框内已有内容越长,这类事件的计算开销越高。
  • 原代码的切片逻辑x = y+1存在bug,会导致每一批次的第一条数据被跳过(比如第一批取0-199,第二批x从201开始,会漏掉索引为200的编号)。

更高效的实现方案

按执行效率从高到低排序,可根据网站的校验强度选择:

方案1:通过JavaScript直接赋值输入框(效率最高)

send_keys的逐字符模拟逻辑是最大的性能瓶颈,可以直接通过Selenium调用JS接口修改输入框的DOM值,跳过逐字符输入、逐次触发事件的开销,提交速度是原生send_keys的几十到上百倍。
实现代码参考:

import pandas as pd
import time
from selenium.webdriver.common.by import By

# 读取数据时直接把登记编号列转为字符串,避免长数字被转成科学计数法
df = pd.read_csv('arMestre.csv', dtype={0: str})
all_codes = df.iloc[:, 0].str.strip().tolist()
# 批次大小可根据网站承载能力调整,无严格限制时可设为500-1000
batch_size = 500
# 替换成实际的输入框定位逻辑
input_element = driver.find_element(By.CSS_SELECTOR, "输入框对应的CSS选择器")

for batch_idx in range(0, len(all_codes), batch_size):
    start = time.time()
    # 取当前批次数据,用换行拼接
    current_batch = all_codes[batch_idx : batch_idx + batch_size]
    batch_content = "\n".join(current_batch)
    # JS直接清空、赋值输入框,并手动触发事件通知网站内容更新
    driver.execute_script(
        """
        const inputDom = arguments[0];
        inputDom.value = arguments[1];
        // 触发标准输入、变更事件,兼容大部分网站的前端校验逻辑
        inputDom.dispatchEvent(new Event('input', {bubbles: true}));
        inputDom.dispatchEvent(new Event('change', {bubbles: true}));
        """,
        input_element,
        batch_content
    )
    # 此处补充提交查询、等待CSV下载完成的逻辑
    cost = time.time() - start
    print(f"第{batch_idx//batch_size + 1}批提交耗时:{cost:.2f}s")

如果JS赋值后网站识别不到输入内容(部分做了严格反爬的网站会监听真实键盘事件),再用下面的兼容方案。

方案2:保留send_keys逻辑,每次提交前清空输入框(兼容性最好)

只需要在每轮提交前调用clear()方法清空输入框的历史内容,就能避免文本累计带来的开销,每轮提交耗时会稳定在和第一轮接近的水平,同时修正原代码的切片bug。
实现代码参考:

import pandas as pd
import time
from selenium.webdriver.common.by import By

df = pd.read_csv('arMestre.csv', dtype={0: str})
all_codes = df.iloc[:, 0].str.strip().tolist()
batch_size = 200
input_element = driver.find_element(By.CSS_SELECTOR, "输入框对应的CSS选择器")

for batch_idx in range(0, len(all_codes), batch_size):
    start = time.time()
    current_batch = all_codes[batch_idx : batch_idx + batch_size]
    batch_content = "\n".join(current_batch) + "\n"
    # 关键:提交前先清空输入框历史内容
    input_element.clear()
    input_element.send_keys(batch_content)
    # 此处补充提交查询、等待下载的逻辑
    cost = time.time() - start
    print(f"第{batch_idx//batch_size + 1}批提交耗时:{cost:.2f}s")

额外提效建议

  • 不要用df.to_string()生成批次文本,这个方法会自动做对齐补空格,既拖慢速度,还可能导致提交的编号带多余空格格式错误,直接转成字符串列表用换行拼接效率最高。
  • 读取CSV时一定要把登记编号列指定为字符串类型,否则14位的长数字会被pandas自动转为科学计数法,导致提交的编号完全错误。
  • 如果网站没有严格的浏览器环境校验,可以抓包获取查询接口的地址、参数规则,直接用requests库批量发请求提交数据,速度会比Selenium方案快几个数量级。

内容的提问来源于stack exchange,提问作者Vawkay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 13:06:31