杰瑞科技汇

Selenium爬虫如何高效应对反爬?

这是一个非常经典且强大的技术组合,尤其适合处理那些“传统”爬虫(如 requests + BeautifulSoup)难以应对的网站。

Selenium爬虫如何高效应对反爬?-图1
(图片来源网络,侵删)

目录

  1. 什么是 Selenium?为什么需要它?
  2. Selenium 工作原理
  3. 环境搭建
  4. Selenium 核心用法详解
  5. 实战案例:爬取动态加载的图片
  6. Selenium 进阶技巧
  7. 总结与对比

什么是 Selenium?为什么需要它?

传统爬虫的局限性

传统的 Python 爬虫通常使用 requests 库向服务器发送 HTTP 请求,然后使用 BeautifulSouplxml 等库解析服务器返回的 HTML 代码。

这种方式的优点是速度快、资源消耗低,但它有一个致命的弱点:它只能获取服务器返回的静态 HTML 内容

现在很多网站为了提升用户体验,大量使用 JavaScript (JS) 来动态加载数据。

  • 无限滚动加载:你滚动到页面底部时,才会加载新的内容。
  • AJAX 请求:点击按钮或输入关键词后,通过异步请求从服务器获取数据并更新页面,而整个页面不会刷新。
  • 渲染复杂内容:图表、评论区、商品列表等都是 JS 动态生成的。

对于这些网站,requests 只能拿到一个空的“骨架” HTML,里面没有我们想要的数据,这时,Selenium 就派上用场了。

Selenium爬虫如何高效应对反爬?-图2
(图片来源网络,侵删)

Selenium 是什么?

Selenium 是一个Web 自动化测试工具,它可以通过代码模拟真实用户的浏览器操作,

  • 打开网页
  • 点击按钮
  • 输入文字
  • 滚动页面
  • 等待元素加载

最重要的是,Selenium 在执行这些操作时,会等待 JavaScript 完全执行并渲染出最终的页面,然后再将我们需要的、包含动态数据的 HTML 代码交给我们,Selenium 可以被看作是一个“有头浏览器”(Headed Browser)。


Selenium 工作原理

Selenium 的流程是这样的:

  1. 你的 Python 脚本:告诉 Selenium 要打开哪个网址,要执行什么操作(比如点击“加载更多”按钮)。
  2. Selenium WebDriver:这是一个“桥梁”,它接收 Python 脚本的指令,并将其翻译成浏览器能听懂的语言。
  3. 浏览器 (如 Chrome, Firefox):浏览器接收到指令后,像真人一样去执行操作(打开网页、点击等),浏览器内部有一个叫做 DOM (Document Object Model) 的树形结构,所有的页面元素都在上面。
  4. 获取渲染后的 HTML:当页面加载完成(或你指定的操作完成后),Selenium 可以从浏览器的 DOM 中获取到最终渲染完毕的 HTML 源代码。
  5. 交还给 Python:Python 脚本拿到这个“完整”的 HTML 后,就可以再用 BeautifulSoup 等工具进行解析,提取所需数据了。

环境搭建

在使用 Selenium 之前,你需要安装几个东西:

安装 Selenium 库

打开你的终端或命令行,执行:

pip install selenium

安装浏览器驱动 (WebDriver)

这是最关键也最容易出错的一步,WebDriver 是 Selenium 控制浏览器的“翻译官”,你需要为你的浏览器(如 Chrome)下载对应的驱动程序。

以 Chrome 浏览器为例:

  1. 查看 Chrome 版本:打开 Chrome,进入 设置 -> Chrome,记下你的 Chrome 版本号(0.6478.127)。
  2. 下载对应驱动
    • 访问 Chrome 官方驱动下载页面:https://googlechromelabs.github.io/chrome-for-testing/
    • 找到与你的 Chrome 版本最接近的 chromedriverlatestlatest-RELEASE 就足够了。
    • 根据你的操作系统下载对应的压缩包(如 win32, mac-x64, linux64)。
  3. 配置环境变量
    • 方法一(推荐):将下载好的 chromedriver.exe (Windows) 或 chromedriver (Mac/Linux) 文件,放到你的 Python 脚本所在的同一个目录下,这样 Selenium 就能自动找到它。
    • 方法二:将 chromedriver 所在的目录路径添加到系统的环境变量 PATH 中。

注意:WebDriver 的版本最好与你的浏览器版本保持一致或非常接近,否则可能会出现不兼容的问题。


Selenium 核心用法详解

下面我们通过代码来学习 Selenium 的核心功能。

基本导入和初始化

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
# 方式一:不指定驱动路径(chromedriver 在脚本同目录或 PATH 中)
# driver = webdriver.Chrome()
# 方式二:明确指定驱动路径(更推荐)
# s = Service(executable_path='path/to/your/chromedriver')
# driver = webdriver(service=s)
# 为了演示,我们使用方式一
driver = webdriver.Chrome()

打开和关闭网页

# 1. 打开网页
driver.get("https://www.baidu.com")
# 2. 获取窗口标题
print("当前页面标题是:", driver.title) # 输出: 百度一下,你就知道
# 3. 等待几秒,观察效果 (手动操作时很有用)
time.sleep(3)
# 4. 关闭浏览器
# driver.quit() # 关闭整个浏览器进程,推荐使用
# driver.close() # 只关闭当前标签页

定位元素

这是 Selenium 的核心,你需要告诉 Selenium 要操作页面上的哪个元素,Selenium 提供了 8 种定位方式,最常用的是以下几种:

定位方式 Python 方法 描述
ID (最可靠) driver.find_element(By.ID, "value") 通过元素的 id 属性定位。
CSS Selector (最强大) driver.find_element(By.CSS_SELECTOR, ".class") 通过 CSS 选择器定位,灵活且强大。
XPath (最灵活) driver.find_element(By.XPATH, "//div[@id='kw']") 通过 XPath 路径定位,可以处理复杂的结构。
Name driver.find_element(By.NAME, "username") 通过元素的 name 属性定位。
Link Text driver.find_element(By.LINK_TEXT, "登录") 通过超链接的完整文本定位。
Partial Link Text driver.find_element(By.PARTIAL_LINK_TEXT, "登") 通过超链接的部分文本定位。
Tag Name driver.find_element(By.TAG_NAME, "div") 通过标签名定位。
Class Name driver.find_element(By.CLASS_NAME, "s_ipt") 通过元素的 class 属性定位。

示例:

driver.get("https://www.baidu.com")
# 通过 ID 搜索框
search_box = driver.find_element(By.ID, "kw")
# 通过 CSS Selector 搜索框
# search_box = driver.find_element(By.CSS_SELECTOR, "#kw")
# 通过 Name 搜索框
# search_box = driver.find_element(By.NAME, "wd")
print("找到搜索框:", search_box)

操作元素

找到元素后,就可以对它进行操作了。

# 清空搜索框
search_box.clear()
# 在搜索框中输入内容
search_box.send_keys("Python 爬虫")
# 模拟回车键进行搜索
search_box.send_keys(Keys.ENTER)
# 或者点击搜索按钮
# search_button = driver.find_element(By.ID, "su")
# search_button.click()

获取元素信息

# 获取元素的文本内容
# 例如获取百度的“新闻”链接的文本
news_link = driver.find_element(By.LINK_TEXT, "新闻")
print("新闻链接的文本是:", news_link.text)
# 获取元素的属性值
# 例如获取搜索框的 name 属性
print("搜索框的 name 属性是:", search_box.get_attribute("name"))

等待

time.sleep() 是最简单的等待方式,但不推荐,因为它会固定等待,无论元素是否已经加载好,都会浪费时间。

推荐使用 WebDriverWait (显式等待):它会等待某个条件满足(比如元素出现)后,再继续执行代码,最多等待指定的时间,如果超时,则抛出异常。

try:
    # 等待最多 10 秒,直到 ID 为 "content_left" 的元素出现
    wait = WebDriverWait(driver, 10)
    content_left = wait.until(
        EC.presence_of_element_located((By.ID, "content_left"))
    )
    print("内容区域已加载!")
    # 等待最多 10 秒,直到链接文本为 "下一页" 的元素可以点击
    # next_page_button = wait.until(
    #     EC.element_to_be_clickable((By.LINK_TEXT, "下一页"))
    # )
    # print("下一页按钮已可点击!")
except Exception as e:
    print(f"等待超时或发生错误: {e}")

实战案例:爬取某壁纸网站的图片

假设我们要爬取一个需要滚动页面才能加载更多图片的壁纸网站。

目标:爬取 https://wallhaven.cc/search?q=nature 页面所有壁纸的链接。

import os
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 创建一个保存图片的文件夹
if not os.path.exists('wallpapers'):
    os.makedirs('wallpapers')
# 初始化 WebDriver
driver = webdriver.Chrome()
driver.get("https://wallhaven.cc/search?q=nature")
print("开始爬取...")
# 滚动页面,加载更多图片
# 滚动 5 次,每次滚动后等待 2 秒
for i in range(5):
    print(f"正在滚动页面,第 {i+1} 次...")
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    time.sleep(2) # 简单等待,让图片有时间加载
# 找到所有壁纸的缩略图链接
# 检查页面结构,壁纸的缩略图通常在 <a> 标签内,并且有特定的 class
try:
    # 使用显式等待,确保至少一个缩略图加载出来
    wait = WebDriverWait(driver, 10)
    thumbnails = wait.until(
        EC.presence_of_all_elements_located((By.CSS_SELECTOR, "a.preview"))
    )
    print(f"找到 {len(thumbnails)} 张壁纸。")
    # 遍历所有缩略图,获取高清图链接
    for i, thumb in enumerate(thumbnails):
        try:
            # 点击缩略图,打开高清图页面
            thumb.click()
            # 切换到新打开的窗口
            driver.switch_to.window(driver.window_handles[1])
            # 等待高清图加载
            wait.until(
                EC.presence_of_element_located((By.CSS_SELECTOR, "img#wallpaper"))
            )
            # 获取高清图的 src 属性
            high_res_img = driver.find_element(By.CSS_SELECTOR, "img#wallpaper").get_attribute("src")
            print(f"正在下载第 {i+1} 张图片: {high_res_img}")
            # TODO: 在这里添加下载图片的代码 (可以使用 requests 库)
            # 
            # import requests
            # response = requests.get(high_res_img)
            # with open(f"wallpapers/wallpaper_{i+1}.jpg", "wb") as f:
            #     f.write(response.content)
            # 关闭当前高清图窗口,回到搜索结果页
            driver.close()
            driver.switch_to.window(driver.window_handles[0])
            # 回到搜索页后,等待一下再点击下一张,避免操作太快
            time.sleep(1)
        except Exception as e:
            print(f"处理第 {i+1} 张图片时出错: {e}")
            # 如果出错,确保切换回主窗口
            if len(driver.window_handles) > 1:
                driver.close()
                driver.switch_to.window(driver.window_handles[0])
            continue
except Exception as e:
    print(f"页面加载或元素定位失败: {e}")
print("爬取完成!")
driver.quit()

注意:上面的代码中,下载图片的部分被注释了,你需要导入 requests 库并取消注释来完成下载功能。


Selenium 进阶技巧

  1. 无头模式:不显示浏览器界面,在后台运行,速度更快,适合服务器环境。

    from selenium.webdriver.chrome.options import Options
    chrome_options = Options()
    chrome_options.add_argument("--headless") # 开启无头模式
    chrome_options.add_argument("--disable-gpu") # 某些系统需要禁用 GPU
    driver = webdriver.Chrome(options=chrome_options)
  2. 设置窗口大小

    driver.maximize_window() # 最大化窗口
    driver.set_window_size(1920, 1080) # 设置固定大小
  3. 处理弹窗

    # 处理 alert 弹窗
    # driver.switch_to.alert.accept() # 点击 "确定"
    # driver.switch_to.alert.dismiss() # 点击 "取消"
    # text = driver.switch_to.alert.text # 获取弹窗文本
  4. 处理 iframe: 如果目标元素在 <iframe> 内,你需要先切换到 iframe 才能操作。

    # iframe_element = driver.find_element(By.ID, "my_frame_id")
    # driver.switch_to.frame(iframe_element)
    # ... 在 iframe 内操作元素 ...
    # 操作完后切回主文档
    # driver.switch_to.default_content()
  5. 页面截图

    driver.save_screenshot('screenshot.png')

总结与对比

特性 requests + BeautifulSoup Selenium
工作原理 发送 HTTP 请求,解析静态 HTML 模拟真实浏览器,渲染 JS 后再获取 HTML
速度 非常快 ,因为要启动浏览器并渲染页面
资源消耗 ,仅 Python 进程 ,需要额外运行浏览器进程
适用场景 适合大部分静态网站、API 接口 适合 JS 动态加载、需要登录、需要交互的网站
反爬 容易被 IP 封禁,需要处理 headers、cookies 等 模拟真实浏览器,反爬能力稍强,但仍有特征(如 webdriver 标识)
学习曲线 简单 相对复杂,需要学习浏览器操作

如何选择?

  • 首选 requests:在开始一个爬虫项目时,永远先尝试用 requests 去获取数据,如果能拿到,效率是最高的。
  • 切换到 Selenium:当你发现 requests 拿到的 HTML 中没有你想要的数据,或者通过抓包工具(F12)发现数据是通过 AJAX 请求加载的,再考虑使用 Selenium。

终极建议:可以将两者结合使用,先用 Selenium 登录、获取 cookies,然后将 cookies 附加到 requests 请求中,用 requests 去爬取数据页面,这样既能利用 Selenium 处理复杂交互,又能享受 requests 的高速度。

分享:
扫描分享到社交APP
上一篇
下一篇