Python与Selenium实现浏览器自动化测试与数据抓取
1. Selenium与Python的完美结合浏览器自动化利器如果你曾经需要重复执行网页操作比如每天登录网站查询数据或者测试网页功能是否正常手动操作不仅耗时还容易出错。这就是Selenium大显身手的地方——它能像真人一样操控浏览器但速度更快且永不疲倦。Selenium最初是为网页测试而生的工具但它的能力远不止于此。通过Python调用Selenium你可以自动填写表单并提交抓取动态加载的网页数据定时执行网页操作生成网页截图或PDF测试网页兼容性我最近用Selenium Python帮朋友自动预约健身房时段原本需要每天定点抢名额现在完全交给程序处理成功率反而更高。这就是自动化带来的效率革命。2. 环境搭建与基础配置2.1 Python环境准备推荐使用Python 3.10版本这是Selenium 4.x的官方支持版本。如果你已经安装了Anaconda可以直接使用conda创建独立环境conda create -n selenium_env python3.10 conda activate selenium_env对于纯Python环境建议使用virtualenvpython -m venv selenium_venv source selenium_venv/bin/activate # Linux/Mac selenium_venv\Scripts\activate # Windows2.2 Selenium安装与浏览器驱动安装Selenium包非常简单pip install -U selenium现代Selenium 4.x最大的改进是引入了Selenium Manager它能自动处理浏览器驱动问题。以前需要手动下载chromedriver等驱动并配置PATH现在只需一行代码from selenium import webdriver driver webdriver.Chrome() # 自动下载并配置chrome驱动不过在实际项目中我建议还是明确指定驱动路径避免自动下载的版本与本地浏览器不匹配from selenium.webdriver.chrome.service import Service service Service(/path/to/chromedriver) driver webdriver.Chrome(serviceservice)注意浏览器版本必须与驱动版本匹配。Chrome可以在chrome://version/查看版本号然后到ChromeDriver官网下载对应版本。3. 核心API实战解析3.1 页面导航与元素定位Selenium的核心能力在于模拟用户操作。让我们从一个完整示例开始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(Selenium Python Keys.RETURN) # 输入并回车 results driver.find_elements(By.CSS_SELECTOR, h3.t) # 获取结果标题 for item in results[:3]: print(item.text) driver.quit() # 关闭浏览器元素定位的8种常用方式By.ID- 通过HTML id属性By.NAME- 通过name属性By.CLASS_NAME- 通过class名By.TAG_NAME- 通过标签名By.LINK_TEXT- 通过链接文本By.PARTIAL_LINK_TEXT- 链接文本包含By.CSS_SELECTOR- CSS选择器By.XPATH- XPath表达式个人经验优先使用ID和CSS选择器它们性能最好且最稳定。XPATH虽然强大但容易随页面结构调整失效。3.2 等待策略告别元素找不到的烦恼动态网页元素加载是自动化测试中最常见的问题。Selenium提供三种等待方式硬性等待不推荐import time time.sleep(5) # 强制等待5秒隐式等待全局设置driver.implicitly_wait(10) # 最多等10秒显式等待推荐方式from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC wait WebDriverWait(driver, 10) element wait.until(EC.presence_of_element_located((By.ID, dynamic-content)))实际项目中我常用自定义等待条件处理复杂场景def element_has_class(locator, class_name): def predicate(driver): element driver.find_element(*locator) return class_name in element.get_attribute(class) return predicate wait.until(element_has_class((By.ID, status), ready))4. 高级技巧与实战应用4.1 处理弹窗与iframe网页弹窗和iframe是常见的痛点。以下是处理方法# 处理JavaScript弹窗 alert driver.switch_to.alert print(alert.text) alert.accept() # 或alert.dismiss() # 切换到iframe iframe driver.find_element(By.TAG_NAME, iframe) driver.switch_to.frame(iframe) # 操作iframe内元素 driver.find_element(By.ID, iframe-btn).click() # 切回主文档 driver.switch_to.default_content()4.2 执行JavaScript代码Selenium可以直接执行JS实现原生API做不到的功能# 滚动到页面底部 driver.execute_script(window.scrollTo(0, document.body.scrollHeight)) # 修改元素属性 driver.execute_script(arguments[0].style.border3px solid red, element) # 获取页面性能指标 load_time driver.execute_script( return performance.timing.loadEventEnd - performance.timing.navigationStart )4.3 文件上传下载处理文件操作需要特殊配置# 文件上传input typefile upload driver.find_element(By.ID, file-upload) upload.send_keys(/path/to/file.pdf) # 文件下载配置 chrome_options webdriver.ChromeOptions() prefs { download.default_directory: /path/to/downloads, download.prompt_for_download: False } chrome_options.add_experimental_option(prefs, prefs) driver webdriver.Chrome(optionschrome_options)5. 项目实战构建自动化测试框架5.1 使用Page Object模式大型项目中推荐使用Page Object设计模式class LoginPage: def __init__(self, driver): self.driver driver self.url https://example.com/login def open(self): self.driver.get(self.url) return self def enter_credentials(self, username, password): self.driver.find_element(By.ID, username).send_keys(username) self.driver.find_element(By.ID, password).send_keys(password) return self def submit(self): self.driver.find_element(By.ID, submit-btn).click() return HomePage(self.driver) class HomePage: def __init__(self, driver): self.driver driver def get_welcome_message(self): return self.driver.find_element(By.ID, welcome).text # 使用示例 driver webdriver.Chrome() home_page ( LoginPage(driver) .open() .enter_credentials(test, pass) .submit() ) print(home_page.get_welcome_message())5.2 集成单元测试框架结合pytest可以构建强大的测试套件import pytest from selenium.webdriver import Chrome pytest.fixture def browser(): driver Chrome() yield driver driver.quit() def test_login(browser): home_page ( LoginPage(browser) .open() .enter_credentials(valid, credentials) .submit() ) assert Welcome in home_page.get_welcome_message() def test_failed_login(browser): login_page LoginPage(browser).open() login_page.enter_credentials(wrong, creds).submit() assert Invalid in browser.find_element(By.ID, error).text5.3 生成测试报告使用Allure可以生成美观的测试报告pip install allure-pytest# conftest.py import allure from selenium import webdriver pytest.hookimpl(tryfirstTrue, hookwrapperTrue) def pytest_runtest_makereport(item, call): outcome yield rep outcome.get_result() if rep.when call and rep.failed: driver item.funcargs[browser] allure.attach( driver.get_screenshot_as_png(), namescreenshot, attachment_typeallure.attachment_type.PNG )运行测试并生成报告pytest --alluredir./reports allure serve ./reports6. 性能优化与疑难解答6.1 提升执行速度的技巧使用无头模式(Headless)options webdriver.ChromeOptions() options.add_argument(--headlessnew) driver webdriver.Chrome(optionsoptions)禁用图片加载prefs {profile.managed_default_content_settings.images: 2} options.add_experimental_option(prefs, prefs)设置页面加载策略options.page_load_strategy eager # 不等待完整加载6.2 常见问题解决方案问题1ElementNotInteractableException原因元素被遮挡或不可见 解决from selenium.webdriver.common.action_chains import ActionChains element driver.find_element(By.ID, hidden-btn) ActionChains(driver).move_to_element(element).click().perform()问题2StaleElementReferenceException原因DOM已更新导致元素引用失效 解决def safe_click(locator): def predicate(driver): try: driver.find_element(*locator).click() return True except StaleElementReferenceException: return False WebDriverWait(driver, 10).until(predicate)问题3浏览器CPU/内存占用高优化方案定期清理缓存driver.execute_script(window.localStorage.clear())复用浏览器实例不要频繁创建/销毁设置合理的等待超时时间6.3 最佳实践总结每个测试用例应该独立不依赖其他测试状态关键操作添加日志记录和截图使用明确的等待条件而非固定sleep定期更新浏览器和驱动版本敏感信息(账号密码)使用环境变量而非硬编码CI/CD环境中使用Docker容器确保环境一致性我在实际项目中发现维护一个健康的Selenium测试套件就像养花——需要定期修剪(移除过时测试)、施肥(添加新测试)和除虫(修复不稳定测试)。当测试覆盖率超过70%时部署新版本时的信心会大幅提升。