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

打印 上一主题 下一主题

主题 973|帖子 973|积分 2923

目录

什么是 Selenium

Selenium 由 Jason Huggins 于 2004 年发起,最初名为 JavaScript Testing Framework,后因受到希腊神话中“月亮女神 Selene”的启发而更名为 Selenium。它最初是为了解决网页自动化测试需求而诞生的开源工具,但因其能模拟真实浏览器操作(如点击、输入、滚动等),也被广泛用于网页数据爬取。爬虫工具有很多,例如 BeautifulSoup4,为什么选择自动化测试工具 Selenium 举行爬虫?目前绝大部分 Web 应用都使用 JavaScrip 动态加载数据,而 BeautifulSoup4 只能剖析初始页面的 HTML 源码,对于动态加载的数据无法获取,因此使用 Selenium 模拟用户,完成数据加载的操作。
场景SeleniumBeautifulSoup4动态网页数据爬取✅ 必须使用,如单页应用、JavaScript 渲染内容。❌ 无法直接处理,需联合其他工具(如 Selenium 获取动态内容后剖析)。静态网页数据提取⚠️ 可用,但效率较低。✅ 推荐,快速剖析固定结构的 HTML/XML。登录验证/表单提交✅ 直接模拟用户输入和点击。❌ 需联合 Requests 会话保持,但无法处理 JavaScript 验证。跨浏览器兼容性测试✅ 支持多浏览器并行测试(如通过 Selenium Grid)。❌ 无此功能,仅剖析 HTML。环境搭建与配置

安装 Selenium

创建 Python 捏造环境后,执行命令安装 selenium 包。
  1. pip install selenium
复制代码
下载浏览器驱动

下面以 Edge 浏览器为例:

  • 确认 Edge 版本:

    • 设置 → 关于 Microsoft Edge。


  • 下载对应版本的浏览器驱动:

  • 配置驱动路径:

    • 方式一:将 edgedriver.exe 放置在恣意已知的目录中或添加到系统环境变量中。
      1. from selenium import webdriver
      2. from selenium.webdriver.edge.service import Service
      3. service = Service(executable_path='D:/msedgedriver.exe')
      4. driver = webdriver.Edge(service=service)
      复制代码
    • 方式二:使用 WebDriverManager 自动管理驱动:
      1. # 安装 WebDriverManager
      2. pip install webdriver-manager
      复制代码
      1. # 使用代码自动下载驱动
      2. from selenium import webdriver
      3. from selenium.webdriver.edge.service import Service
      4. from webdriver_manager.microsoft import EdgeChromiumDriverManager
      5. service = Service(executable_path=EdgeChromiumDriverManager().install())
      6. driver = webdriver.Edge(service=service)
      复制代码

基础操作

启动浏览器并访问网页
  1. from selenium import webdriver
  2. from selenium.webdriver.edge.service import Service
  3. service = Service(executable_path='D:/msedgedriver.exe')
  4. driver = webdriver.Edge(service=service)driver.get("https://www.baidu.com/")
复制代码

定位网页元素

不管是爬虫或者是测试,获取到“感兴趣”的元素才能举行后续的操作。常见的定位方法有这样几种方式:
定位方式语法示例适用场景IDdriver.find_element(By.ID, "username")通过元素的 id 属性定位,唯一性高,但需要目标元素有 idCSS 选择器driver.find_element(By.CSS_SELECTOR, ".login")通过 CSS 选择器定位,灵活,适合复杂结构XPathdriver.find_element(By.XPATH, "//button[@type='submit']")通过 XPath 路径定位,精准,但路径易变,维护本钱高通过 ID 定位
  1. from selenium.webdriver.common.by import By
  2. element = driver.find_element(By.ID, "su")
复制代码

通过 CSS 选择器定位
  1. element = driver.find_element(By.CSS_SELECTOR, ".s_btn")
复制代码

通过 XPath 定位
  1. element = driver.find_element(By.XPATH, "//*[@id="su"]")
复制代码

与元素交互

提取数据
  1. # 获取页面标题
  2. title = driver.title
  3. # 获取元素文本、属性
  4. text = element.text
  5. href = element.get_attribute("href")
复制代码
交互操作
  1. # 输入文本
  2. search_input = driver.find_element(By.ID, "kw")
  3. search_input.clear()  # 清除原有内容
  4. search_input.send_keys("电脑玩家张高兴")
  5. # 点击按钮
  6. search_btn = driver.find_element(By.ID, "su")
  7. search_btn.click()
复制代码

设置等待时间
  1. driver.implicitly_wait(10)  # 等待 10 秒
复制代码
切换页面

Selenium 不会主动的切换窗口,要对新弹出的页面举行操作,需要先调用 switch_to 切换到该页面。
  1. # 获取所有窗口,将页面切换到最新的窗口
  2. windows = driver.window_handles
  3. driver.switch_to.window(windows[-1])
复制代码
执行 JavaScript 代码

有时网页数据是动态加载的,因此需要执行 JavaScript 代码,完成数据加载这一举动的触发。
  1. # 模拟滚动到底部加载更多内容
  2. driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
复制代码
关闭浏览器
  1. 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)向当前焦点元素发送按键模拟鼠标悬停点击菜单项

下面模拟用户用鼠标点击百度顶部菜单“更多”中的“翻译”条目。
  1. from selenium.webdriver.common.action_chains import ActionChains
  2. # 获取相关元素
  3. menu = driver.find_element(By.CSS_SELECTOR, "#s-top-left > div")
  4. item = driver.find_element(By.CSS_SELECTOR, "#s-top-more > div:nth-child(1) > a")
  5. # 定义动作链
  6. actions = ActionChains(driver)
  7. actions.move_to_element(menu).pause(1).click(item).perform()  # pause(1) 悬停1秒后点击
复制代码
模拟键盘输入
  1. from selenium.webdriver.common.keys import Keys
  2. # 模拟 Ctrl+C
  3. actions.key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
复制代码
设置请求参数

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

在服务器或无界面环境中运行爬虫,避免显式启动浏览器窗口,节省资源。
  1. from selenium.webdriver.edge.options import Options
  2. options = Options()
  3. options.add_argument("--headless=new")
  4. options.add_argument("--disable-gpu")   # 部分系统需禁用 GPU 避免报错
  5. service = Service(executable_path='D:/msedgedriver.exe')
  6. driver = webdriver.Edge(service=service, options=options)
复制代码
禁用浏览器弹窗和关照

网站存在弹窗广告、关照提示(如“允许关照”),干扰自动化操作。
  1. options.add_argument("--disable-popup-blocking")  # 禁用弹窗拦截
  2. options.add_argument("--disable-notifications")   # 禁用浏览器通知
复制代码
设置代理服务器
  1. options.add_argument("--proxy-server=http://127.0.0.1:8080")
复制代码
忽略 HTTPS 证书错误

访问的网站使用自签名证书或存在证书错误,导致浏览器报错。
  1. options.add_argument("--ignore-certificate-errors")
复制代码
禁用扩展程序

浏览器默认安装的扩展(如广告拦截插件)干扰页面加载或元素定位。
  1. options.add_argument("--disable-extensions")  # 禁用所有扩展
  2. options.add_argument("--disable-extensions-except=/path/to/extension")  # 通过扩展 ID 禁用某个扩展
复制代码
调解窗口大小和显示

需要模拟特定分辨率或最大化窗口。
  1. options.add_argument("--start-maximized")      # 启动时最大化窗口
  2. options.add_argument("window-size=1920x1080")  # 设置固定窗口大小
复制代码
设置反爬虫策略
  1. 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
  2. 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 文件允许逐行添加记录,而不需要一次性加载整个文件。
  1. with jsonlines.open(os.path.join(file_path, 'articles.jsonl'), mode='a') as f:
  2.     f.write(article)
复制代码
递归的遍历网站

在这个脚本中,crawl() 函数是焦点部分,它负责从一个起始 URL 开始,递归地探索并抓取整个网站的内容,从一个页面开始,提取其全部链接,并对每个新发现的有效链接重复这一过程,直到没有新的链接为止。
  1. def crawl(url):
  2.     """爬取页面"""
  3.     html_content = fetch_page_content(url)
  4.     if not html_content:
  5.         return
  6.     links = parse_articles_and_links(url)
  7.     for link in links:
  8.         crawl(link)  # 递归调用自身处理新链接
复制代码
在 crawl 函数内部,首先获取当前页面的内容(fetch_page_content),然后分析页面以提取文章信息和全部内部链接(parse_articles_and_links)。对于每一个新找到的有效链接,都会再次调用 crawl 函数举行处理。这样就形成了一个递归的过程,每次调用都进一步深入网站的一个新区域。当某个页面被访问过(存储在 visited_urls 列表中),或者没有更多的有效链接可探索时,对应的 crawl 调用就会竣事,程序返回到上一级调用继续执行,直到最初的调用也完成为止。
代码示例
  1. from selenium import webdriver
  2. from selenium.webdriver.edge.service import Service
  3. from selenium.webdriver.common.by import By
  4. from urllib.parse import urljoin, urlparse
  5. import os
  6. import jsonlines
  7. import re
  8. import time
  9. file_path = "output"
  10. start_url = "https://www.xzcit.cn/"
  11. visited_urls = []  # 已经访问过的URL
  12. articles = []
  13. service = Service(executable_path='D:/msedgedriver.exe')
  14. driver = webdriver.Edge(service=service)
  15. def is_valid(url):
  16.     """检查URL是否属于目标站点"""
  17.     parsed = urlparse(url)
  18.     return bool(parsed.netloc) and 'www.xzcit.cn' in url
  19. def is_element(by, value):
  20.     """检查元素是否存在"""
  21.     try:
  22.         driver.find_element(by, value)
  23.     except:
  24.         return False
  25.     return True
  26. def smooth_scrol(scroll_step=350, wait_time=0.1):
  27.     """
  28.     按照指定步长和等待时间进行页面滚动。
  29.     scroll_step: 每次滚动的像素数
  30.     wait_time: 每次滚动间的等待时间
  31.     """
  32.     driver.execute_script("window.scrollTo({top: 0});")
  33.     # 获取当前文档高度
  34.     last_height = driver.execute_script("return document.body.scrollHeight")
  35.     while True:
  36.         for i in range(0, last_height, scroll_step):
  37.             driver.execute_script(f"window.scrollTo(0, {i});")
  38.             time.sleep(wait_time)  # 控制滚动速度  
  39.         new_height = driver.execute_script("return document.body.scrollHeight")
  40.         if new_height == last_height:
  41.             break
  42.         last_height = new_height
  43. def fetch_page_content(url):
  44.     """获取页面内容"""
  45.     if url in visited_urls:
  46.         return None
  47.     print(f"Crawling: {url}")
  48.     visited_urls.append(url)
  49.     try:
  50.         driver.get(url)
  51.     except:
  52.         return None
  53.     smooth_scrol()
  54.     html_content = driver.page_source
  55.     return html_content if html_content else None
  56. def parse_articles_and_links(url):
  57.     """提取文章信息和内部链接"""
  58.     links = []
  59.     try:
  60.         if is_element(By.CLASS_NAME, 'article'):
  61.             title = driver.find_element(By.CLASS_NAME, 'arti_title').text
  62.             body = driver.find_element(By.CLASS_NAME, 'entry')
  63.             author = driver.find_element(By.CLASS_NAME, 'arti_publisher').text.replace('作者:', '')
  64.             dateStr = driver.find_element(By.CLASS_NAME, 'arti_update').text.replace('日期:', '')
  65.             date = time.strftime('%Y年%#m月%#d日', time.strptime(dateStr, '%Y-%m-%d'))
  66.             content = ''
  67.             for p in body.find_elements(By.TAG_NAME, 'p'):
  68.                 if p.text != '':
  69.                     content += p.text + '\n'
  70.             content = "".join(re.split('\xa0| ', content))
  71.             if content != '':
  72.                 article = {'date': date, 'author': author, 'title': title, 'content': content}
  73.                 articles.append(article)
  74.                 print(article)
  75.                 with jsonlines.open(os.path.join(file_path, 'articles.jsonl'), mode='a') as f:
  76.                     f.write(article)
  77.     except Exception as e:
  78.         print("发生异常:", repr(e))
  79.     # 提取页面中的所有链接
  80.     for a in driver.find_elements(By.TAG_NAME, 'a'):
  81.         link = a.get_attribute("href")
  82.         full_link = urljoin(url, link)
  83.         if is_valid(full_link) and full_link not in visited_urls and full_link not in links :
  84.             links.append(full_link)
  85.             print(full_link)
  86.     return links
  87. def crawl(url):
  88.     """爬取页面"""
  89.     html_content = fetch_page_content(url)
  90.     if not html_content:
  91.         return
  92.     links = parse_articles_and_links(url)
  93.    
  94.     for link in links:
  95.         crawl(link)  # 递归调用自身处理新链接
  96. if __name__ == '__main__':
  97.     if not os.path.exists(file_path):
  98.         os.makedirs(file_path)
  99.     crawl(start_url)
  100.     driver.quit()
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

刘俊凯

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表