author: 专注Python实战,分享爬虫与数据分析干货
title: Python爬虫实战⑧|Selenium模拟浏览器,JS渲染页面一把抓
update: 2026-04-26
tags: Python,爬虫,Selenium,浏览器自动化,JS渲染,动态页面,WebDriver

作者:专注Python实战,分享爬虫与数据分析干货
更新时间:2026年4月
适合人群:遇到JS渲染页面无法抓取、需要模拟浏览器操作的爬虫开发者


前言:有些页面,requests永远抓不到

有些网站,无论你怎么找API接口,数据就是拿不到——

  • 网站用JS动态渲染,HTML源码是空的
  • 需要先点击按钮、滚动页面才加载内容
  • 有复杂的登录验证码
  • 数据藏在iframe里

Selenium = 真实浏览器自动化。 它打开一个真实浏览器,像人一样操作,JS渲染的内容全部能拿到。


一、Selenium安装与配置

1.1 安装Selenium

pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple

Selenium 4.6+ 自带驱动管理器,无需手动下载驱动。但Chrome浏览器需要安装好。

1.2 第一个Selenium程序

from selenium import webdriver

# 打开Chrome浏览器
driver = webdriver.Chrome()

# 访问网页
driver.get("https://www.baidu.com")

# 获取页面标题
print("页面标题:", driver.title)

# 关闭浏览器
driver.quit()

1.3 常用配置选项

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()

# 无头模式(不显示浏览器窗口,速度快,省资源)
options.add_argument("--headless")

# 禁用图片加载(加速)
options.add_argument("--disable-images")

# 设置窗口大小
options.add_argument("--window-size=1920,1080")

# 禁用GPU加速(避免无头模式下的报错)
options.add_argument("--disable-gpu")

# 禁用图片/CSS/JS(进一步加速)
prefs = {
    "profile.managed_default_content_settings.images": 2,
    "profile.managed_default_content_settings.stylesheets": 2,
}
options.add_experimental_option("prefs", prefs)

# 启动带配置的浏览器
driver = webdriver.Chrome(options=options)
driver.get("https://example.com")
driver.quit()

二、元素定位(8种方式)

Selenium用不同方式定位页面元素:

2.1 八种定位方法

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://www.baidu.com")

# 1. ID定位(最快,推荐)
driver.find_element(By.ID, "kw")

# 2. Name定位
driver.find_element(By.NAME, "wd")

# 3. Class Name定位
driver.find_element(By.CLASS_NAME, "s_ipt")

# 4. Tag Name定位
driver.find_element(By.TAG_NAME, "input")

# 5. XPath定位(最强大)
driver.find_element(By.XPATH, "//input[@id='kw']")

# 6. CSS Selector定位
driver.find_element(By.CSS_SELECTOR, "#kw")

# 7. Link Text定位(链接文本)
driver.find_element(By.LINK_TEXT, "新闻")

# 8. Partial Link Text定位
driver.find_element(By.PARTIAL_LINK_TEXT, "新")

# 找多个元素(返回列表)
inputs = driver.find_elements(By.TAG_NAME, "input")
print(f"共找到 {len(inputs)} 个input标签")

2.2 XPath定位实战

# 文本包含
driver.find_element(By.XPATH, "//a[contains(text(),'登录')]")

# 属性匹配
driver.find_element(By.XPATH, "//button[@type='submit']")

# 组合条件
driver.find_element(By.XPATH, "//div[@class='card' and @id='main']")

# 按层级定位
driver.find_element(By.XPATH, "//form[@id='login']//button[@type='submit']")

# 模糊class
driver.find_element(By.XPATH, "//div[contains(@class, 'product')]")

三、元素操作

3.1 输入文本与点击

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome()
driver.get("https://www.baidu.com")

# 找到搜索框
search_box = driver.find_element(By.ID, "kw")

# 输入文本
search_box.send_keys("Python爬虫")

# 清空并重新输入
search_box.clear()
search_box.send_keys("Selenium教程")

# 按回车键
search_box.send_keys(Keys.RETURN)

# 找到搜索按钮并点击
search_btn = driver.find_element(By.ID, "su")
search_btn.click()

# 等待页面加载
import time
time.sleep(2)

# 获取当前URL
print("当前URL:", driver.current_url)

driver.quit()

3.2 下拉框处理

from selenium.webdriver.support.ui import Select

# 定位下拉框
select = Select(driver.find_element(By.TAG_NAME, "select"))

# 选择选项(三种方式)
select.select_by_value("option_value")   # 按value属性
select.select_by_index(2)                # 按索引(从0开始)
select.select_by_visible_text("显示文本")  # 按显示文字

# 获取所有选项
for option in select.options:
    print(option.text)

3.3 复选框和单选框

# 勾选复选框
checkbox = driver.find_element(By.ID, "agree")
if not checkbox.is_selected():
    checkbox.click()

# 检查是否选中
print("是否选中:", checkbox.is_selected())

# 勾选单选框
radio = driver.find_element(By.XPATH, "//input[@name='gender' and @value='female']")
radio.click()

四、等待机制(最重要)

Selenium最大的坑:页面还没加载完就去找元素,找不到就报错。 解决方案是等待。

4.1 强制等待(简单但低效)

import time
time.sleep(3)  # 强制等3秒

4.2 显式等待(推荐)

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

# 等待某个元素出现(最多等10秒,每0.5秒检查一次)
element = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "kw"))
)
print("元素出现了:", element)

# 等待元素可点击
btn = WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.ID, "su"))
)
btn.click()

# 等待URL包含特定字符
WebDriverWait(driver, 10).until(
    EC.url_contains("baidu.com")
)

# 等待元素文本包含特定内容
WebDriverWait(driver, 10).until(
    EC.text_to_be_present_in_element((By.ID, "result"), "Python")
)

4.3 常用等待条件

# 元素出现在DOM中
EC.presence_of_element_located((By.ID, "element_id"))

# 元素可见(能看见且有大小)
EC.visibility_of_element_located((By.ID, "element_id"))

# 元素可点击
EC.element_to_be_clickable((By.ID, "element_id"))

# 元素文本包含特定内容
EC.text_to_be_present_in_element((By.ID, "element_id"), "文本内容")

# URL包含特定字符
EC.url_contains("keyword")

# 页面标题包含特定字符
EC.title_contains("标题")

# alert出现
EC.alert_is_present()

# 等待多个元素
elements = WebDriverWait(driver, 10).until(
    EC.presence_of_all_elements_located((By.CLASS_NAME, "item"))
)

五、执行JavaScript

Selenium可以执行任意JS代码:

# 滚动到页面底部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

# 滚动到指定元素位置
element = driver.find_element(By.ID, "comments")
driver.execute_script("arguments[0].scrollIntoView();", element)

# 获取页面高度
height = driver.execute_script("return document.body.scrollHeight;")
print("页面高度:", height)

# 点击隐藏的元素(用JS强制点击)
element = driver.find_element(By.XPATH, "//button[@id='hidden_btn']")
driver.execute_script("arguments[0].click();", element)

# 获取动态页面完整HTML(包含JS渲染后的内容)
html = driver.execute_script("return document.documentElement.outerHTML;")
print(html[:500])

# 设置输入框值(绕过readonly限制)
driver.execute_script("document.getElementById('date').value='2026-01-01';")

六、页面操作进阶

6.1 窗口和iframe切换

# 获取当前窗口句柄
current_window = driver.current_window_handle
print("当前窗口:", current_window)

# 打开新窗口
driver.execute_script("window.open('https://www.baidu.com');")

# 切换到新窗口
windows = driver.window_handles
driver.switch_to.window(windows[-1])  # 切换到最新窗口
print("新窗口:", driver.title)

# 切换回原窗口
driver.switch_to.window(current_window)

# 操作iframe
# 方法1:按ID或name切换
driver.switch_to.frame("iframe_id")

# 方法2:按索引切换
driver.switch_to.frame(0)

# 方法3:切回主文档
driver.switch_to.default_content()

# 操作alert/弹窗
alert = driver.switch_to.alert
print("弹窗文本:", alert.text)
alert.accept()        # 点击确定
# alert.dismiss()     # 点击取消

6.2 键盘和鼠标操作

from selenium.webdriver.common.action_chains import ActionChains

# 鼠标悬停
element = driver.find_element(By.ID, "dropdown")
ActionChains(driver).move_to_element(element).perform()

# 右键点击
ActionChains(driver).context_click(element).perform()

# 双击
ActionChains(driver).double_click(element).perform()

# 拖拽
source = driver.find_element(By.ID, "draggable")
target = driver.find_element(By.ID, "droppable")
ActionChains(driver).drag_and_drop(source, target).perform()

# 组合键
ActionChains(driver).key_down(Keys.CONTROL).send_keys("a").key_up(Keys.CONTROL).perform()

七、实战:Selenium版豆瓣Top250爬虫

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
import csv

# 配置无头浏览器
options = Options()
options.add_argument("--headless")
options.add_argument("--disable-gpu")
options.add_argument("--window-size=1920,1080")

driver = webdriver.Chrome(options=options)

all_movies = []

try:
    for page in range(2):  # 演示2页
        start = page * 25
        url = f"https://movie.douban.com/top250?start={start}"
        print(f"第{page+1}页: 加载中...", end=" ")

        driver.get(url)

        # 等待页面加载完成(至少看到电影列表)
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CLASS_NAME, "item"))
        )

        # 等待页面完全加载
        time.sleep(1)

        # 提取电影数据
        items = driver.find_elements(By.CLASS_NAME, "item")
        print(f"找到 {len(items)} 部电影")

        for item in items:
            try:
                rank = item.find_element(By.CLASS_NAME, "pic").find_element(By.TAG_NAME, "em").text
                title = item.find_element(By.CLASS_NAME, "title").text
                rating = item.find_element(By.CLASS_NAME, "rating_num").text

                try:
                    quote = item.find_element(By.CLASS_NAME, "inq").text
                except:
                    quote = ""

                all_movies.append([rank, title, rating, quote])
            except Exception as e:
                print(f"  解析出错: {e}")

        # 礼貌延迟
        time.sleep(2)

except Exception as e:
    print(f"爬虫出错: {e}")

finally:
    driver.quit()

# 保存数据
with open("豆瓣Top250_Selenium版.csv", "w", newline="", encoding="utf-8-sig") as f:
    writer = csv.writer(f)
    writer.writerow(["排名", "电影", "评分", "短评"])
    writer.writerows(all_movies)

print(f"\n共 {len(all_movies)} 部电影,已保存")
for m in all_movies[:5]:
    print(f"  {m[0]:>3}. {m[1]:<15} {m[2]}  {m[3]}")

八、知识卡

方法 说明
webdriver.Chrome(options=) 启动Chrome
driver.get(url) 打开网页
driver.quit() 关闭浏览器
By.ID / By.NAME / By.XPATH 元素定位方式
element.send_keys(text) 输入文本
element.click() 点击元素
WebDriverWait(driver, 10) 显式等待(最安全)
EC.presence_of_element_located() 等待元素出现
EC.element_to_be_clickable() 等待元素可点击
driver.execute_script(js) 执行JavaScript
driver.switch_to.frame() 切换iframe
driver.switch_to.window() 切换窗口
ActionChains 鼠标键盘操作链
element.text 获取元素文本
element.get_attribute(“href”) 获取元素属性

九、课后作业

必做题:

  1. 安装Selenium,编写第一个自动打开百度并搜索关键词的程序
  2. 用Selenium实现豆瓣Top250前2页的爬取
  3. 练习显式等待的3种条件

选做题:

  1. 用Selenium模拟登录任意网站
  2. 用execute_script实现无限滚动加载的页面抓取

完成作业的同学,把运行截图发到评论区!


Selenium = 爬虫的终极武器。 无论什么JS渲染、什么动态页面,只要浏览器能打开,Selenium就能抓到。

但Selenium速度慢、资源消耗大。能用requests解决的,优先用requests。Selenium是最后的保底手段。

本篇要点:

  • Selenium安装与配置
  • 8种元素定位方式
  • 输入/点击/下拉框操作
  • 显式等待(最重要)
  • JavaScript执行
  • 窗口和iframe切换
  • 实战:Selenium豆瓣爬虫

下一篇学习Cookie与登录态——搞定需要登录才能访问的页面。

收藏 + 关注,专栏更新不迷路!

有问题欢迎评论区留言,大家一起讨论!


标签:Python | Selenium | 浏览器自动化 | JS渲染 | 动态页面 | WebDriver | 反爬虫

更多推荐