Appearance
5.1 浏览器自动化
在现代办公环境中,我们经常需要与网页进行交互,比如自动登录网站、爬取数据、填写表单等操作。通过Python实现浏览器自动化可以帮助我们高效完成这些任务。
本文将介绍如何使用Python实现浏览器自动化,包括基础浏览器操作、网页元素交互、表单自动填写以及网页截图等功能。
浏览器自动化工具简介
在Python中,有多个强大的库可用于浏览器自动化:
- Selenium:一个用于Web应用程序测试的工具,支持多种浏览器
- Playwright:由Microsoft开发的现代化自动化工具,支持多浏览器(Chromium, Firefox, Webkit)
- Requests + BeautifulSoup:适用于简单的网页请求和解析
- MechanicalSoup:一个用于自动交互网站的Python库
安装所需依赖:
bash
pip install selenium playwright requests beautifulsoup4 mechanicalsoup
基础浏览器操作
使用Selenium打开浏览器并访问网页
Selenium 是 Python 中用于浏览器自动化的常用工具,以下是使用 Selenium 打开浏览器并访问网页的基础示例:
python
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import time
def open_browser_and_visit(url):
"""
打开浏览器并访问指定网页
Args:
url: 要访问的网址
"""
try:
# 创建 Chrome 浏览器实例
driver = webdriver.Chrome()
# 访问指定网页
print(f"正在访问 {url}")
driver.get(url)
# 等待5秒,让页面加载完成
time.sleep(5)
# 获取并打印页面标题
print(f"页面标题: {driver.title}")
return driver
except Exception as e:
print(f"浏览器自动化时出错: {e}")
return None
# 使用示例 - 访问百度首页
if __name__ == "__main__":
driver = open_browser_and_visit("https://www.baidu.com")
if driver:
# 关闭浏览器
print("正在关闭浏览器...")
driver.quit()
上面的代码演示了使用 Selenium 打开 Chrome 浏览器并访问指定网页的基本流程。
使用Playwright进行多浏览器自动化
Playwright 支持多浏览器(Chromium, Firefox, Webkit)自动化,以下是使用 Playwright 的示例代码:
python
import asyncio
from playwright.async_api import async_playwright
import asyncstdlib
async def visit_website_with_playwright(url):
"""
使用Playwright访问网页
Args:
url: 要访问的网址
"""
try:
async with async_playwright() as p:
# 启动浏览器(这里使用chromium,也可以选择firefox或webkit)
browser = await p.chromium.launch(headless=False)
# 创建新页面
page = await browser.new_page()
# 访问指定网页
print(f"正在访问 {url}")
await page.goto(url)
# 获取并输出页面标题
title = await page.title()
print(f"页面标题: {title}")
# 返回页面对象以便后续操作
return page
except Exception as e:
print(f"使用Playwright时出错: {e}")
return None
# 使用示例 - 访问知乎首页
if __name__ == "__main__":
asyncio.run(visit_website_with_playwright("https://www.zhihu.com"))
这段代码展示了如何使用 Playwright 进行浏览器自动化操作。
网页元素交互
查找并点击网页元素
自动化浏览器的一个常见需求是查找并点击特定的网页元素,以下是实现这一功能的示例:
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
def search_on_baidu(keyword):
"""
在百度搜索指定关键词
Args:
keyword: 要搜索的关键词
"""
try:
# 创建 Chrome 浏览器实例
driver = webdriver.Chrome()
# 访问百度首页
driver.get("https://www.baidu.com")
print(f"已访问百度首页 - 当前URL: {driver.current_url}")
# 等待页面加载
time.sleep(2)
# 查找搜索框元素
search_box = driver.find_element(By.NAME, "wd")
print("找到搜索框")
# 输入搜索关键词
search_box.send_keys(keyword)
print(f"输入搜索词: {keyword}")
# 提交搜索
search_box.send_keys(Keys.RETURN)
print("提交搜索")
# 等待结果加载
time.sleep(5)
# 输出当前页面标题和URL
print(f"搜索结果页面标题: {driver.title}")
print(f"搜索结果页面URL: {driver.current_url}")
return driver
except Exception as e:
print(f"浏览器自动化时出错: {e}")
return None
# 使用示例 - 搜索"Python自动化"
if __name__ == "__main__":
driver = search_on_baidu("Python自动化")
if driver:
# 截图保存搜索结果
driver.save_screenshot("baidu_search_result.png")
# 关闭浏览器
print("正在关闭浏览器...")
driver.quit()
处理弹窗和警告框
自动化过程中经常会遇到弹窗,以下是如何处理浏览器弹窗的示例:
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.alert import Alert
import time
def handle_alerts():
"""演示如何处理浏览器弹窗"""
try:
# 创建浏览器实例
driver = webdriver.Chrome()
# 打开包含弹窗的测试页面
driver.get("https://www.w3schools.com/js/tryit.asp?filename=tryjs_alert")
# 切换到iframe
driver.switch_to.frame("iframeResult")
# 点击显示alert按钮
driver.find_element(By.XPATH, '//button[text()="显示提示框"]').click()
# 等待弹窗出现
time.sleep(2)
# 切换到alert
alert = driver.switch_to.alert
# 获取弹窗文本并打印
print(f"弹窗文本: {alert.text}")
# 接受弹窗(点击确定)
alert.accept()
# 返回主页面
driver.switch_to.default_content()
# 等待操作完成
time.sleep(2)
return True
except Exception as e:
print(f"处理弹窗时出错: {e}")
return False
# 使用示例
if __name__ == "__main__":
result = handle_alerts()
print(f"弹窗处理完成 {'成功' if result else '失败'}")
表单自动填写
自动填写登录表单
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
import time
def login_to_website(url, username, password, username_selector, password_selector, login_selector):
"""
登录到指定网站
Args:
url: 登录页面URL
username: 用户名
password: 密码
username_selector: 用户名输入框的CSS选择器
password_selector: 密码输入框的CSS选择器
login_selector: 登录按钮的CSS选择器
"""
try:
# 创建浏览器实例
driver = webdriver.Chrome()
# 打开登录页面
driver.get(url)
print(f"已访问登录页面 - {url}")
# 等待用户名输入框可用并填写用户名
username_field = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, username_selector))
)
username_field.send_keys(username)
print("已填写用户名")
# 等待密码输入框可用并填写密码
password_field = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, password_selector))
)
password_field.send_keys(password)
print("已填写密码")
# 等待登录按钮可点击并点击
login_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, login_selector))
)
login_button.click()
print("已提交登录")
# 等待跳转
time.sleep(5)
# 返回驱动程序以便后续操作
return driver
except Exception as e:
print(f"登录时出错: {e}")
return None
# 示例 - 登录GitHub
if __name__ == "__main__":
driver = login_to_website(
url="https://github.com/login",
username="your_username",
password="your_password",
username_selector="#login_field",
password_selector="#password",
login_selector=".btn-mktg"
)
if driver:
print(f"当前页面: {driver.current_url}")
# 截图保存登录后的页面
driver.save_screenshot("github_login_result.png")
# 关闭浏览器
print("正在关闭浏览器...")
driver.quit()
处理下拉菜单和复选框
以下是一个处理下拉菜单和复选框的示例:
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
import time
def fill_form_and_submit():
"""填写包含下拉菜单和复选框的表单"""
try:
# 创建浏览器实例
driver = webdriver.Chrome()
# 打开表单页面
driver.get("https://example.com/form-page")
print(f"已访问表单页面 - {driver.current_url}")
# 选择下拉菜单项
dropdown = Select(driver.find_element(By.ID, "options"))
dropdown.select_by_visible_text("选项2")
print("已选择下拉菜单项")
# 勾选复选框
checkbox = driver.find_element(By.ID, "agree_checkbox")
if not checkbox.is_selected():
checkbox.click()
print("已勾选复选框")
# 提交表单
submit_button = driver.find_element(By.CSS_SELECTOR, "button[type='submit']")
submit_button.click()
print("表单已提交")
# 等待并验证结果
time.sleep(5)
print(f"当前页面: {driver.current_url}")
return True
except Exception as e:
print(f"填写表单时出错: {e}")
return False
finally:
# 关闭浏览器
driver.quit()
print("浏览器已关闭")
return True
这个代码使用了Selenium库来模拟浏览器行为,并填写表单。首先,创建了一个Chrome浏览器实例,并导航到指定的URL。然后,使用CSS选择器找到表单的输入框,并输入用户名和密码。接着,使用CSS选择器找到提交按钮,并点击它。最后,等待5秒,并验证当前页面的URL是否与指定的URL一致。如果一致,则返回True,否则返回False。
网页截图与数据提取
网页截图与元素截图
在自动化测试或数据采集过程中,截图是一个非常有用的功能:
python
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
import os
def take_screenshots(url):
"""获取网页截图和特定元素截图"""
try:
# 创建浏览器实例
driver = webdriver.Chrome()
# 访问网页
driver.get(url)
print(f"已访问网页: {url}")
# 等待页面加载
time.sleep(3)
# 创建截图目录
os.makedirs("screenshots", exist_ok=True)
# 获取整个页面的截图
driver.save_screenshot("screenshots/full_page.png")
print("已保存整页截图")
# 获取特定元素的截图
try:
# 以百度首页的logo为例
if "baidu.com" in url:
element = driver.find_element(By.ID, "s_lg_img")
# 滚动到元素位置
driver.execute_script("arguments[0].scrollIntoView();", element)
time.sleep(1)
# 截取元素截图
element.screenshot("screenshots/element.png")
print("已保存元素截图")
except Exception as e:
print(f"获取元素截图时出错: {e}")
return True
except Exception as e:
print(f"截图过程中出错: {e}")
return False
finally:
# 关闭浏览器
driver.quit()
print("浏览器已关闭")
# 使用示例
if __name__ == "__main__":
take_screenshots("https://www.baidu.com")
提取网页数据
除了交互操作外,从网页提取数据也是浏览器自动化的重要应用:
python
from selenium import webdriver
from selenium.webdriver.common.by import By
import pandas as pd
import time
def extract_table_data(url, table_selector):
"""提取网页中的表格数据"""
try:
# 创建浏览器实例
driver = webdriver.Chrome()
# 访问网页
driver.get(url)
print(f"已访问网页: {url}")
# 等待页面加载
time.sleep(3)
# 查找表格元素
table = driver.find_element(By.CSS_SELECTOR, table_selector)
# 提取表头
headers = []
header_cells = table.find_elements(By.CSS_SELECTOR, "th")
for cell in header_cells:
headers.append(cell.text)
# 提取表格数据
rows = []
data_rows = table.find_elements(By.CSS_SELECTOR, "tr")
# 跳过表头行
for row in data_rows[1:]:
cells = row.find_elements(By.CSS_SELECTOR, "td")
row_data = [cell.text for cell in cells]
if row_data: # 确保行不为空
rows.append(row_data)
# 创建DataFrame
df = pd.DataFrame(rows, columns=headers)
print(f"已提取表格数据,共{len(rows)}行")
# 保存为CSV
df.to_csv("extracted_table.csv", index=False, encoding="utf-8-sig")
print("数据已保存到 extracted_table.csv")
return df
except Exception as e:
print(f"提取表格数据时出错: {e}")
return None
finally:
# 关闭浏览器
driver.quit()
print("浏览器已关闭")
# 使用示例 - 提取某网站的表格数据
# extract_table_data("https://example.com/table-page", "table.data-table")
高级浏览器自动化技巧
等待策略
在网页自动化中,正确的等待策略对于提高脚本的稳定性至关重要:
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
def demonstrate_wait_strategies():
"""演示不同的等待策略"""
driver = webdriver.Chrome()
try:
# 访问网页
driver.get("https://www.baidu.com")
# 1. 隐式等待 - 全局设置
driver.implicitly_wait(10) # 设置最长等待时间为10秒
print("已设置隐式等待")
# 使用隐式等待查找元素
search_box = driver.find_element(By.ID, "kw")
print("找到搜索框 (使用隐式等待)")
# 2. 显式等待 - 针对特定元素
# 等待搜索按钮可点击
search_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "su"))
)
print("找到搜索按钮 (使用显式等待)")
# 3. 自定义等待条件
def title_contains_baidu(driver):
return "百度" in driver.title
WebDriverWait(driver, 10).until(title_contains_baidu)
print("页面标题包含'百度' (使用自定义等待条件)")
return True
except Exception as e:
print(f"等待策略演示时出错: {e}")
return False
finally:
driver.quit()
print("浏览器已关闭")
# 使用示例
if __name__ == "__main__":
demonstrate_wait_strategies()
无头浏览器模式
无头浏览器模式可以在后台运行浏览器,不显示界面,适合服务器环境:
python
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
def run_headless_browser(url):
"""使用无头模式运行浏览器"""
try:
# 配置Chrome选项
chrome_options = Options()
chrome_options.add_argument("--headless") # 启用无头模式
chrome_options.add_argument("--disable-gpu") # 禁用GPU加速
chrome_options.add_argument("--window-size=1920,1080") # 设置窗口大小
# 创建无头浏览器实例
driver = webdriver.Chrome(options=chrome_options)
# 访问网页
print(f"正在访问 {url} (无头模式)")
driver.get(url)
# 等待页面加载
time.sleep(3)
# 获取页面信息
title = driver.title
page_source_length = len(driver.page_source)
print(f"页面标题: {title}")
print(f"页面源码长度: {page_source_length} 字符")
# 保存截图
driver.save_screenshot("headless_screenshot.png")
print("已保存无头模式截图")
return True
except Exception as e:
print(f"无头浏览器运行时出错: {e}")
return False
finally:
# 关闭浏览器
driver.quit()
print("无头浏览器已关闭")
# 使用示例
if __name__ == "__main__":
run_headless_browser("https://www.baidu.com")
处理多窗口和标签页
在自动化过程中,有时需要处理多个窗口或标签页:
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
def handle_multiple_windows():
"""处理多窗口和标签页"""
try:
# 创建浏览器实例
driver = webdriver.Chrome()
# 访问初始页面
driver.get("https://www.baidu.com")
print(f"当前窗口标题: {driver.title}")
# 记录当前窗口句柄
original_window = driver.current_window_handle
print(f"原始窗口句柄: {original_window}")
# 打开新标签页
driver.execute_script("window.open('https://www.zhihu.com', '_blank');")
print("已打开新标签页")
# 等待新标签页加载
time.sleep(3)
# 获取所有窗口句柄
all_windows = driver.window_handles
print(f"所有窗口句柄: {all_windows}")
# 切换到新标签页
for window in all_windows:
if window != original_window:
driver.switch_to.window(window)
break
print(f"已切换到新标签页,标题: {driver.title}")
# 在新标签页执行操作
time.sleep(2)
# 切回原始标签页
driver.switch_to.window(original_window)
print(f"已切回原始标签页,标题: {driver.title}")
return True
except Exception as e:
print(f"处理多窗口时出错: {e}")
return False
finally:
# 关闭浏览器
driver.quit()
print("浏览器已关闭")
# 使用示例
if __name__ == "__main__":
handle_multiple_windows()
实际应用场景
自动化网站登录与数据采集
以下是一个完整的示例,展示如何自动登录网站并采集数据:
python
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import pandas as pd
import time
import os
from datetime import datetime
class WebsiteAutomator:
"""网站自动化类,用于登录和数据采集"""
def __init__(self, headless=False):
"""初始化浏览器"""
# 配置Chrome选项
chrome_options = Options()
if headless:
chrome_options.add_argument("--headless")
chrome_options.add_argument("--disable-gpu")
chrome_options.add_argument("--window-size=1920,1080")
# 创建浏览器实例
self.driver = webdriver.Chrome(options=chrome_options)
self.driver.implicitly_wait(10) # 设置隐式等待
# 创建输出目录
self.output_dir = "automation_output"
os.makedirs(self.output_dir, exist_ok=True)
def login(self, url, username, password, username_selector, password_selector, login_selector):
"""登录网站"""
try:
# 访问登录页面
self.driver.get(url)
print(f"已访问登录页面: {url}")
# 填写用户名和密码
self.driver.find_element(By.CSS_SELECTOR, username_selector).send_keys(username)
self.driver.find_element(By.CSS_SELECTOR, password_selector).send_keys(password)
# 点击登录按钮
self.driver.find_element(By.CSS_SELECTOR, login_selector).click()
print("已提交登录表单")
# 等待登录成功
time.sleep(5)
# 验证登录状态
if "login" not in self.driver.current_url.lower():
print("登录成功")
return True
else:
print("登录失败")
return False
except Exception as e:
print(f"登录过程中出错: {e}")
return False
def navigate_to_page(self, url):
"""导航到指定页面"""
try:
self.driver.get(url)
print(f"已导航到页面: {url}")
return True
except Exception as e:
print(f"导航过程中出错: {e}")
return False
def extract_table_data(self, table_selector, filename=None):
"""提取表格数据"""
try:
# 等待表格加载
WebDriverWait(self.driver, 20).until(
EC.presence_of_element_located((By.CSS_SELECTOR, table_selector))
)
# 查找表格元素
table = self.driver.find_element(By.CSS_SELECTOR, table_selector)
# 提取表头
headers = []
header_cells = table.find_elements(By.CSS_SELECTOR, "th")
for cell in header_cells:
headers.append(cell.text)
# 提取表格数据
rows = []
data_rows = table.find_elements(By.CSS_SELECTOR, "tr")
# 跳过表头行
for row in data_rows[1:]:
cells = row.find_elements(By.CSS_SELECTOR, "td")
row_data = [cell.text for cell in cells]
if row_data: # 确保行不为空
rows.append(row_data)
# 创建DataFrame
df = pd.DataFrame(rows, columns=headers)
print(f"已提取表格数据,共{len(rows)}行")
# 保存为CSV
if filename is None:
filename = f"table_data_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
filepath = os.path.join(self.output_dir, filename)
df.to_csv(filepath, index=False, encoding="utf-8-sig")
print(f"数据已保存到 {filepath}")
return df
except Exception as e:
print(f"提取表格数据时出错: {e}")
return None
def take_screenshot(self, filename=None):
"""获取页面截图"""
try:
if filename is None:
filename = f"screenshot_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
filepath = os.path.join(self.output_dir, filename)
self.driver.save_screenshot(filepath)
print(f"截图已保存到 {filepath}")
return True
except Exception as e:
print(f"截图时出错: {e}")
return False
def close(self):
"""关闭浏览器"""
self.driver.quit()
print("浏览器已关闭")
# 使用示例
if __name__ == "__main__":
# 创建自动化实例
automator = WebsiteAutomator(headless=False)
try:
# 登录网站
login_success = automator.login(
url="https://example.com/login",
username="your_username",
password="your_password",
username_selector="#username",
password_selector="#password",
login_selector="button[type='submit']"
)
if login_success:
# 导航到数据页面
automator.navigate_to_page("https://example.com/data-page")
# 截图
automator.take_screenshot("data_page.png")
# 提取表格数据
data = automator.extract_table_data("table.data-table", "extracted_data.csv")
if data is not None:
print("数据采集完成")
finally:
# 关闭浏览器
automator.close()
自动化表单提交与数据验证
以下是一个自动化表单提交与数据验证的示例:
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait, Select
from selenium.webdriver.support import expected_conditions as EC
import pandas as pd
import time
import random
def automate_form_submission(data_file):
"""自动化表单提交与数据验证"""
try:
# 读取测试数据
test_data = pd.read_csv(data_file)
print(f"已加载测试数据,共{len(test_data)}条记录")
# 创建浏览器实例
driver = webdriver.Chrome()
# 记录结果
results = []
# 处理每条测试数据
for index, row in test_data.iterrows():
try:
# 访问表单页面
driver.get("https://example.com/form")
print(f"处理第{index+1}条数据")
# 等待表单加载
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "form-container"))
)
# 填写表单字段
driver.find_element(By.ID, "name").send_keys(row["name"])
driver.find_element(By.ID, "email").send_keys(row["email"])
# 选择下拉菜单
select = Select(driver.find_element(By.ID, "category"))
select.select_by_visible_text(row["category"])
# 勾选复选框
if row["subscribe"] == "Yes":
checkbox = driver.find_element(By.ID, "subscribe")
if not checkbox.is_selected():
checkbox.click()
# 添加随机延迟,模拟人工操作
time.sleep(random.uniform(1, 3))
# 提交表单
driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
# 等待提交结果
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "result-message"))
)
# 获取结果消息
result_message = driver.find_element(By.ID, "result-message").text
# 记录结果
results.append({
"name": row["name"],
"email": row["email"],
"success": "success" in result_message.lower(),
"message": result_message
})
print(f"表单提交结果: {result_message}")
# 添加随机延迟,避免请求过于频繁
time.sleep(random.uniform(2, 5))
except Exception as e:
print(f"处理数据 {index+1} 时出错: {e}")
results.append({
"name": row["name"],
"email": row["email"],
"success": False,
"message": str(e)
})
# 保存结果
results_df = pd.DataFrame(results)
results_df.to_csv("form_submission_results.csv", index=False)
print(f"已保存提交结果,成功率: {results_df['success'].mean()*100:.2f}%")
return results_df
except Exception as e:
print(f"表单自动化过程中出错: {e}")
return None
finally:
# 关闭浏览器
driver.quit()
print("浏览器已关闭")
# 使用示例
# automate_form_submission("test_data.csv")
小结
本文介绍了如何使用Python实现浏览器自动化,包括基础浏览器操作、网页元素交互、表单自动填写、网页截图与数据提取等功能。通过Selenium、Playwright等工具,我们可以轻松实现各种浏览器自动化任务,提高工作效率。
浏览器自动化技术在以下场景中特别有用:
- 自动化测试:验证网站功能是否正常工作
- 数据采集:从网页中提取结构化数据
- 表单自动填写:批量处理在线表单
- 网站监控:定期检查网站状态和内容变化
- 自动化报告生成:定期从网页获取数据并生成报告
在实际应用中,需要注意以下几点:
- 合理使用等待策略:避免因页面加载不完全导致的错误
- 异常处理:捕获并处理可能出现的各种异常
- 模拟人类行为:添加随机延迟,避免被网站识别为机器人
- 遵守网站规则:尊重robots.txt和使用条款,避免过于频繁的请求
通过本文的学习,读者应该能够掌握使用Python进行浏览器自动化的基本技能,为构建更复杂的自动化系统打下基础。