零基础玩转Selenium——从安装到实战的爬虫指南
1. 为什么你需要Selenium一个爬虫新手的真实困惑如果你刚开始学爬虫大概率已经听过或者用过requests和BeautifulSoup这对黄金搭档。它们确实好用抓取静态网页数据又快又准。但很快你就会遇到一个头疼的问题当你兴冲冲地打开一个购物网站或者社交媒体准备大展身手时却发现用requests拿到的response.text里空空如也只有几行基础的HTML骨架你想要的那些商品列表、用户评论、动态加载的内容通通不见踪影。这就是我们常说的“动态网页”。现在的网站为了用户体验和性能大量使用 JavaScript 在用户浏览器里实时渲染内容。传统的爬虫工具只能拿到服务器最初返回的“空壳”而真正有价值的数据是后来由 JavaScript 代码“画”上去的。这时候requests就有点力不从心了。我第一次遇到这情况时也懵了对着浏览器里明明显示得清清楚楚的页面代码却抓不到任何东西那种感觉就像隔着一层单向玻璃看得见摸不着。后来我发现了Selenium它简直是为这类场景而生的“神器”。简单来说Selenium 是一个浏览器自动化工具。它最初是用来做网页自动化测试的但爬虫开发者们很快发现它能完美解决动态加载的问题。因为它不是直接发送HTTP请求而是真正地启动一个浏览器比如Chrome、Edge、Firefox像真人一样去打开网页、等待页面完全加载、执行JavaScript然后再去获取渲染后的完整HTML。你在浏览器里能看到什么Selenium 就能抓到什么。所以Selenium 特别适合以下这些让你抓狂的场景页面内容由 JavaScript 异步加载比如无限滚动的社交媒体、点击“加载更多”才出现的数据。需要登录才能访问Selenium 可以模拟输入用户名密码、点击登录按钮的全过程。操作复杂比如需要先点击某个选项卡再选择日期再提交表单才能看到结果。对付简单的反爬有些网站通过检测请求头或行为模式来反爬而Selenium驱动的浏览器行为与真人高度相似。当然它也不是万能的。相比requests它速度慢、占用资源多毕竟开着一个浏览器。但对于我们新手来说先从 Selenium 入手能让你绕过最复杂的动态内容难题快速获得成就感建立起信心。等基础打牢了再去研究更高效的方案比如分析背后的API接口也不迟。接下来我们就从零开始一步步把它用起来。2. 手把手搭建你的第一个Selenium环境万事开头难但Selenium的环境搭建其实比想象中简单。你只需要准备好两样东西Python的Selenium库和对应浏览器的驱动程序。我强烈建议新手使用Chrome或Edge浏览器因为它们的驱动最稳定社区资源也最丰富。这里我以 Edge 浏览器为例Chrome 的步骤几乎一模一样。2.1 第一步安装Selenium库打开你的命令行终端Windows上是CMD或PowerShellMac/Linux上是Terminal输入下面这行命令。这是最标准的方式。pip install selenium如果你安装了多个Python版本或者遇到了权限问题可以尝试用pip3或者加上--user参数pip3 install selenium # 或者 pip install selenium --user安装过程通常很快。完成后你可以在Python里导入试试不报错就说明成功了。from selenium import webdriver print(Selenium 库导入成功)2.2 第二步搞定最关键的浏览器驱动这是新手最容易卡住的一步但其实只要理清逻辑就很简单。Selenium 库本身只是个“指挥中心”它需要靠一个叫做WebDriver的“驱动程序”来实际控制浏览器。这个驱动必须和你的浏览器版本严格匹配。具体操作步骤查看你的浏览器版本 打开 Edge 浏览器点击右上角的三个点...-帮助和反馈-关于 Microsoft Edge。你会看到一个版本号比如版本 128.0.2739.42 (正式版本) (64 位)。记下主版本号128。下载对应版本的驱动 访问微软官方的 Edge WebDriver 下载页面。你需要根据刚才记下的主版本号找到对应的驱动版本进行下载。下载时选择与你操作系统匹配的文件通常是 Windows 的msedgedriver.exe。放置驱动并配置路径 下载下来的是一个msedgedriver.exe文件。你有两种方法来让Python找到它方法A推荐给新手把这个exe文件直接放在你的 Python 安装目录下或者 Scripts 目录下因为这些目录通常已经在系统的环境变量PATH里。放进去之后你在代码里就可以直接初始化不用指定路径。方法B更灵活把驱动文件放在任何你喜欢的位置比如D:\WebDriver\。然后在代码里初始化时通过Service对象明确告诉 Selenium 驱动在哪。这里我用方法B写个例子这样你以后管理多个驱动会更清晰from selenium import webdriver from selenium.webdriver.edge.service import Service # 指定你的 msedgedriver.exe 文件所在路径 driver_path rD:\WebDriver\msedgedriver.exe # 注意这里的 r 是为了防止路径中的反斜杠被转义 # 创建 Service 对象 service Service(executable_pathdriver_path) # 使用这个 service 来启动浏览器 driver webdriver.Edge(serviceservice) # 如果一切正常你会看到一个新的Edge浏览器窗口被打开 driver.get(https://www.baidu.com)如果浏览器成功启动并打开了百度恭喜你环境搭建已经成功了99%。剩下的1%是可能会遇到的小坑比如驱动版本不匹配会报错按照错误提示重新下载对应版本即可。3. Selenium 核心操作像真人一样浏览网页环境搞定我们就可以开始“驾驶”浏览器了。Selenium 的 API 设计得非常直观很多方法名一看就懂。3.1 页面级操作导航、窗口与源码让我们从一个最简单的脚本开始它包含了最基础的几个操作import time from selenium import webdriver from selenium.webdriver.edge.service import Service service Service(rD:\WebDriver\msedgedriver.exe) driver webdriver.Edge(serviceservice) # 打开第一个网页 driver.get(https://www.baidu.com) print(当前页面标题是:, driver.title) # 获取标题 time.sleep(2) # 等待2秒方便我们观察 # 调整浏览器窗口 driver.maximize_window() # 最大化窗口 # driver.set_window_size(1200, 800) # 或者自定义窗口大小 # driver.set_window_position(100, 100) # 设置窗口在屏幕上的位置 # 在同一个浏览器标签页里打开新页面会覆盖当前页面 driver.get(https://news.baidu.com) time.sleep(2) # 模拟点击浏览器的“后退”按钮 driver.back() print(后退到了:, driver.title) time.sleep(1) # 模拟点击“前进”按钮 driver.forward() print(又前进到了:, driver.title) time.sleep(1) # 刷新当前页面 driver.refresh() # 获取渲染后的完整页面HTML源码这是爬虫最关心的 full_html driver.page_source # 你可以把 full_html 保存下来或者用 BeautifulSoup 等工具解析 # print(full_html[:500]) # 打印前500个字符看看 # 关闭当前标签页如果只有一个标签页则关闭浏览器 driver.close() # 彻底关闭浏览器并结束WebDriver进程更干净 driver.quit()几个关键点解释driver.get(url)这是导航到某个网址的核心命令。driver.page_source这是获取动态渲染后完整HTML的魔法属性。之前requests抓不到的数据现在都在这里面了。driver.close()和driver.quit()close()关闭当前标签页quit()退出整个浏览器并释放资源。写脚本时最后用driver.quit()是个好习惯。time.sleep(seconds)这是一个“强制等待”。让程序暂停几秒确保页面有足够时间加载。但在真实项目中我们会有更智能的等待方式后面会讲。3.2 元素级操作与页面内容交互能打开页面拿到源码只是第一步我们更需要的是与页面上的具体元素互动点击按钮、输入文字、下拉选择等等。要做到这些首先必须找到那个元素。如何定位元素在浏览器页面按F12打开开发者工具使用左上角的箭头工具点击页面上你感兴趣的部分比如搜索框代码区就会高亮显示出对应的HTML代码。Selenium 提供了8种主要的定位方式对应着HTML元素的不同属性定位方式代码示例 (By.XXX)适用于IDBy.ID元素有唯一的id属性时最快最准NAMEBy.NAME元素有name属性时CLASS_NAMEBy.CLASS_NAME通过元素的CSS类名定位TAG_NAMEBy.TAG_NAME通过标签名定位如input,divLINK_TEXTBy.LINK_TEXT精确匹配超链接的完整文本PARTIAL_LINK_TEXTBy.PARTIAL_LINK_TEXT匹配超链接文本的部分内容CSS_SELECTORBy.CSS_SELECTOR使用CSS选择器功能强大灵活XPATHBy.XPATH使用XML路径语言功能最强大路径可复制实战模拟百度搜索我们以在百度输入框输入关键词并搜索为例演示最常用的ID和XPATH定位。import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys # 引入键盘按键 driver webdriver.Edge() driver.get(https://www.baidu.com) driver.maximize_window() # 方法1通过ID定位。查看百度输入框发现它有 idkw search_box driver.find_element(By.ID, kw) # 方法2通过XPATH定位。在开发者工具中右键点击元素-复制-复制XPath # search_box driver.find_element(By.XPATH, //*[idkw]) # 在搜索框里输入文字 search_box.send_keys(Python爬虫) time.sleep(1) # 模拟按下键盘的“回车键”进行搜索 search_box.send_keys(Keys.ENTER) # 除了回车还可以模拟点击搜索按钮其id是‘su’ # search_button driver.find_element(By.ID, su) # search_button.click() time.sleep(3) # 等待搜索结果加载 print(搜索完成当前页面标题包含:, driver.title) driver.quit()find_element和find_elements的区别find_element(By.XX, 值)返回第一个匹配到的元素。如果没找到会抛出NoSuchElementException异常。find_elements(By.XX, 值)返回一个包含所有匹配元素的列表。如果没找到返回空列表[]。 当你需要操作一个特定元素如唯一的搜索框时用前者当需要处理一组元素如商品列表时用后者。4. 等待的艺术让爬虫更稳定可靠上面例子中我用了很多time.sleep(3)这是为了演示方便。但在真实爬虫里这是非常糟糕的做法。因为网络速度和电脑性能不同固定等待时间要么太长效率低下要么太短页面没加载完就操作导致报错。Selenium 提供了两种更优雅的等待策略隐式等待和显式等待。4.1 隐式等待设置全局耐心隐式等待告诉WebDriver在查找任何一个元素时如果没能立即找到就等待一段设定的时间期间持续尝试查找直到找到或超时。from selenium import webdriver from selenium.webdriver.common.by import By driver webdriver.Edge() # 设置隐式等待时间为10秒 driver.implicitly_wait(10) driver.get(https://一个加载很慢的网站.com) # 下面这行代码会等待最多等10秒直到id为‘myButton’的元素出现 # 如果10秒内出现了就继续执行如果10秒后还没出现就抛出异常 button driver.find_element(By.ID, myButton) button.click()隐式等待是全局性的设置一次对后续所有的find_element和find_elements都生效。它简单但不够灵活因为它只检查元素是否存在不关心元素是否可点击、可见或有特定文本。4.2 显式等待条件触发精准控制显式等待则强大和精准得多。你可以为某个特定的操作设定一个等待条件比如“等待这个元素变成可点击状态”或者“等待这个元素里的文字包含某个关键词”。这更符合真实场景。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.Edge() driver.get(https://www.example.com) # 创建一个WebDriverWait对象设置最大等待时间10秒 wait WebDriverWait(driver, 10) try: # 等待直到ID为‘dynamicContent’的元素出现在DOM中 element wait.until( EC.presence_of_element_located((By.ID, dynamicContent)) ) print(元素已加载) # 再等待直到这个元素变得可见不仅存在而且宽高大于0 visible_element wait.until( EC.visibility_of_element_located((By.ID, dynamicContent)) ) print(元素现在可见了) # 再等待直到这个元素可以被点击 clickable_element wait.until( EC.element_to_be_clickable((By.ID, submitBtn)) ) clickable_element.click() print(按钮已点击) except TimeoutException: print(等待超时元素没有出现或满足条件) driver.quit()常用的等待条件EC有presence_of_element_located元素出现在DOM中不一定可见。visibility_of_element_located元素可见。element_to_be_clickable元素可见且可点击。text_to_be_present_in_element元素文本包含特定文字。我的经验是在项目里混合使用。先设置一个较短的隐式等待如5秒作为兜底然后在关键操作如点击一个异步加载的按钮前使用显式等待来确保状态正确。这能让你的爬虫既健壮又高效。5. 处理复杂交互多窗口、iframe与动作链当爬虫需要应对更复杂的网站交互时以下几个技巧必不可少。5.1 多窗口/标签页切换点击一个链接有时会在新标签页打开。此时Selenium的焦点还在老页面你需要手动切换。# 获取当前所有窗口的句柄类似于ID original_window driver.current_window_handle print(当前窗口句柄:, original_window) # 点击一个会在新标签页打开的链接 link driver.find_element(By.LINK_TEXT, 打开新窗口) link.click() # 获取所有窗口句柄 all_windows driver.window_handles # 这是一个列表 # 切换到新窗口假设是新打开的最后一个 for window in all_windows: if window ! original_window: driver.switch_to.window(window) break print(已切换到新窗口标题是:, driver.title) # 在新窗口操作完毕后可以切回原窗口 driver.switch_to.window(original_window) # 也可以直接新建一个标签页 driver.switch_to.new_window(tab) # 新建标签页 driver.get(https://www.newpage.com) driver.switch_to.new_window(window) # 新建浏览器窗口5.2 处理 iframe/表单嵌套很多登录框、广告、地图插件是嵌套在iframe或frame标签里的。你必须先“进入”这个框才能操作里面的元素。driver.get(https://一个带iframe登录框的网站.com) # 方法1通过iframe的id或name切换 driver.switch_to.frame(login_frame) # login_frame是iframe的id # 方法2通过定位到的iframe元素切换 iframe_element driver.find_element(By.XPATH, //iframe[classmodal-iframe]) driver.switch_to.frame(iframe_element) # 现在可以操作iframe里面的元素了 driver.find_element(By.NAME, username).send_keys(your_username) driver.find_element(By.NAME, password).send_keys(your_password) # 操作完成后必须切回主页面 driver.switch_to.default_content() # 或者切回上一级iframe如果有多层嵌套 # driver.switch_to.parent_frame()5.3 动作链模拟复杂的鼠标和键盘操作对于拖拽、右键菜单、悬停等复杂操作需要使用ActionChains。from selenium.webdriver.common.action_chains import ActionChains driver.get(https://一个可拖拽元素的网站.com) source driver.find_element(By.ID, draggable) target driver.find_element(By.ID, droppable) # 创建动作链对象 actions ActionChains(driver) # 将一系列动作放入链中点击并按住源元素 - 移动到目标元素 - 释放鼠标 actions.click_and_hold(source).move_to_element(target).release().perform() # 另一个例子鼠标悬停 menu driver.find_element(By.ID, dropdownMenu) actions.move_to_element(menu).perform() # perform() 是执行所有链中动作的关键 # 悬停后下拉菜单应该显示出来了再点击其中的选项 driver.find_element(By.LINK_TEXT, 选项一).click()6. 实战项目爬取一个动态商品列表让我们把所有知识串联起来完成一个模拟小项目爬取一个模拟电商网站例如一个练习用的测试网站上的商品名称和价格。假设这个网站的商品列表是滚动加载的。import time import csv 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.common.keys import Keys # 初始化浏览器并设置一些选项避免被轻易检测 options webdriver.EdgeOptions() # 添加参数移除“自动化控制”特征一种基础的反反爬措施 options.add_argument(--disable-blink-featuresAutomationControlled) # 不自动关闭浏览器方便调试 options.add_experimental_option(detach, True) driver webdriver.Edge(optionsoptions) driver.implicitly_wait(5) # 设置全局隐式等待 wait WebDriverWait(driver, 10) # 显式等待对象 driver.get(https://scrapingclub.com/exercise/list_infinite_scroll/) driver.maximize_window() product_data [] # 用来存储商品信息 # 模拟滚动加载。这里假设滚动3次来加载更多商品 for scroll in range(3): # 将页面滚动到底部 driver.execute_script(window.scrollTo(0, document.body.scrollHeight);) print(f已执行第 {scroll 1} 次滚动) # 等待新的商品卡片加载出来。这里假设新加载的商品会有特定的类 # 使用显式等待等待至少4个带有‘card’类的元素出现比上一次多 time.sleep(2) # 简单等待一下网络请求也可以换成更智能的显式等待 # 滚动完成后开始解析页面上的所有商品 # 使用 find_elements 获取所有商品卡片 product_cards driver.find_elements(By.CLASS_NAME, card) # 根据目标网站的HTML结构调整选择器 print(f共找到 {len(product_cards)} 个商品) for card in product_cards: try: # 在单个卡片元素内查找商品名和价格元素 name card.find_element(By.CLASS_NAME, card-title).text price card.find_element(By.CLASS_NAME, card-price).text product_data.append([name, price]) print(f商品: {name}, 价格: {price}) except Exception as e: # 如果某个卡片解析失败打印错误并继续 print(f解析一个商品时出错: {e}) continue # 将数据保存到CSV文件 with open(products.csv, w, newline, encodingutf-8-sig) as file: writer csv.writer(file) writer.writerow([商品名称, 价格]) # 写入表头 writer.writerows(product_data) print(f数据已保存到 products.csv共 {len(product_data)} 条记录。) driver.quit()这个例子涵盖了基础设置、页面滚动、智能等待、元素查找包括在父元素内查找、异常处理和数据存储。你可以根据实际要爬取的网站调整选择器、滚动逻辑和等待条件。7. 进阶话题绕开常见的检测机制随着你频繁使用Selenium可能会遇到一些网站提示“检测到自动化工具”或直接拒绝访问。这是因为Selenium驱动的浏览器有一些特征可以被网站检测到例如navigator.webdriver属性为true。这里分享几个我常用的、相对简单有效的应对方法。1. 添加启动参数最常用在初始化浏览器选项时添加一些参数可以隐藏部分特征。from selenium import webdriver from selenium.webdriver.edge.options import Options options Options() # 移除“自动化控制”特征 options.add_argument(--disable-blink-featuresAutomationControlled) # 排除“启用自动化”的开关 options.add_experimental_option(excludeSwitches, [enable-automation]) # 禁用密码保存提示等弹窗 options.add_experimental_option(prefs, { credentials_enable_service: False, profile.password_manager_enabled: False }) # 使用无头模式不显示浏览器界面节省资源 # options.add_argument(--headless) driver webdriver.Edge(optionsoptions)2. 使用undetected-chromedriver(对于Chrome/Edge)这是一个第三方库专门用于修改ChromeDriver使其更难被检测。它使用起来和原生Selenium几乎一样。pip install undetected-chromedriverimport undetected_chromedriver as uc driver uc.Chrome() driver.get(https://nowsecure.nl) # 这是一个著名的检测自动化工具的测试网站 # 正常操作... driver.quit()3. 关于验证码这是一个更棘手的问题。对于简单的图片验证码可以尝试接入打码平台如超级鹰、图鉴等用它们的API识别。但核心思路是Selenium本身不解决验证码识别它只负责“搬运”和“输入”。你需要用Selenium截图验证码区域发送给打码平台获取返回的文本再用Selenium输入到文本框。更复杂的滑动、点选验证码破解成本很高。对于个人学习和中小型项目更务实的建议是尝试寻找网站的手机版或WAP版其反爬可能较弱。分析网站API如果能找到数据接口直接请求API效率远高于模拟浏览器。降低请求频率添加合理的随机延迟模拟真人操作。使用代理IP池防止因请求过于频繁而被封IP。记住爬虫的道德和法律边界很重要。始终遵守网站的robots.txt协议不要对目标网站造成压力仅用于学习和获取公开数据。从Selenium入门理解网页交互的逻辑然后逐步探索更高效、更专业的方法这才是成长的正确路径。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2409094.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!