🕐 预计用时:3-4 小时 | 🎯 目标:掌握 Selenium 浏览器自动化、元素定位、等待策略和模拟操作
Selenium 是最流行的浏览器自动化工具——用代码控制浏览器做任何人类能做的事情:点击按钮、填写表单、滚动页面、截取屏幕……
# Selenium 能做什么?
# ✅ 自动化测试(Web 应用的功能测试)
# ✅ 网页数据采集(对付 JavaScript 动态渲染页面)
# ✅ 自动化操作(批量注册、自动签到、自动下单)
# ✅ 截图和 PDF 生成
# vs requests + BeautifulSoup:
# requests → 获取静态 HTML(服务器返回什么拿什么)
# Selenium → 控制真实浏览器(能执行 JS、点击按钮、处理登录)
# 类比:
# requests = 看照片(只能看,不能操作)
# Selenium = 远程桌面(能看,能点,能输入,完全操控)# 1. 安装 Selenium
pip install selenium
# 2. 安装浏览器驱动
# 方式1:自动管理(推荐!Selenium 4.6+)
from selenium import webdriver
driver = webdriver.Chrome() # 自动下载匹配的 ChromeDriver
# 方式2:手动安装
# 下载 ChromeDriver: https://chromedriver.chromium.org/
# 放到系统 PATH 中
# 3. 验证安装
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://www.python.org')
print(driver.title) # "Welcome to Python.org"
driver.quit() # 关闭浏览器# 完整的启动配置
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
# Chrome 选项
options = Options()
options.add_argument('--window-size=1920,1080') # 窗口大小
options.add_argument('--disable-gpu') # 禁用 GPU
options.add_argument('--no-sandbox') # Linux 服务器需要
options.add_argument('--disable-dev-shm-usage') # 共享内存限制
# 无头模式(不显示浏览器窗口,后台运行)
# options.add_argument('--headless')
# 启动浏览器
driver = webdriver.Chrome(options=options)
# 常用操作
driver.get('https://www.baidu.com') # 打开网页
print(driver.title) # 获取标题
print(driver.current_url) # 获取当前 URL
print(driver.page_source) # 获取页面 HTML(全部,含 JS 渲染后)
# 关闭
driver.quit() # 关闭浏览器和驱动进程
# driver.close() # 只关闭当前标签页💡 driver.quit() vs driver.close():
• driver.quit():关闭所有标签页 + 退出浏览器 + 结束驱动进程(推荐!)
• driver.close():只关闭当前标签页,浏览器和驱动还在
始终用 driver.quit(),否则浏览器进程会残留在内存中。
from selenium import webdriver
driver = webdriver.Chrome()
# === 页面导航 ===
driver.get('https://www.baidu.com') # 打开 URL
driver.back() # 后退
driver.forward() # 前进
driver.refresh() # 刷新
# === 窗口管理 ===
driver.maximize_window() # 最大化
driver.minimize_window() # 最小化
driver.set_window_size(1024, 768) # 设置大小
driver.set_window_position(0, 0) # 设置位置
# === 标签页管理 ===
# 打开新标签页
driver.execute_script("window.open('https://www.python.org', '_blank');")
# 获取所有标签页句柄
handles = driver.window_handles
print(f'标签页数量: {len(handles)}')
# 切换到第二个标签页
driver.switch_to.window(handles[1])
# 关闭当前标签页
driver.close()
# 切回第一个标签页
driver.switch_to.window(handles[0])
# === JavaScript 执行 ===
driver.execute_script("alert('Hello from Selenium!');")
driver.execute_script("window.scrollTo(0, 1000);") # 滚动到页面中部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") # 滚动到底部
# 返回元素的位置和大小
element = driver.find_element('id', 'myId')
position = driver.execute_script(
"return arguments[0].getBoundingClientRect();", element
)
print(f'位置: x={position["x"]}, y={position["y"]}')
print(f'大小: w={position["width"]}, h={position["height"]}')
# === 截图 ===
driver.save_screenshot('screenshot.png') # 整个页面
element.screenshot('element.png') # 单个元素截图
# === 获取 Cookies ===
cookies = driver.get_cookies()
for cookie in cookies:
print(f'{cookie["name"]}: {cookie["value"]}')
# === 执行异步 JS ===
driver.execute_async_script("""
// 模拟异步操作
setTimeout(function() {
document.title = 'Modified by Selenium';
arguments[arguments.length - 1]('done');
}, 2000);
""")Selenium 提供了 8 种方式来定位页面上的元素。掌握这 8 种,就能找到页面上的任何东西。
from selenium.webdriver.common.by import By
driver.get('https://www.baidu.com')
# === 1. ID 定位(最稳定,优先使用)===
search_box = driver.find_element(By.ID, 'kw')
# === 2. NAME 定位 ===
search_box = driver.find_element(By.NAME, 'wd')
# === 3. CLASS_NAME 定位 ===
search_box = driver.find_element(By.CLASS_NAME, 's_ipt')
# === 4. TAG_NAME 定位 ===
all_inputs = driver.find_elements(By.TAG_NAME, 'input')
# === 5. LINK_TEXT 定位(精确匹配链接文字)===
link = driver.find_element(By.LINK_TEXT, '新闻')
# === 6. PARTIAL_LINK_TEXT(部分匹配链接文字)===
link = driver.find_element(By.PARTIAL_LINK_TEXT, '新')
# === 7. CSS_SELECTOR 定位(最灵活!)===
# 通过 ID
search_box = driver.find_element(By.CSS_SELECTOR, '#kw')
# 通过 class
search_box = driver.find_element(By.CSS_SELECTOR, '.s_ipt')
# 通过属性
search_box = driver.find_element(By.CSS_SELECTOR, 'input[name="wd"]')
# 父子关系
search_box = driver.find_element(By.CSS_SELECTOR, 'form#form input.s_ipt')
# 属性包含
link = driver.find_element(By.CSS_SELECTOR, 'a[href*="news"]')
# === 8. XPATH 定位(最强大!能定位任何元素)===
# 通过属性
search_box = driver.find_element(By.XPATH, '//input[@id="kw"]')
# 通过文本
link = driver.find_element(By.XPATH, '//a[text()="新闻"]')
# 包含某属性值
link = driver.find_element(By.XPATH, '//a[contains(@href, "news")]')
# 父元素
parent = driver.find_element(By.XPATH, '//input[@id="kw"]/..')
# 兄弟元素
next_sibling = driver.find_element(By.XPATH, '//input[@id="kw"]/following-sibling::*')
# 多条件
element = driver.find_element(By.XPATH, '//input[@type="text" and @name="wd"]')By.ID | find_element(By.ID, 'kw') | ||
By.NAME | find_element(By.NAME, 'wd') | ||
By.CLASS_NAME | find_element(By.CLASS_NAME, 'ipt') | ||
By.TAG_NAME | find_element(By.TAG_NAME, 'input') | ||
By.LINK_TEXT | find_element(By.LINK_TEXT, '新闻') | ||
By.PARTIAL_LINK_TEXT | find_element(By.PARTIAL_LINK_TEXT, '新') | ||
By.CSS_SELECTOR | find_element(By.CSS_SELECTOR, '#kw') | ||
By.XPATH | find_element(By.XPATH, '//input[@id="kw"]') |
💡 定位优先级:
1. ID — 最稳定,页面上唯一,不会变
2. CSS Selector — 灵活,速度快,推荐日常使用
3. XPath — 最强大,能定位任何元素,但速度稍慢
4. Name / Class — 简单场景可用
5. Link Text — 专门用于链接find_elements(复数)返回列表,找不到返回空列表;find_element 找不到抛异常。
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
# === 基本操作 ===
element = driver.find_element(By.ID, 'username')
element.send_keys('hello') # 输入文字
element.send_keys(Keys.ENTER) # 按回车
element.send_keys(Keys.TAB) # 按 Tab
element.send_keys(Keys.CONTROL, 'a') # Ctrl+A 全选
element.send_keys(Keys.CONTROL, 'c') # Ctrl+C 复制
element.clear() # 清空输入框
element.click() # 点击
element.submit() # 提交表单(Selenium 4 已弃用,建议用 click() 点击提交按钮)
# === 获取元素信息 ===
element.text # 获取文本内容
element.get_attribute('href') # 获取属性值
element.get_attribute('value') # 获取输入框的值
element.get_attribute('class') # 获取 class
element.is_displayed() # 是否可见
element.is_enabled() # 是否可用
element.is_selected() # 是否选中(checkbox/radio)
element.size # 大小 {'height': 30, 'width': 200}
element.location # 位置 {'x': 100, 'y': 200}
element.tag_name # 标签名
# === 下拉框操作 ===
from selenium.webdriver.support.ui import Select
select = Select(driver.find_element(By.ID, 'city'))
select.select_by_visible_text('北京') # 按文字选择
select.select_by_value('beijing') # 按 value 选择
select.select_by_index(0) # 按索引选择
select.deselect_all() # 取消所有选择(多选框)
# === 鼠标操作(ActionChains)===
actions = ActionChains(driver)
# 悬停
menu = driver.find_element(By.ID, 'menu')
actions.move_to_element(menu).perform()
# 右键
actions.context_click(element).perform()
# 双击
actions.double_click(element).perform()
# 拖拽
source = driver.find_element(By.ID, 'draggable')
target = driver.find_element(By.ID, 'droppable')
actions.drag_and_drop(source, target).perform()
# 悬停 → 点击子菜单
actions.move_to_element(menu).pause(0.5).click(submenu).perform()网页加载需要时间,元素不会立即出现。等待是 Selenium 最重要的概念之一。
# ❌ 错误做法:用 sleep 等待(慢且不可靠)
import time
time.sleep(5) # 等 5 秒,不管元素出没出现
# ✅ 正确做法:显式等待(等到元素出现为止)
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# === 显式等待(推荐!)===
# 最多等 10 秒,每 0.5 秒检查一次,直到条件满足
wait = WebDriverWait(driver, 10, poll_frequency=0.5)
# 等待元素出现
element = wait.until(EC.presence_of_element_located((By.ID, 'kw')))
# 等待元素可点击
button = wait.until(EC.element_to_be_clickable((By.ID, 'su')))
# 等待元素可见
element = wait.until(EC.visibility_of_element_located((By.CLASS_NAME, 'result')))
# 等待元素消失(如加载动画消失)
wait.until(EC.invisibility_of_element_located((By.CLASS_NAME, 'loading')))
# 等待标题包含某文字
wait.until(EC.title_contains('百度'))
# 等待 URL 包含某文字
wait.until(EC.url_contains('search'))
# 等待 alert 出现
alert = wait.until(EC.alert_is_present())
alert.accept()
# === 隐式等待(全局设置,不推荐单独使用)===
driver.implicitly_wait(10) # 所有 find_element 最多等 10 秒presence_of_element_located | |
visibility_of_element_located | |
element_to_be_clickable | |
text_to_be_present_in_element | |
invisibility_of_element_located | |
frame_to_be_available_and_switch_to_it | |
alert_is_present | |
number_of_windows_to_be |
⚠️ 等待策略总结:
❌ sleep(5):永远不要用!慢且不可靠
⚠️ implicitly_wait(10):全局隐式等待,对某些条件无效
✅ WebDriverWait + expected_conditions:精确等待,条件满足立即继续
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
def baidu_search(keyword):
"""自动百度搜索"""
driver = webdriver.Chrome()
driver.maximize_window()
try:
# 1. 打开百度
driver.get('https://www.baidu.com')
print(f'✅ 打开百度: {driver.title}')
# 2. 等待搜索框出现
wait = WebDriverWait(driver, 10)
search_box = wait.until(
EC.presence_of_element_located((By.ID, 'kw'))
)
# 3. 输入关键词
search_box.clear()
search_box.send_keys(keyword)
print(f'✅ 输入关键词: {keyword}')
# 4. 点击搜索按钮
search_btn = driver.find_element(By.ID, 'su')
search_btn.click()
print('✅ 点击搜索')
# 5. 等待搜索结果出现
wait.until(
EC.presence_of_element_located((By.CLASS_NAME, 'result'))
)
print('✅ 搜索结果已加载')
# 6. 截图保存
driver.save_screenshot('search_result.png')
print('✅ 截图已保存')
# 7. 获取搜索结果
results = driver.find_elements(By.CSS_SELECTOR, '.result h3 a')
print(f'\n📋 搜索结果(前5条):')
for i, result in enumerate(results[:5]):
print(f' {i+1}. {result.text}')
print(f' {result.get_attribute("href")}')
return results
except Exception as e:
print(f'❌ 出错了: {e}')
driver.save_screenshot('error.png')
finally:
driver.quit()
print('✅ 浏览器已关闭')
# 执行搜索
baidu_search('Python 教程')# === 处理 alert 弹窗 ===
driver.get('https://example.com')
# 触发 alert(例如点击某个按钮)
driver.find_element(By.ID, 'alertBtn').click()
# 等待并切换到 alert
wait = WebDriverWait(driver, 10)
alert = wait.until(EC.alert_is_present())
# 获取 alert 文字
print(f'Alert 内容: {alert.text}')
# 操作
alert.accept() # 点击"确定"
# alert.dismiss() # 点击"取消"
# alert.send_keys('输入内容') # 如果是 prompt
# === 处理 iframe ===
# iframe 是页面中嵌套的另一个页面,需要先切换才能操作内部元素
# 方式1:通过 iframe 的 name 或 id 切换
driver.switch_to.frame('iframe_name')
# 方式2:通过元素切换
iframe = driver.find_element(By.ID, 'myFrame')
driver.switch_to.frame(iframe)
# 方式3:通过索引切换(0 = 第一个 iframe)
driver.switch_to.frame(0)
# 操作 iframe 内的元素
driver.find_element(By.ID, 'innerElement').click()
# 切回主页面(必须!)
driver.switch_to.default_content()
# === 处理新窗口/标签页 ===
# 点击某个链接打开了新窗口
driver.find_element(By.LINK_TEXT, '新窗口链接').click()
# 获取所有窗口句柄
handles = driver.window_handles
# 切换到新窗口(最后一个)
driver.switch_to.window(handles[-1])
print(f'新窗口标题: {driver.title}')
# 操作新窗口...
# 切回原窗口
driver.switch_to.window(handles[0])
# === 处理文件上传 ===
# 找到 file input 元素
file_input = driver.find_element(By.CSS_SELECTOR, 'input[type="file"]')
# 直接发送文件路径(不需要点击弹窗!)
file_input.send_keys('/path/to/file.jpg')
# === 处理下拉框(select)===
from selenium.webdriver.support.ui import Select
select_element = Select(driver.find_element(By.ID, 'country'))
select_element.select_by_visible_text('中国') # 按文字
select_element.select_by_value('CN') # 按 value
select_element.select_by_index(0) # 按索引# 用 Selenium 打开 Python 官网 (python.org)
# 获取:页面标题、当前 URL、页面源码长度
# 截图保存为 python_org.png
# 然后关闭浏览器# 创建一个简单的 HTML 表单页面
# 用 Selenium 自动填写所有字段:
# - 文本输入(姓名、邮箱)
# - 下拉选择(城市)
# - 单选按钮(性别)
# - 复选框(爱好)
# - 提交表单# 自动搜索"Python selenium"
# 提取前 10 条搜索结果的标题和链接
# 保存为 CSV 文件🚀 明日预告:Day 80 — Selenium 进阶
无头模式、反检测技巧、数据采集实战——用 Selenium 绕过反爬,从动态页面批量采集数据。