如何用 Selenium 解决新闻数据批量采集难题

一、核心技术原理与优势

1. Selenium 核心工作原理

Selenium 本身并非浏览器,而是一套跨平台、跨浏览器的自动化测试框架,其核心工作流程分为三步:

  1. 开发者编写 Selenium 脚本(支持 Python、Java、C# 等语言,本文采用 Python 实现),定义浏览器操作逻辑;
  2. 脚本通过WebDriver(浏览器驱动)与对应浏览器建立通信,WebDriver 相当于浏览器与 Selenium 脚本之间的 "翻译官";
  3. 浏览器执行 WebDriver 传递的操作指令,完成页面加载、元素交互等动作,并将执行结果返回给 Selenium 脚本,最终实现页面数据的提取与保存。

2. Selenium 解决新闻采集难题的核心优势

  • 支持动态渲染页面:能够等待 JavaScript 执行完成,获取传统爬虫无法捕获的动态加载内容(如滚动加载的新闻列表、异步渲染的新闻详情);
  • 模拟真人操作:可模拟点击翻页、下拉滚动、输入查询关键词等动作,绕过简单的反爬机制;
  • 跨浏览器兼容:支持 Chrome、Firefox、Edge 等主流浏览器,适配不同新闻网站的兼容性要求;
  • 灵活的等待机制:提供显式等待、隐式等待,解决页面加载速度不一致导致的元素定位失败问题;
  • 可扩展能力强:可配合验证码识别工具、代理 IP 池等,应对更高强度的反爬策略。

二、前期环境搭建

要实现基于 Selenium 的新闻数据采集,首先需要完成以下环境配置,全程以 Python 语言、Chrome 浏览器为例:

1. 安装 Python 核心依赖库

2. 配置 ChromeDriver 浏览器驱动

Selenium 操作 Chrome 浏览器必须依赖 ChromeDriver,关键注意点:ChromeDriver 版本必须与本地安装的 Chrome 浏览器版本对应

步骤 1:查看 Chrome 浏览器版本

打开 Chrome 浏览器 → 点击右上角「三个点」→ 「帮助」→ 「关于 Google Chrome」,查看当前浏览器版本(如 120.0.6099.109)。

步骤 2:下载对应版本 ChromeDriver
  1. 官方下载地址:https://sites.google.com/chromium.org/driver/(科学上网);
  2. 国内替代地址:https://registry.npmmirror.com/binary.html?path=chromedriver/
  3. 下载对应系统(Windows/macOS/Linux)的 ChromeDriver 压缩包,解压后得到可执行文件(Windows 为 chromedriver.exe,macOS/Linux 为 chromedriver)。
步骤 3:配置 ChromeDriver 环境

两种配置方式二选一即可:

  1. 简单方式:将解压后的 ChromeDriver 可执行文件,放到 Python 的安装目录(Scripts 文件夹)下;
  2. 全局方式:将 ChromeDriver 的存放路径添加到系统环境变量(Path)中,后续脚本无需指定驱动路径。

三、实战实现:新闻数据批量采集

本次实战以某资讯网站的国内新闻栏目为例,实现以下功能:1. 打开目标网站,等待页面完全加载;2. 提取单页新闻的标题、发布时间、链接、摘要;3. 模拟点击翻页,批量采集多页数据;4. 将采集到的数据保存为 Excel 文件,方便后续分析。

1. 完整实现代码

python

运行

plain 复制代码
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.common.exceptions import NoSuchElementException, TimeoutException
import pandas as pd
import time

class NewsCrawler:
    def __init__(self):
        # 初始化Chrome浏览器配置
        self.options = webdriver.ChromeOptions()
        # 可选配置:隐藏浏览器窗口(无头模式),提升采集效率
        # self.options.add_argument('--headless=new')
        # 可选配置:禁用图片加载,减少页面加载时间
        self.options.add_argument('--blink-settings=imagesEnabled=false')
        # 可选配置:模拟普通浏览器请求,避免被反爬识别
        self.options.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36')
        
        # 初始化浏览器驱动
        self.driver = webdriver.Chrome(options=self.options)
        # 初始化WebDriverWait,设置默认最大等待时间10秒
        self.wait = WebDriverWait(self.driver, 10)
        # 初始化新闻数据存储列表
        self.news_data = []
    
    def extract_news_single_page(self):
        """提取单页的所有新闻数据"""
        try:
            # 显式等待:等待新闻列表容器加载完成(根据目标网站调整元素定位器)
            news_list = self.wait.until(
                EC.presence_of_all_elements_located(
                    (By.CLASS_NAME, "news-item")  # 替换为目标网站的新闻项类名
                )
            )
            
            # 遍历新闻列表,提取单条新闻数据
            for news in news_list:
                news_info = {}
                try:
                    # 提取新闻标题(根据目标网站调整元素定位方式)
                    title_elem = news.find_element(By.CLASS_NAME, "news-title")
                    news_info["标题"] = title_elem.text
                    news_info["链接"] = title_elem.get_attribute("href")
                    
                    # 提取新闻发布时间
                    time_elem = news.find_element(By.CLASS_NAME, "news-time")
                    news_info["发布时间"] = time_elem.text
                    
                    # 提取新闻摘要
                    summary_elem = news.find_element(By.CLASS_NAME, "news-summary")
                    news_info["摘要"] = summary_elem.text
                    
                    # 将单条新闻数据添加到总列表
                    self.news_data.append(news_info)
                    print(f"成功提取新闻:{news_info['标题']}")
                
                except NoSuchElementException as e:
                    print(f"单条新闻数据提取失败,缺失元素:{str(e)}")
                    continue
            
            print(f"当前页面提取完成,累计采集新闻{len(self.news_data)}条")
        
        except TimeoutException:
            print("新闻列表加载超时,无法提取单页数据")
        except Exception as e:
            print(f"单页数据提取异常:{str(e)}")
    
    def click_next_page(self):
        """模拟点击下一页按钮,返回是否成功翻页"""
        try:
            # 显式等待:等待下一页按钮可点击
            next_btn = self.wait.until(
                EC.element_to_be_clickable(
                    (By.CLASS_NAME, "page-next")  # 替换为目标网站的下一页按钮类名
                )
            )
            
            # 模拟点击下一页(避免直接点击触发反爬,添加短暂延时)
            self.driver.execute_script("arguments[0].click();", next_btn)
            # 翻页后等待新页面加载(可根据网站加载速度调整延时)
            time.sleep(2)
            return True
        
        except (NoSuchElementException, TimeoutException):
            print("已无下一页,翻页结束")
            return False
        except Exception as e:
            print(f"翻页操作异常:{str(e)}")
            return False
    
    def batch_crawl_news(self, target_url, page_count=5):
        """
        批量采集多页新闻数据
        :param target_url: 目标新闻栏目URL
        :param page_count: 要采集的页数,默认5页
        """
        try:
            # 打开目标网站
            self.driver.get(target_url)
            print(f"成功打开目标网站:{target_url}")
            
            # 循环采集指定页数
            for current_page in range(1, page_count + 1):
                print(f"\n开始采集第{current_page}页新闻数据")
                # 提取当前页新闻数据
                self.extract_news_single_page()
                # 翻页(如果是最后一页,无需翻页)
                if current_page < page_count:
                    if not self.click_next_page():
                        break
            
        except Exception as e:
            print(f"批量采集异常:{str(e)}")
    
    def save_news_to_excel(self, file_name="新闻采集结果.xlsx"):
        """将采集到的新闻数据保存为Excel文件"""
        if not self.news_data:
            print("无采集到的新闻数据,无法保存")
            return
        
        try:
            # 将列表转换为pandas DataFrame
            df = pd.DataFrame(self.news_data)
            # 保存为Excel文件(忽略索引列)
            df.to_excel(file_name, index=False, engine="openpyxl")
            print(f"新闻数据已成功保存为Excel文件,路径:{file_name}")
            print(f"最终采集到有效新闻{len(self.news_data)}条")
        
        except Exception as e:
            print(f"数据保存失败:{str(e)}")
    
    def close_crawler(self):
        """关闭浏览器,释放资源"""
        self.driver.quit()
        print("爬虫已关闭,浏览器资源释放完成")

# 主函数:执行新闻采集
if __name__ == "__main__":
    # 初始化爬虫实例
    news_crawler = NewsCrawler()
    
    try:
        # 配置目标参数(替换为实际的新闻栏目URL)
        TARGET_NEWS_URL = "https://www.example.com/news/domestic"  # 示例URL,需替换为真实地址
        CRAWL_PAGE_COUNT = 5  # 要采集的页数
        
        # 批量采集新闻数据
        news_crawler.batch_crawl_news(TARGET_NEWS_URL, CRAWL_PAGE_COUNT)
        
        # 保存采集结果到Excel
        news_crawler.save_news_to_excel()
    
    finally:
        # 无论采集是否成功,最终都关闭爬虫
        news_crawler.close_crawler()

2. 代码关键说明与适配调整

(1) 元素定位器调整

代码中使用<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">By.CLASS_NAME</font>进行元素定位(如<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">news-item</font><font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">news-title</font>),这是最常用的定位方式之一。实际使用时,需要根据目标新闻网站的 HTML 结构,替换为对应的定位器,常用定位方式包括:

  • <font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">By.ID</font>:通过元素 ID 定位(优先级最高,唯一性最强);
  • <font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">By.XPATH</font>:通过 XPath 路径定位(最灵活,支持复杂场景,如<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">//div[@class="news-item"]/h3/a</font>);
  • <font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">By.CSS_SELECTOR</font>:通过 CSS 选择器定位(效率高,如<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">.news-item .news-title</font>);
  • <font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">By.TAG_NAME</font>:通过标签名定位(适用于批量获取同类型标签)。
(2) 核心功能模块解析
  1. 浏览器配置模块:添加了用户代理、禁用图片加载等配置,减少被反爬识别的概率,同时提升页面加载效率;
  2. 显式等待模块:使用<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">WebDriverWait</font>配合<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">expected_conditions</font>,等待关键元素加载完成后再执行操作,避免 "元素未找到" 的错误,相比<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">time.sleep()</font>的固定延时,更灵活、更高效;
  3. 数据提取模块:遍历单页新闻列表,提取核心字段并存储到列表中,捕获单条新闻的元素缺失异常,保证整体采集流程不中断;
  4. 翻页模块:模拟点击下一页按钮,使用<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">execute_script()</font>点击避免元素遮挡导致的点击失败,翻页后添加短暂延时,确保新页面完全加载;
  5. 数据保存模块:利用<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">pandas</font>将采集到的列表数据转换为 Excel 文件,方便后续的数据分析和整理。
(3) 可选配置启用

代码中提供了无头模式(隐藏浏览器窗口)的配置,注释解除后即可启用,适合在服务器端运行,提升采集效率;如果采集过程中出现页面加载缓慢,可适当调整<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">WebDriverWait</font>的最大等待时间和<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">time.sleep()</font>的延时时间。

3. 运行结果说明

  1. 运行脚本后,会自动打开 Chrome 浏览器,跳转到目标新闻栏目 URL;
  2. 终端会实时打印采集进度,包括单页新闻提取情况、累计采集数量;
  3. 采集完成后,在脚本运行目录下会生成名为「新闻采集结果.xlsx」的 Excel 文件;
  4. Excel 文件中包含新闻标题、发布时间、链接、摘要四个字段,可直接用于后续的舆情分析、文本挖掘等工作。

四、进阶优化:提升采集稳定性与效率

在实际的新闻采集场景中,面对高强度反爬的新闻网站,单纯的基础采集脚本可能会出现被封禁、采集效率低下等问题,以下是几种关键的优化策略:

1. 应对反爬机制的优化

  • 加入代理 IP 池:通过更换代理 IP,避免单一 IP 被网站封禁,可配合<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">requests</font>库或专业代理 IP 服务(例如亿牛云),在<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">ChromeOptions</font>中添加代理配置:<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">self.options.add_argument('--proxy-server=http://ip:port')</font>
  • 随机延时与操作模拟:在点击、翻页等操作之间添加随机延时(如<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">time.sleep(random.uniform(1, 3))</font>),模拟真人的操作节奏,避免固定操作间隔被反爬识别;
  • 验证码处理:如果遇到登录验证码或滑块验证码,可配合<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">ddddocr</font>(验证码识别库)、<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">Selenium</font>模拟滑块拖动等方式,实现验证码自动处理;
  • Cookie 持久化:登录一次网站后,保存 Cookie 信息,后续采集直接加载 Cookie,避免重复登录,减少被反爬识别的概率。

2. 提升采集效率的优化

  • 启用无头模式:解除代码中无头模式的注释,隐藏浏览器窗口,减少系统资源占用,提升采集效率;
  • 多线程 / 多进程采集:针对多个新闻栏目或多个网站,采用多线程或多进程的方式并行采集,充分利用系统资源,大幅提升采集速度;
  • 数据增量采集:记录已采集的新闻链接,后续采集只获取新增的新闻数据,避免重复采集,节省时间和资源;
  • 异步加载优化:对于滚动加载的新闻列表(无翻页按钮),可模拟下拉滚动操作(<font style="color:rgb(31, 35, 41);background-color:rgba(0, 0, 0, 0);">self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")</font>),实现无限滚动采集。

3. 稳定性与容错性优化

  • 增加异常捕获覆盖范围:针对网络中断、页面崩溃、元素定位失败等常见异常,添加更细致的异常捕获和处理逻辑;
  • 断点续传:将采集过程中的数据实时保存到本地文件,避免脚本崩溃导致已采集数据丢失,后续可从断点处继续采集;
  • 元素定位容错:对于同一元素,提供多种定位方式(如先通过 CLASS_NAME 定位,失败后再通过 XPath 定位),提升元素定位的成功率。

五、总结

Selenium 凭借其强大的浏览器模拟能力和动态页面解析能力,完美解决了传统爬虫在新闻数据批量采集中遇到的动态渲染、反爬拦截等难题。本文从环境搭建、实战实现到进阶优化,全面讲解了基于 Selenium 的新闻采集流程,核心要点总结如下:

  1. Selenium 的核心价值在于模拟真人浏览器操作,能够获取 JavaScript 动态渲染的完整页面内容;
  2. 环境搭建的关键是保证 ChromeDriver 版本与 Chrome 浏览器版本对应,避免驱动兼容性问题;
  3. 实战脚本采用面向对象的设计,实现了单页提取、翻页采集、数据保存的完整流程,具有良好的可扩展性和可维护性;
  4. 面对高强度反爬网站,需要结合代理 IP、随机延时、验证码处理等优化策略,提升采集的稳定性和效率。
相关推荐
少云清2 小时前
【软件测试】5_性能测试 _常用性能测试工具对比
测试工具
我的xiaodoujiao1 天前
使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 39--生成 Allure测试报告
python·学习·测试工具·pytest
_OP_CHEN1 天前
【测试理论与实践】(九)Selenium 自动化测试常用函数全攻略:从元素定位到文件上传,覆盖 99% 实战场景
自动化测试·python·测试开发·selenium·测试工具·测试工程师·自动化工具
我的xiaodoujiao1 天前
使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 38--Allure 测试报告
python·学习·测试工具·pytest
废弃的小码农2 天前
功能测试--Day02--Web项目测试
功能测试·测试工具
悟能不能悟2 天前
怎么使用postman批量的给api做测试
测试工具·lua·postman
猿小路2 天前
抓包工具-Wireshark
网络·测试工具·wireshark
智航GIS2 天前
10.4 Selenium:Web 自动化测试框架
前端·python·selenium·测试工具
廖圣平3 天前
从零开始,福袋直播间脚本研究【三】《多进程执行selenium》
python·selenium·测试工具