杰瑞科技汇

Python Selenium如何执行JS?

Of course! This is a very common and powerful combination in web automation. Let's break down how to use Python with Selenium to execute JavaScript, covering the main use cases and providing clear examples.

Python Selenium如何执行JS?-图1
(图片来源网络,侵删)

The Core Concept: Why Execute JavaScript with Selenium?

Selenium's primary goal is to simulate user interactions (clicking, typing, navigating). However, sometimes you need to do things that are difficult or impossible through the standard Selenium API. This is where JavaScript execution comes in.

Common reasons to use JavaScript (execute_script) in Selenium:

  1. Bypassing Complex UI: Directly clicking an element that's hidden behind a modal, menu, or complex CSS selector.
  2. Performing Actions Not Natively Supported: Scrolling a page, changing element styles, or dragging and dropping.
  3. Getting Data from the Page: Extracting information from JavaScript variables or complex data structures on the page.
  4. Waiting for Asynchronous Operations: Waiting for a specific JavaScript variable to be set or a function to complete, which is more reliable than a simple time.sleep().
  5. Modifying the Page State: Changing an element's attribute (e.g., making a disabled field enabled) or adding/removing CSS classes.

The Key Method: execute_script()

Selenium's WebDriver provides the primary method for this: driver.execute_script(script, *args).

  • script: A string containing the JavaScript code you want to run.
  • *`args`**: (Optional) Any number of arguments you want to pass from your Python script into the JavaScript code.

Synchronous vs. Asynchronous

By default, execute_script runs synchronously. This means your Python script will wait for the JavaScript code to finish executing before it continues. This is perfect for 95% of use cases.

Python Selenium如何执行JS?-图2
(图片来源网络,侵删)

There is also execute_async_script, which runs asynchronously. This is used when your JavaScript code contains operations that take time, like fetch(), setTimeout, or Promise. Your Python script will send the async script and then immediately continue. You need a special mechanism in the JS code to signal back to Python when it's done (usually by calling a callback function that Selenium provides).


Practical Examples

Let's set up a simple environment and dive into examples.

Setup

First, make sure you have the necessary libraries installed:

pip install selenium

You'll also need a WebDriver for your browser (e.g., ChromeDriver for Google Chrome). The easiest way to manage this is with selenium-manager, which is built into Selenium 4.6+.

Python Selenium如何执行JS?-图3
(图片来源网络,侵删)

Example 1: Getting and Setting Page Title

This is the simplest example. We'll get the page title using JS and then change it.

from selenium import webdriver
from selenium.webdriver.common.by import By
# Start a browser session
driver = webdriver.Chrome()
driver.get("https://www.google.com")
# --- 1. GETTING DATA USING JS ---
# Get the page title using JavaScriptjs = "return document.title;"
current_title = driver.execute_script(title_js)
print(f"The page title is: {current_title}")
# --- 2. MODIFYING THE PAGE USING JS ---
# Change the page title using JavaScriptjs = "document.title = 'My New Title!';"
driver.execute_script(new_title_js)
print(f"The page title has been changed to: {driver.title}")
driver.quit()

Example 2: Interacting with Elements (Scrolling into View)

A very common use case is scrolling an element into the user's viewport before interacting with it.

from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://en.wikipedia.org/wiki/Python_(programming_language)")
# Find an element that is not initially in view
# Let's find the "References" section, which is at the bottom
element = driver.find_element(By.ID, "References")
# Scroll the element into view using JavaScript
# 'arguments[0]' refers to the first argument we pass, which is the 'element'
driver.execute_script("arguments[0].scrollIntoView(true);", element)
print("Scrolled to the References section.")
# You can now safely interact with it, e.g., click a link inside it
driver.quit()

Example 3: Modifying Element Attributes

Imagine a form field is disabled (disabled="disabled"), and you want to enable it to type in it.

from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://www.w3schools.com/html/html_form_attributes.asp")
# Find a disabled input element
disabled_input = driver.find_element(By.XPATH, "//input[@disabled]")
print(f"Is input disabled? {disabled_input.get_attribute('disabled')}") # Should be 'true'
# Use JavaScript to remove the 'disabled' attribute
driver.execute_script("arguments[0].removeAttribute('disabled');", disabled_input)
print(f"Is input disabled after JS? {disabled_input.get_attribute('disabled')}") # Should be None
# Now Selenium can interact with it
disabled_input.send_keys("This text was added by Selenium!")
driver.quit()

Example 4: Passing Arguments from Python to JavaScript

You can pass variables from Python directly into your JavaScript script. This makes your code much more dynamic.

from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://www.example.com")
# Define arguments in Python
my_arg1 = "Hello from Python!"
my_arg2 = 123
# The JavaScript script will receive these arguments
# The order matters: arguments[0] is my_arg1, arguments[1] is my_arg2
js_script = """
    var message = arguments[0];
    var number = arguments[1];
    console.log('Message received in JS: ' + message);
    console.log('Number received in JS: ' + number);
    return 'JS received: ' + message + ' and ' + number;
"""
# Execute the script and pass the arguments
result = driver.execute_script(js_script, my_arg1, my_arg2)
print(f"Result returned from JS: {result}")
driver.quit()

Example 5: Using execute_async_script for Waiting

This is a more advanced but very powerful technique. Let's say we want to wait for a specific element to appear, but its appearance is triggered by an asynchronous JavaScript function on the page.

from selenium import webdriver
from selenium.webdriver.common.by import By
import time
driver = webdriver.Chrome()
driver.get("https://google.com")
# This script will wait until an element with ID 'myDynamicElement' exists.
# The 'window.scrollTo' is just to make the page a bit more interesting.
# The 'callback' is the special argument from Selenium that we call when done.
async_script = """
    // Poll for the element's existence
    const checkInterval = setInterval(() => {
        const element = document.getElementById('myDynamicElement');
        if (element) {
            clearInterval(checkInterval);
            // Signal to Selenium that we are done
            // The first argument to the callback is the error (null for success)
            // The second argument is the return value
            arguments[0](null, 'Element found!');
        }
    }, 500); // Check every 500ms
"""
# First, let's add a dynamic element to the page after a delay
# This simulates a real-world async operation
driver.execute_script("""
    setTimeout(() => {
        const elem = document.createElement('div');
        elem.id = 'myDynamicElement';
        elem.textContent = 'I am a dynamically added element!';
        document.body.appendChild(elem);
    }, 2000);
""")
print("Waiting for the dynamic element to appear...")
# Now, use execute_async_script to wait for it
# We pass a lambda function as the callback to handle the result
try:
    result = driver.execute_async_script(async_script)
    print(f"Async script finished. Result: {result}")
    # Now we can safely find the element
    dynamic_element = driver.find_element(By.ID, 'myDynamicElement')
    print(f"Found element text: {dynamic_element.text}")
except Exception as e:
    print(f"An error occurred: {e}")
driver.quit()

Best Practices

  1. Use Sparingly: If Selenium can do it (e.g., element.click(), element.send_keys()), prefer the Selenium API. It's more readable, maintainable, and less brittle than JavaScript.
  2. Be Specific: Your JavaScript should be as specific as possible. Avoid generic scripts like document.querySelector('input').click() if you can use driver.find_element(By.CSS_SELECTOR, 'input').click().
  3. Handle Return Values: JavaScript execution can return values to Python. Use this to get data from the page instead of parsing the page source with Python string methods.
  4. Error Handling: JavaScript errors in execute_script will raise a JavascriptException in Python. Wrap your calls in try...except blocks if the script might fail.
  5. Readability: For complex scripts, store the JavaScript code in a multi-line string variable or even in an external .js file to keep your Python code clean.
分享:
扫描分享到社交APP
上一篇
下一篇