目录
-
- 课程目标
- [1. Selenium简介](#1. Selenium简介)
-
- [1.1 为什么需要Selenium?](#1.1 为什么需要Selenium?)
- [1.2 安装Selenium](#1.2 安装Selenium)
- [1.3 基本使用](#1.3 基本使用)
- [2. 浏览器驱动配置](#2. 浏览器驱动配置)
-
- [2.1 Chrome驱动配置](#2.1 Chrome驱动配置)
- [2.2 Firefox驱动配置](#2.2 Firefox驱动配置)
- [3. 元素定位方法](#3. 元素定位方法)
-
- [3.1 基本定位方法](#3.1 基本定位方法)
- [3.2 查找多个元素](#3.2 查找多个元素)
- [3.3 等待元素出现](#3.3 等待元素出现)
- [4. 用户行为模拟](#4. 用户行为模拟)
-
- [4.1 基本操作](#4.1 基本操作)
- [4.2 高级操作](#4.2 高级操作)
- [4.3 处理弹窗和框架](#4.3 处理弹窗和框架)
- [5. 实战案例:爬取动态加载的商品列表](#5. 实战案例:爬取动态加载的商品列表)
- [6. 处理常见问题](#6. 处理常见问题)
-
- [6.1 反爬虫检测](#6.1 反爬虫检测)
- [6.2 处理验证码](#6.2 处理验证码)
- [6.3 性能优化](#6.3 性能优化)
- [7. 实践练习](#7. 实践练习)
- [8. 课程小结](#8. 课程小结)
- [9. 下节预告](#9. 下节预告)
- [10. 作业](#10. 作业)
专栏导读
🌸 欢迎来到Python办公自动化专栏---Python处理办公问题,解放您的双手
🏳️🌈 个人博客主页:请点击------> 个人的博客主页 求收藏
🏳️🌈 Github主页:请点击------> Github主页 求Star⭐
🏳️🌈 知乎主页:请点击------> 知乎主页 求关注
🏳️🌈 CSDN博客主页:请点击------> CSDN的博客主页 求关注
👍 该系列文章专栏:请点击------>Python办公自动化专栏 求订阅
🕷 此外还有爬虫专栏:请点击------>Python爬虫基础专栏 求订阅
📕 此外还有python基础专栏:请点击------>Python基础学习专栏 求订阅
文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
❤️ 欢迎各位佬关注! ❤️
课程目标
- 掌握Selenium的安装和基本使用
- 学会处理JavaScript动态生成的内容
- 理解浏览器自动化的原理和应用
- 掌握模拟用户行为的技巧
1. Selenium简介
Selenium是一个用于自动化浏览器操作的工具,它可以模拟真实用户的行为,处理JavaScript动态生成的内容。
1.1 为什么需要Selenium?
- 处理JavaScript动态内容
- 模拟用户交互(点击、输入、滚动等)
- 处理AJAX请求
- 绕过一些反爬虫机制
- 截图和页面监控
1.2 安装Selenium
bash
# 安装Selenium
pip install selenium
# 下载浏览器驱动
# Chrome: https://chromedriver.chromium.org/
# Firefox: https://github.com/mozilla/geckodriver/releases
# Edge: https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
1.3 基本使用
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 创建浏览器实例
driver = webdriver.Chrome() # 需要chromedriver在PATH中
try:
# 访问网页
driver.get("https://example.com")
# 查找元素
element = driver.find_element(By.ID, "element-id")
# 获取文本
text = element.text
print(text)
finally:
# 关闭浏览器
driver.quit()
2. 浏览器驱动配置
2.1 Chrome驱动配置
python
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
def create_chrome_driver():
"""创建Chrome驱动"""
chrome_options = Options()
# 无头模式(不显示浏览器窗口)
chrome_options.add_argument('--headless')
# 禁用图片加载(提高速度)
chrome_options.add_argument('--blink-settings=imagesEnabled=false')
# 禁用JavaScript(如果不需要)
# chrome_options.add_argument('--disable-javascript')
# 设置窗口大小
chrome_options.add_argument('--window-size=1920,1080')
# 禁用GPU加速
chrome_options.add_argument('--disable-gpu')
# 禁用开发者工具
chrome_options.add_argument('--disable-dev-shm-usage')
# 设置用户代理
chrome_options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')
# 指定驱动路径(如果不在PATH中)
service = Service('path/to/chromedriver.exe')
driver = webdriver.Chrome(service=service, options=chrome_options)
# 设置隐式等待
driver.implicitly_wait(10)
return driver
# 使用示例
driver = create_chrome_driver()
2.2 Firefox驱动配置
python
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.service import Service
def create_firefox_driver():
"""创建Firefox驱动"""
firefox_options = Options()
# 无头模式
firefox_options.add_argument('--headless')
# 禁用图片
firefox_options.set_preference('permissions.default.image', 2)
# 禁用CSS
firefox_options.set_preference('permissions.default.stylesheet', 2)
# 设置用户代理
firefox_options.set_preference('general.useragent.override',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0')
service = Service('path/to/geckodriver.exe')
driver = webdriver.Firefox(service=service, options=firefox_options)
driver.implicitly_wait(10)
return driver
3. 元素定位方法
3.1 基本定位方法
python
from selenium.webdriver.common.by import By
# 通过ID定位
element = driver.find_element(By.ID, "element-id")
# 通过类名定位
element = driver.find_element(By.CLASS_NAME, "class-name")
# 通过标签名定位
element = driver.find_element(By.TAG_NAME, "div")
# 通过名称定位
element = driver.find_element(By.NAME, "element-name")
# 通过链接文本定位
element = driver.find_element(By.LINK_TEXT, "链接文本")
# 通过部分链接文本定位
element = driver.find_element(By.PARTIAL_LINK_TEXT, "部分文本")
# 通过CSS选择器定位
element = driver.find_element(By.CSS_SELECTOR, ".class-name")
# 通过XPath定位
element = driver.find_element(By.XPATH, "//div[@class='class-name']")
3.2 查找多个元素
python
# 查找所有匹配的元素
elements = driver.find_elements(By.CLASS_NAME, "item")
for element in elements:
print(element.text)
# 在特定元素内查找子元素
parent = driver.find_element(By.ID, "parent-id")
child = parent.find_element(By.CLASS_NAME, "child-class")
3.3 等待元素出现
python
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
def wait_for_element(driver, locator, timeout=10):
"""等待元素出现"""
try:
element = WebDriverWait(driver, timeout).until(
EC.presence_of_element_located(locator)
)
return element
except TimeoutException:
print(f"元素 {locator} 在 {timeout} 秒内未出现")
return None
# 使用示例
element = wait_for_element(driver, (By.ID, "dynamic-content"))
# 等待元素可点击
clickable_element = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "button-id"))
)
# 等待元素可见
visible_element = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CLASS_NAME, "popup"))
)
4. 用户行为模拟
4.1 基本操作
python
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
# 点击元素
element = driver.find_element(By.ID, "button")
element.click()
# 输入文本
input_field = driver.find_element(By.NAME, "username")
input_field.clear() # 清空输入框
input_field.send_keys("用户名")
# 提交表单
form = driver.find_element(By.ID, "login-form")
form.submit()
# 按键操作
input_field.send_keys(Keys.ENTER)
input_field.send_keys(Keys.TAB)
input_field.send_keys(Keys.ESCAPE)
# 组合键
input_field.send_keys(Keys.CONTROL + "a") # Ctrl+A
input_field.send_keys(Keys.CONTROL + "c") # Ctrl+C
4.2 高级操作
python
# 鼠标操作
actions = ActionChains(driver)
# 悬停
element = driver.find_element(By.ID, "hover-element")
actions.move_to_element(element).perform()
# 右键点击
actions.context_click(element).perform()
# 双击
actions.double_click(element).perform()
# 拖拽
source = driver.find_element(By.ID, "source")
target = driver.find_element(By.ID, "target")
actions.drag_and_drop(source, target).perform()
# 滚动到元素
driver.execute_script("arguments[0].scrollIntoView();", element)
# 滚动页面
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
4.3 处理弹窗和框架
python
# 处理JavaScript弹窗
try:
alert = driver.switch_to.alert
alert_text = alert.text
print(f"弹窗内容:{alert_text}")
alert.accept() # 点击确定
# alert.dismiss() # 点击取消
except:
print("没有弹窗")
# 处理iframe
iframe = driver.find_element(By.TAG_NAME, "iframe")
driver.switch_to.frame(iframe)
# 在iframe中操作
element_in_iframe = driver.find_element(By.ID, "element-in-iframe")
# 切换回主页面
driver.switch_to.default_content()
# 处理新窗口
original_window = driver.current_window_handle
# 点击打开新窗口的链接
driver.find_element(By.LINK_TEXT, "新窗口").click()
# 等待新窗口出现
WebDriverWait(driver, 10).until(lambda d: len(d.window_handles) > 1)
# 切换到新窗口
for window_handle in driver.window_handles:
if window_handle != original_window:
driver.switch_to.window(window_handle)
break
# 在新窗口中操作
print(driver.title)
# 关闭新窗口并切换回原窗口
driver.close()
driver.switch_to.window(original_window)
5. 实战案例:爬取动态加载的商品列表
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
import time
import json
import random
class DynamicProductSpider:
def __init__(self, headless=True):
self.driver = self.create_driver(headless)
self.products = []
def create_driver(self, headless):
"""创建浏览器驱动"""
chrome_options = Options()
if headless:
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
chrome_options.add_argument('--disable-blink-features=AutomationControlled')
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(options=chrome_options)
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
return driver
def scroll_and_load(self, max_scrolls=10):
"""滚动页面加载更多内容"""
last_height = self.driver.execute_script("return document.body.scrollHeight")
scrolls = 0
while scrolls < max_scrolls:
# 滚动到页面底部
self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# 等待新内容加载
time.sleep(random.uniform(2, 4))
# 检查是否有新内容
new_height = self.driver.execute_script("return document.body.scrollHeight")
if new_height == last_height:
# 尝试点击"加载更多"按钮
try:
load_more_btn = self.driver.find_element(By.CLASS_NAME, "load-more")
if load_more_btn.is_displayed():
load_more_btn.click()
time.sleep(3)
continue
except:
break
last_height = new_height
scrolls += 1
print(f"已滚动 {scrolls} 次,页面高度:{new_height}")
def extract_products(self):
"""提取商品信息"""
try:
# 等待商品列表加载
WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "product-item"))
)
# 获取所有商品元素
product_elements = self.driver.find_elements(By.CLASS_NAME, "product-item")
print(f"找到 {len(product_elements)} 个商品")
for element in product_elements:
product_data = self.extract_single_product(element)
if product_data:
self.products.append(product_data)
except Exception as e:
print(f"提取商品失败:{e}")
def extract_single_product(self, element):
"""提取单个商品信息"""
try:
# 商品名称
name_elem = element.find_element(By.CLASS_NAME, "product-name")
name = name_elem.text.strip()
# 商品价格
price_elem = element.find_element(By.CLASS_NAME, "product-price")
price = price_elem.text.strip()
# 商品链接
link_elem = element.find_element(By.TAG_NAME, "a")
link = link_elem.get_attribute("href")
# 商品图片
img_elem = element.find_element(By.TAG_NAME, "img")
image_url = img_elem.get_attribute("src")
# 评分(可能不存在)
try:
rating_elem = element.find_element(By.CLASS_NAME, "rating")
rating = rating_elem.get_attribute("data-rating")
except:
rating = ""
# 销量(可能不存在)
try:
sales_elem = element.find_element(By.CLASS_NAME, "sales")
sales = sales_elem.text.strip()
except:
sales = ""
return {
'name': name,
'price': price,
'link': link,
'image_url': image_url,
'rating': rating,
'sales': sales
}
except Exception as e:
print(f"提取单个商品失败:{e}")
return None
def search_products(self, keyword, max_pages=3):
"""搜索商品"""
try:
# 访问搜索页面
search_url = f"https://example-shop.com/search?q={keyword}"
self.driver.get(search_url)
# 等待页面加载
time.sleep(3)
for page in range(max_pages):
print(f"正在处理第 {page + 1} 页...")
# 滚动加载更多内容
self.scroll_and_load()
# 提取当前页面的商品
self.extract_products()
# 尝试翻页
try:
next_btn = self.driver.find_element(By.CLASS_NAME, "next-page")
if next_btn.is_enabled():
next_btn.click()
time.sleep(3)
else:
break
except:
break
except Exception as e:
print(f"搜索商品失败:{e}")
def handle_login(self, username, password):
"""处理登录"""
try:
# 点击登录按钮
login_btn = self.driver.find_element(By.CLASS_NAME, "login-btn")
login_btn.click()
# 等待登录表单出现
WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.NAME, "username"))
)
# 输入用户名和密码
username_field = self.driver.find_element(By.NAME, "username")
password_field = self.driver.find_element(By.NAME, "password")
username_field.send_keys(username)
time.sleep(1)
password_field.send_keys(password)
time.sleep(1)
# 提交表单
submit_btn = self.driver.find_element(By.CLASS_NAME, "submit-btn")
submit_btn.click()
# 等待登录完成
WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "user-info"))
)
print("登录成功")
return True
except Exception as e:
print(f"登录失败:{e}")
return False
def save_products(self, filename='products.json'):
"""保存商品数据"""
with open(filename, 'w', encoding='utf-8') as f:
json.dump(self.products, f, ensure_ascii=False, indent=2)
print(f"已保存 {len(self.products)} 个商品到 {filename}")
def close(self):
"""关闭浏览器"""
self.driver.quit()
# 使用示例
if __name__ == "__main__":
spider = DynamicProductSpider(headless=False) # 显示浏览器窗口用于调试
try:
# 搜索商品
spider.search_products("手机", max_pages=3)
# 保存结果
spider.save_products()
finally:
spider.close()
6. 处理常见问题
6.1 反爬虫检测
python
def setup_stealth_driver():
"""设置隐蔽的浏览器驱动"""
chrome_options = Options()
# 禁用自动化标识
chrome_options.add_argument('--disable-blink-features=AutomationControlled')
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)
# 随机用户代理
user_agents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
]
chrome_options.add_argument(f'--user-agent={random.choice(user_agents)}')
driver = webdriver.Chrome(options=chrome_options)
# 移除webdriver属性
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
return driver
6.2 处理验证码
python
def handle_captcha(driver):
"""处理验证码"""
try:
# 检查是否有验证码
captcha_img = driver.find_element(By.ID, "captcha-image")
if captcha_img.is_displayed():
print("检测到验证码,需要人工处理")
# 截图保存验证码
captcha_img.screenshot("captcha.png")
# 等待用户手动输入验证码
input("请手动输入验证码后按回车继续...")
except:
pass # 没有验证码
6.3 性能优化
python
def optimize_driver_performance():
"""优化驱动性能"""
chrome_options = Options()
# 禁用图片加载
prefs = {
"profile.managed_default_content_settings.images": 2,
"profile.default_content_setting_values.notifications": 2,
"profile.managed_default_content_settings.media_stream": 2,
}
chrome_options.add_experimental_option("prefs", prefs)
# 禁用扩展
chrome_options.add_argument('--disable-extensions')
# 禁用插件
chrome_options.add_argument('--disable-plugins')
# 禁用GPU
chrome_options.add_argument('--disable-gpu')
# 设置页面加载策略
chrome_options.page_load_strategy = 'eager' # 不等待所有资源加载完成
return webdriver.Chrome(options=chrome_options)
7. 实践练习
练习1:模拟登录
编写程序模拟登录某个网站,并爬取登录后的内容。
练习2:处理无限滚动
处理无限滚动的页面,自动加载所有内容。
练习3:表单自动填写
编写程序自动填写复杂的表单并提交。
8. 课程小结
本课程我们学习了:
- Selenium的安装和基本配置
- 浏览器驱动的设置和优化
- 元素定位和等待机制
- 用户行为模拟技术
- 处理动态内容和JavaScript
- 反爬虫检测的应对方法
9. 下节预告
下一课我们将学习:
- 多线程和异步爬虫技术
- 提高爬虫效率的方法
- 并发控制和资源管理
- 分布式爬虫基础
10. 作业
- 使用Selenium爬取一个需要JavaScript的网站
- 实现自动翻页功能
- 处理包含验证码的登录流程
- 优化Selenium的性能和稳定性
提示:Selenium虽然功能强大,但相对较慢,应该在必要时才使用,能用requests解决的问题优先使用requests。
结尾
希望对初学者有帮助;致力于办公自动化的小小程序员一枚
希望能得到大家的【❤️一个免费关注❤️】感谢!
求个 🤞 关注 🤞 +❤️ 喜欢 ❤️ +👍 收藏 👍
此外还有办公自动化专栏,欢迎大家订阅:Python办公自动化专栏
此外还有爬虫专栏,欢迎大家订阅:Python爬虫基础专栏
此外还有Python基础专栏,欢迎大家订阅:Python基础学习专栏