张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫

news/2025/3/11 14:17:51/文章来源:https://www.cnblogs.com/zhanggaoxing/p/18764969

目录
  • 什么是 Selenium
  • 环境搭建与配置
    • 安装 Selenium
    • 下载浏览器驱动
  • 基础操作
    • 启动浏览器并访问网页
    • 定位网页元素
      • 通过 ID 定位
      • 通过 CSS 选择器定位
      • 通过 XPath 定位
    • 与元素交互
      • 提取数据
      • 交互操作
    • 设置等待时间
    • 切换页面
    • 执行 JavaScript 代码
    • 关闭浏览器
  • 进阶技巧
    • 使用 ActionChains 模拟用户操作
      • 常用方法
      • 模拟鼠标悬停点击菜单项
      • 模拟键盘输入
    • 设置请求参数
      • 设置无头模式
      • 禁用浏览器弹窗和通知
      • 设置代理服务器
      • 忽略 HTTPS 证书错误
      • 禁用扩展程序
      • 调整窗口大小和显示
      • 设置反爬虫策略
  • 实战案例:爬取徐州工业职业技术学院网站新闻
    • 核心功能函数
    • 数据提取与存储
    • 递归的遍历网站
    • 代码示例

什么是 Selenium

Selenium 由 Jason Huggins 于 2004 年发起,最初名为 JavaScript Testing Framework,后因受到希腊神话中“月亮女神 Selene”的启发而更名为 Selenium。它最初是为了解决网页自动化测试需求而诞生的开源工具,但因其能模拟真实浏览器操作(如点击、输入、滚动等),也被广泛用于网页数据爬取。爬虫工具有很多,例如 BeautifulSoup4,为什么选择自动化测试工具 Selenium 进行爬虫?目前绝大部分 Web 应用都使用 JavaScrip 动态加载数据,而 BeautifulSoup4 只能解析初始页面的 HTML 源码,对于动态加载的数据无法获取,因此使用 Selenium 模拟用户,完成数据加载的操作。

场景 Selenium BeautifulSoup4
动态网页数据爬取 ✅ 必须使用,如单页应用、JavaScript 渲染内容。 ❌ 无法直接处理,需结合其他工具(如 Selenium 获取动态内容后解析)。
静态网页数据提取 ⚠️ 可用,但效率较低。 ✅ 推荐,快速解析固定结构的 HTML/XML。
登录验证/表单提交 ✅ 直接模拟用户输入和点击。 ❌ 需结合 Requests 会话保持,但无法处理 JavaScript 验证。
跨浏览器兼容性测试 ✅ 支持多浏览器并行测试(如通过 Selenium Grid)。 ❌ 无此功能,仅解析 HTML。

环境搭建与配置

安装 Selenium

创建 Python 虚拟环境后,执行命令安装 selenium 包。

pip install selenium

下载浏览器驱动

下面以 Edge 浏览器为例:

  1. 确认 Edge 版本:
    • 设置 → 关于 Microsoft Edge。
  2. 下载对应版本的浏览器驱动:
    • 官网:https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver
    • 注意:驱动版本需与浏览器版本一致(如浏览器版本为116,需选择116.x.x的驱动)。
  3. 配置驱动路径:
    • 方式一:将 edgedriver.exe 放置在任意已知的目录中或添加到系统环境变量中。
      from selenium import webdriver
      from selenium.webdriver.edge.service import Serviceservice = Service(executable_path='D:/msedgedriver.exe')
      driver = webdriver.Edge(service=service)
      
    • 方式二:使用 WebDriverManager 自动管理驱动:
      # 安装 WebDriverManager
      pip install webdriver-manager
      
      # 使用代码自动下载驱动
      from selenium import webdriver
      from selenium.webdriver.edge.service import Service
      from webdriver_manager.microsoft import EdgeChromiumDriverManagerservice = Service(executable_path=EdgeChromiumDriverManager().install())
      driver = webdriver.Edge(service=service)
      

基础操作

启动浏览器并访问网页

from selenium import webdriver
from selenium.webdriver.edge.service import Serviceservice = Service(executable_path='D:/msedgedriver.exe')
driver = webdriver.Edge(service=service)
driver.get("https://www.baidu.com/")

定位网页元素

不管是爬虫或者是测试,获取到“感兴趣”的元素才能进行后续的操作。常见的定位方法有这样几种方式:

定位方式 语法示例 适用场景
ID driver.find_element(By.ID, "username") 通过元素的 id 属性定位,唯一性高,但需要目标元素有 id
CSS 选择器 driver.find_element(By.CSS_SELECTOR, ".login") 通过 CSS 选择器定位,灵活,适合复杂结构
XPath driver.find_element(By.XPATH, "//button[@type='submit']") 通过 XPath 路径定位,精准,但路径易变,维护成本高

通过 ID 定位

from selenium.webdriver.common.by import Byelement = driver.find_element(By.ID, "su")

通过 CSS 选择器定位

element = driver.find_element(By.CSS_SELECTOR, ".s_btn")

通过 XPath 定位

element = driver.find_element(By.XPATH, "//*[@id="su"]")

与元素交互

提取数据

# 获取页面标题
title = driver.title
# 获取元素文本、属性
text = element.text
href = element.get_attribute("href")

交互操作

# 输入文本
search_input = driver.find_element(By.ID, "kw")
search_input.clear()  # 清除原有内容
search_input.send_keys("电脑玩家张高兴")
# 点击按钮
search_btn = driver.find_element(By.ID, "su")
search_btn.click()

设置等待时间

driver.implicitly_wait(10)  # 等待 10 秒

切换页面

Selenium 不会主动的切换窗口,要对新弹出的页面进行操作,需要先调用 switch_to 切换到该页面。

# 获取所有窗口,将页面切换到最新的窗口
windows = driver.window_handles
driver.switch_to.window(windows[-1])

执行 JavaScript 代码

有时网页数据是动态加载的,因此需要执行 JavaScript 代码,完成数据加载这一行为的触发。

# 模拟滚动到底部加载更多内容
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

关闭浏览器

driver.quit()

进阶技巧

使用 ActionChains 模拟用户操作

ActionChains 是 Selenium 提供的一个低级用户交互模拟工具,用于执行复杂的鼠标和键盘操作。它通过构建一系列动作(如鼠标移动、点击、拖拽、键盘按键等)的队列,模拟真实用户的操作流程。

常用方法

方法 功能
move_to_element(element) 鼠标悬停在指定元素上
click(element) 点击元素
click_and_hold(element) 按住鼠标左键
context_click(element) 右键点击元素
double_click(element) 双击元素
drag_and_drop(source, target) 拖拽元素到目标位置
move_by_offset(x, y) 从当前位置移动鼠标到相对坐标(x,y)
key_down(key, element) 按下某个键(如 Keys.CONTROL),并保持按下状态
key_up(key, element) 松开之前按下的键
send_keys(keys) 向当前焦点元素发送按键

模拟鼠标悬停点击菜单项

下面模拟用户用鼠标点击百度顶部菜单“更多”中的“翻译”条目。

from selenium.webdriver.common.action_chains import ActionChains
# 获取相关元素
menu = driver.find_element(By.CSS_SELECTOR, "#s-top-left > div")
item = driver.find_element(By.CSS_SELECTOR, "#s-top-more > div:nth-child(1) > a")
# 定义动作链
actions = ActionChains(driver)
actions.move_to_element(menu).pause(1).click(item).perform()  # pause(1) 悬停1秒后点击

模拟键盘输入

from selenium.webdriver.common.keys import Keys
# 模拟 Ctrl+C
actions.key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()

设置请求参数

在使用 Selenium 时,有些时候会因为自动化请求而遇到各种问题,或者想优化爬虫脚本,Options 是一个非常重要的工具,用于定制浏览器的各种行为。

设置无头模式

在服务器或无界面环境中运行爬虫,避免显式启动浏览器窗口,节省资源。

from selenium.webdriver.edge.options import Optionsoptions = Options()
options.add_argument("--headless=new")
options.add_argument("--disable-gpu")   # 部分系统需禁用 GPU 避免报错service = Service(executable_path='D:/msedgedriver.exe')
driver = webdriver.Edge(service=service, options=options)

禁用浏览器弹窗和通知

网站存在弹窗广告、通知提示(如“允许通知”),干扰自动化操作。

options.add_argument("--disable-popup-blocking")  # 禁用弹窗拦截
options.add_argument("--disable-notifications")   # 禁用浏览器通知

设置代理服务器

options.add_argument("--proxy-server=http://127.0.0.1:8080")

忽略 HTTPS 证书错误

访问的网站使用自签名证书或存在证书错误,导致浏览器报错。

options.add_argument("--ignore-certificate-errors")

禁用扩展程序

浏览器默认安装的扩展(如广告拦截插件)干扰页面加载或元素定位。

options.add_argument("--disable-extensions")  # 禁用所有扩展
options.add_argument("--disable-extensions-except=/path/to/extension")  # 通过扩展 ID 禁用某个扩展

调整窗口大小和显示

需要模拟特定分辨率或最大化窗口。

options.add_argument("--start-maximized")      # 启动时最大化窗口
options.add_argument("window-size=1920x1080")  # 设置固定窗口大小

设置反爬虫策略

options.add_argument("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36") # 设置User-Agent
options.add_argument("--disable-blink-features=AutomationControlled") # 禁用浏览器指纹

实战案例:爬取徐州工业职业技术学院网站新闻

下面将使用 Selenium 库来爬取徐州工业职业技术学院网站上的新闻,并使用 jsonlines 库将爬取的数据输出为 .jsonl 文件。通过这个例子,可以学习到如何使用 Selenium 进行网页抓取、页面滚动控制、元素检查以及如何递归地遍历网站的所有链接。

核心功能函数

  • is_valid(): 检查URL是否属于目标站点的一部分。
  • is_element(): 判断指定元素是否存在。
  • smooth_scrol(): 控制页面平滑滚动,帮助加载所有动态内容。
  • fetch_page_content(url): 获取并返回指定URL的内容。
  • parse_articles_and_links(url): 解析页面中的文章信息和内部链接。
  • crawl(url): 主爬虫逻辑,递归调用自身处理新发现的链接。

通过这些函数,实现了从目标网站上自动提取新闻文章的功能,并将结果保存至本地文件。

数据提取与存储

对于每篇文章,脚本会提取标题、作者、日期和正文内容,并将其格式化后保存到 .jsonl 文件中。这种方法非常适合处理大量数据,因为 .jsonl 文件允许逐行添加记录,而不需要一次性加载整个文件。

with jsonlines.open(os.path.join(file_path, 'articles.jsonl'), mode='a') as f:f.write(article)

递归的遍历网站

在这个脚本中,crawl() 函数是核心部分,它负责从一个起始 URL 开始,递归地探索并抓取整个网站的内容,从一个页面开始,提取其所有链接,并对每个新发现的有效链接重复这一过程,直到没有新的链接为止。

def crawl(url):"""爬取页面"""html_content = fetch_page_content(url)if not html_content:returnlinks = parse_articles_and_links(url)for link in links:crawl(link)  # 递归调用自身处理新链接

crawl 函数内部,首先获取当前页面的内容(fetch_page_content),然后分析页面以提取文章信息和所有内部链接(parse_articles_and_links)。对于每一个新找到的有效链接,都会再次调用 crawl 函数进行处理。这样就形成了一个递归的过程,每次调用都进一步深入网站的一个新区域。当某个页面被访问过(存储在 visited_urls 列表中),或者没有更多的有效链接可探索时,对应的 crawl 调用就会结束,程序返回到上一级调用继续执行,直到最初的调用也完成为止。

代码示例

from selenium import webdriver
from selenium.webdriver.edge.service import Service
from selenium.webdriver.common.by import By
from urllib.parse import urljoin, urlparse
import os
import jsonlines
import re
import timefile_path = "output"
start_url = "https://www.xzcit.cn/"
visited_urls = []  # 已经访问过的URL
articles = []service = Service(executable_path='D:/msedgedriver.exe')
driver = webdriver.Edge(service=service)def is_valid(url):"""检查URL是否属于目标站点"""parsed = urlparse(url)return bool(parsed.netloc) and 'www.xzcit.cn' in urldef is_element(by, value):"""检查元素是否存在"""try:driver.find_element(by, value)except:return Falsereturn Truedef smooth_scrol(scroll_step=350, wait_time=0.1):"""按照指定步长和等待时间进行页面滚动。scroll_step: 每次滚动的像素数wait_time: 每次滚动间的等待时间"""driver.execute_script("window.scrollTo({top: 0});")# 获取当前文档高度last_height = driver.execute_script("return document.body.scrollHeight")while True:for i in range(0, last_height, scroll_step):driver.execute_script(f"window.scrollTo(0, {i});")time.sleep(wait_time)  # 控制滚动速度  new_height = driver.execute_script("return document.body.scrollHeight")if new_height == last_height:breaklast_height = new_heightdef fetch_page_content(url):"""获取页面内容"""if url in visited_urls:return Noneprint(f"Crawling: {url}")visited_urls.append(url)try:driver.get(url)except:return Nonesmooth_scrol()html_content = driver.page_sourcereturn html_content if html_content else Nonedef parse_articles_and_links(url):"""提取文章信息和内部链接""" links = []try:if is_element(By.CLASS_NAME, 'article'):title = driver.find_element(By.CLASS_NAME, 'arti_title').textbody = driver.find_element(By.CLASS_NAME, 'entry')author = driver.find_element(By.CLASS_NAME, 'arti_publisher').text.replace('作者:', '')dateStr = driver.find_element(By.CLASS_NAME, 'arti_update').text.replace('日期:', '')date = time.strftime('%Y年%#m月%#d日', time.strptime(dateStr, '%Y-%m-%d'))content = ''for p in body.find_elements(By.TAG_NAME, 'p'):if p.text != '':content += p.text + '\n'content = "".join(re.split('\xa0| ', content))if content != '':article = {'date': date, 'author': author, 'title': title, 'content': content}articles.append(article)print(article)with jsonlines.open(os.path.join(file_path, 'articles.jsonl'), mode='a') as f:f.write(article)except Exception as e:print("发生异常:", repr(e))# 提取页面中的所有链接for a in driver.find_elements(By.TAG_NAME, 'a'):link = a.get_attribute("href")full_link = urljoin(url, link)if is_valid(full_link) and full_link not in visited_urls and full_link not in links :links.append(full_link)print(full_link)return linksdef crawl(url):"""爬取页面"""html_content = fetch_page_content(url)if not html_content:returnlinks = parse_articles_and_links(url)for link in links:crawl(link)  # 递归调用自身处理新链接if __name__ == '__main__':if not os.path.exists(file_path):os.makedirs(file_path)crawl(start_url)driver.quit()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/897255.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DCDC电源模块

车载直流电源DCDC电源模块是一种电力电子设备,它能够在电动汽车或混动汽车的电气系统中,实现直流电源电压之间的升降转换,从而确保低压电电气系统在车辆运行过程中获得稳定且适当的电源供应。 车载直流电源DCDC电源模块是一种电力电子设备,它能够在电动汽车或混动汽车…

SpringSecurity5(1-快速入门)

Spring Security提供了简单而强大的安全机制,支持身份验证和授权。基本使用包括在Spring Boot应用中引入Spring Security依赖,配置HTTP安全规则,定义用户角色和权限。通过使用内存用户存储或集成数据库,可以实现基于表单登录、HTTP基本认证等多种认证方式,确保应用程序的安…

ASE9N20-ASEMI工业自动化专用ASE9N20

ASE9N20-ASEMI工业自动化专用ASE9N20编辑:ll 一、性能卓越,能效先锋 9N20 MOS 管最为人称道的便是它超低的导通电阻。在电路中,犹如为电流开辟了一条 “高速公路”,让电能得以高效传输,极大减少了因电阻产生的热损耗。这意味着无论是为便携设备供电的 DC - DC 转换器,还是…

LayerSkip: 使用自推测解码加速大模型推理

自推测解码是一种新颖的文本生成方法,它结合了推测解码 (Speculative Decoding) 的优势和大语言模型 (LLM) 的提前退出 (Early Exit) 机制。该方法出自论文 LayerSkip: Enabling Early-Exit Inference and Self-Speculative Decoding。它通过使用 同一个模型 的早期层来生成候…

2025年我用 Compose 写了一个 Todo App

标题党嫌疑犯实锤 序言 从2月12日到3月4日这整整三周时间里,我从零开始又学习了一次 Compose。 为什么说又,是因为这已经是我第二次学习这套课程了。 故事从 4 年前说起,2021 年在意外获悉扔物线朱凯老师准备发布一套名为 Compose 的新课程,意识到这是 Android 未来的方向,…

Ubuntu设置静态IP——NetworkManager方式

1、直接在系统界面上设置静态IP的方式,不再赘述 2、命令行方式查看已经有哪些工具#查看状态 sudo systemctl status Netplan sudo systemctl status NetworkManager sudo systemctl status systemd-networkd sudo systemctl status NetworkManager出现Active,说明电脑已经安装…

《Quick Start Kubernetes》读后感

一、 为什么选择这本书? 面试的时候经常被问到 kubernetes(下称 k8s),所以打算学习 k8s。看到《Quick Start Kubernetes》的作者对自己所写的书持续地更新,被这种认真打动了,外加这本书只有100多页,所以选择了这本书作为入门 k8s 的教材。 二、这本书写了什么? 这本书介绍…

正交实验法python实现

1.等水平正交表 每个条件下的种类一样多 例1: 这是一个7因子2状态 列表里内部每一个[]表示一个因子,然后每个因子都有2种类型 #7因子2状态 from allpairspy import AllPairs parameters = [["Chrome", "Firefox"],#因子1有"Chrome"或"Fir…

如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统

本文将提供一个详细的示例,展示如何调用 DeepSeek 的自然语言处理 API 接口。我们将以情感分析为例,演示如何发送请求、处理响应以及处理可能的错误。我在业余时间开发了一款自己的独立产品:升讯威在线客服与营销系统。陆陆续续开发了几年,从一开始的偶有用户尝试,到如今线…

使用 Pixi.js 插件实现探险者小游戏(一)

什么是 Pixi Pixi 是一个非常快的 2D sprite 渲染引擎。使用它你可以轻松的利用 JavaScript 和其他 HTML5 技术制作游戏和应用程序。 Pixi 的官网地址:https://pixijs.com/ 本游戏使用的是 Pixi 的 V4.5.5 版本,官网最新版本更新到了 V8.x,两个版本 API 相差很大,建议大家学…