Python Selenium 从零开始掌握浏览器自动化(超详细新手教程)

 更新时间:2025年12月23日 09:18:04   作者:xiaoyu❅  
本文详细介绍了Selenium的安装、环境搭建、基础操作、元素定位、元素操作、等待机制以及实战项目,涵盖了Selenium的各个方面,感兴趣的朋友跟随小编一起看看吧

一、写给新手的话

        如果你是第一次接触Selenium,可能会觉得有些复杂。别担心!这篇教程将从最基础的安装开始,一步步带你掌握Selenium的每个细节。我会用最简单的语言和大量示例代码,让你快速上手。

二、准备工作:环境搭建

2.1 安装Python(如果你还没有)

首先确认你安装了Python。打开命令行(Windows按Win+R,输入cmd;Mac打开终端),输入:

python --version

如果看到类似 Python 3.12.7 这样的版本号,说明已安装。如果没有,去Python官网下载安装。

2.2 安装Selenium库

在命令行中输入:

pip install selenium

如果下载慢,可以使用国内镜像:

pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple

2.3 安装浏览器驱动管理工具

传统方式需要手动下载浏览器驱动,但现在有更简单的方法:

pip install webdriver-manager

这个工具会自动帮你下载和配置浏览器驱动。

三、第一个Selenium程序:打开百度

让我们从一个最简单的例子开始:

# 1. 导入必要的库
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
# 2. 自动下载并设置Chrome驱动
service = Service(ChromeDriverManager().install())
# 3. 创建浏览器对象(会弹出一个Chrome窗口)
driver = webdriver.Chrome(service=service)
# 4. 打开百度首页
driver.get("https://www.baidu.com")
# 5. 等待5秒,让你看到效果
import time
time.sleep(5)
# 6. 关闭浏览器
driver.quit()

运行这个程序,你会看到:

  • 自动打开Chrome浏览器
  • 自动访问百度首页
  • 5秒后自动关闭

四、Selenium基础操作详解

4.1 常用操作汇总表

操作方法示例
打开网页driver.get(url)driver.get("https://www.baidu.com")
获取页面标题driver.titletitle = driver.title
获取当前URLdriver.current_urlurl = driver.current_url
前进driver.forward()driver.forward()
后退driver.back()driver.back()
刷新driver.refresh()driver.refresh()
关闭当前窗口driver.close()driver.close()
关闭所有窗口driver.quit()driver.quit()
最大化窗口driver.maximize_window()driver.maximize_window()
设置窗口大小driver.set_window_size(width, height)driver.set_window_size(800, 600)

4.2 详细操作示例

# 基础操作示例代码
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import time
# 初始化浏览器
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
try:
    # 访问第一个网站
    driver.get("https://www.baidu.com")
    print(f"当前页面标题:{driver.title}")
    print(f"当前页面URL:{driver.current_url}")
    # 等待2秒
    time.sleep(2)
    # 访问第二个网站
    driver.get("https://www.taobao.com")
    print(f"新页面标题:{driver.title}")
    # 等待2秒
    time.sleep(2)
    # 后退到百度
    driver.back()
    print(f"后退后页面:{driver.title}")
    # 等待2秒
    time.sleep(2)
    # 前进到淘宝
    driver.forward()
    print(f"前进后页面:{driver.title}")
    # 刷新页面
    driver.refresh()
    # 最大化窗口
    driver.maximize_window()
    # 设置窗口大小
    driver.set_window_size(800, 600)
finally:
    # 关闭浏览器
    time.sleep(3)
    driver.quit()
    print("浏览器已关闭")

五、元素定位:找到网页上的内容

        这是Selenium最重要的部分!就像在网页上找东西一样,我们需要告诉Selenium"我要找什么"。

5.1 8种定位方式(从易到难)

方式1:通过ID定位(最简单)

<input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off">
# HTML元素有id属性时使用(id通常是唯一的)
search_input = driver.find_element("id", "kw")
# 或者
search_input = driver.find_element_by_id("kw")

方式2:通过NAME定位

<input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off">

python

# name属性可能不唯一,但经常使用
search_input = driver.find_element("name", "wd")
# 或者
search_input = driver.find_element_by_name("wd")

方式3:通过CLASS_NAME定位

<input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off">
# class可能不唯一,一个元素可能有多个class
search_input = driver.find_element("class name", "s_ipt")
# 或者
search_input = driver.find_element_by_class_name("s_ipt")

方式4:通过TAG_NAME定位

<div>内容</div>
<input type="text">
<a href="..." rel="external nofollow" >链接</a>
# 通过标签名查找(最不精确,通常用来查找多个元素)
divs = driver.find_elements("tag name", "div")  # 所有div元素
inputs = driver.find_elements("tag name", "input")  # 所有input元素
links = driver.find_elements("tag name", "a")  # 所有链接

方式5:通过LINK_TEXT定位

<a href="https://news.baidu.com" rel="external nofollow"  rel="external nofollow" >新闻</a>
<a href="https://www.hao123.com" rel="external nofollow"  rel="external nofollow" >hao123</a>
# 精确匹配链接文本
news_link = driver.find_element("link text", "新闻")
hao123_link = driver.find_element("link text", "hao123")

方式6:通过PARTIAL_LINK_TEXT定位

<a href="https://news.baidu.com" rel="external nofollow"  rel="external nofollow" >百度新闻</a>
<a href="https://www.hao123.com" rel="external nofollow"  rel="external nofollow" >hao123网址导航</a>
# 部分匹配链接文本(包含即可)
baidu_link = driver.find_element("partial link text", "百度")  # 匹配"百度新闻"
hao123_link = driver.find_element("partial link text", "hao123")  # 匹配"hao123网址导航"

方式7:通过CSS_SELECTOR定位(推荐)

CSS选择器功能强大,类似于CSS样式选择元素:

# 通过id
element = driver.find_element("css selector", "#kw")  # #表示id
# 通过class
element = driver.find_element("css selector", ".s_ipt")  # .表示class
# 通过标签名+class
element = driver.find_element("css selector", "input.s_ipt")  # input标签且class为s_ipt
# 通过属性
element = driver.find_element("css selector", "[name='wd']")  # name属性为wd
# 组合选择
element = driver.find_element("css selector", "input#kw.s_ipt[name='wd']")

方式8:通过XPATH定位(最强大)

XPath就像文件路径,可以定位到任何元素:

# 绝对路径(从html开始)
element = driver.find_element("xpath", "/html/body/div/div[2]/div/div/div/form/span/input")
# 相对路径(推荐)
element = driver.find_element("xpath", "//input")  # 所有input标签
# 带属性的相对路径
element = driver.find_element("xpath", "//input[@id='kw']")  # id为kw的input
element = driver.find_element("xpath", "//input[@name='wd']")  # name为wd的input
# 使用and/or
element = driver.find_element("xpath", "//input[@id='kw' and @name='wd']")
# 使用文本内容
element = driver.find_element("xpath", "//a[text()='新闻']")  # 文本为"新闻"的链接
element = driver.find_element("xpath", "//a[contains(text(),'新闻')]")  # 包含"新闻"的链接

5.2 元素定位完整示例

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
# 初始化浏览器
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
try:
    # 打开百度
    driver.get("https://www.baidu.com")
    # 各种定位方式的示例
    # 1. 通过ID定位搜索框
    search_box = driver.find_element(By.ID, "kw")
    # 2. 通过NAME定位搜索框
    search_box = driver.find_element(By.NAME, "wd")
    # 3. 通过CLASS_NAME定位搜索框
    search_box = driver.find_element(By.CLASS_NAME, "s_ipt")
    # 4. 通过TAG_NAME定位所有输入框
    inputs = driver.find_elements(By.TAG_NAME, "input")
    print(f"找到 {len(inputs)} 个input元素")
    # 5. 通过LINK_TEXT定位"新闻"链接
    news_link = driver.find_element(By.LINK_TEXT, "新闻")
    # 6. 通过PARTIAL_LINK_TEXT定位包含"新"的链接
    news_links = driver.find_elements(By.PARTIAL_LINK_TEXT, "新")
    print(f"找到 {len(news_links)} 个包含'新'的链接")
    # 7. 通过CSS_SELECTOR定位
    search_box = driver.find_element(By.CSS_SELECTOR, "#kw")  # id选择器
    search_box = driver.find_element(By.CSS_SELECTOR, ".s_ipt")  # class选择器
    search_box = driver.find_element(By.CSS_SELECTOR, "input#kw")  # 标签+id
    # 8. 通过XPATH定位
    search_box = driver.find_element(By.XPATH, "//input[@id='kw']")
    search_box = driver.find_element(By.XPATH, "//*[@id='kw']")
    print("所有定位方式测试成功!")
finally:
    driver.quit()

5.3 元素定位选择建议

场景推荐方式原因
元素有idBy.ID最简单、最快、唯一
元素有nameBy.NAME简单常用
元素有classBy.CLASS_NAME简单,但class可能重复
查找多个同类元素By.TAG_NAME查找所有同类元素
精确文本链接By.LINK_TEXT链接文本不变时使用
模糊文本链接By.PARTIAL_LINK_TEXT链接文本部分匹配
复杂选择By.CSS_SELECTOR功能强大,语法简洁
最复杂情况By.XPATH功能最强大,但稍慢

六、元素操作:与网页交互

找到元素后,我们需要与之交互。下面是常用的操作:

6.1 输入文本

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
import time
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
try:
    driver.get("https://www.baidu.com")
    # 找到搜索框
    search_box = driver.find_element(By.ID, "kw")
    # 方法1:直接输入
    search_box.send_keys("Python教程")
    time.sleep(2)
    # 方法2:先清空再输入
    search_box.clear()  # 清空内容
    search_box.send_keys("Selenium教程")
    time.sleep(2)
    # 方法3:输入特殊键(如回车)
    from selenium.webdriver.common.keys import Keys
    search_box.clear()
    search_box.send_keys("自动化测试")
    search_box.send_keys(Keys.ENTER)  # 按回车键
    time.sleep(2)
finally:
    driver.quit()

6.2 点击操作

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
import time
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
try:
    driver.get("https://www.baidu.com")
    # 找到搜索框并输入内容
    search_box = driver.find_element(By.ID, "kw")
    search_box.send_keys("Python")
    # 方法1:直接点击百度一下按钮
    search_button = driver.find_element(By.ID, "su")
    search_button.click()
    time.sleep(2)
    # 方法2:模拟键盘回车(不需要点击按钮)
    driver.back()  # 返回百度首页
    time.sleep(1)
    search_box = driver.find_element(By.ID, "kw")
    search_box.clear()
    search_box.send_keys("Selenium")
    search_box.submit()  # 提交表单(相当于在输入框按回车)
    time.sleep(2)
finally:
    driver.quit()

6.3 获取元素信息

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
try:
    driver.get("https://www.baidu.com")
    # 获取搜索框元素
    search_box = driver.find_element(By.ID, "kw")
    # 获取元素的各种属性
    print(f"元素标签名: {search_box.tag_name}")
    print(f"元素ID: {search_box.get_attribute('id')}")
    print(f"元素name: {search_box.get_attribute('name')}")
    print(f"元素class: {search_box.get_attribute('class')}")
    print(f"元素类型: {search_box.get_attribute('type')}")
    print(f"元素值: {search_box.get_attribute('value')}")
    print(f"元素是否可见: {search_box.is_displayed()}")
    print(f"元素是否可用: {search_box.is_enabled()}")
    print(f"元素是否被选中: {search_box.is_selected()}")
    # 获取元素位置和大小
    location = search_box.location
    size = search_box.size
    print(f"元素位置: x={location['x']}, y={location['y']}")
    print(f"元素大小: 宽={size['width']}, 高={size['height']}")
    # 获取元素文本(对于有文本的元素)
    baidu_link = driver.find_element(By.LINK_TEXT, "百度首页")
    print(f"链接文本: {baidu_link.text}")
finally:
    driver.quit()

6.4 处理下拉框

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select
import time
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
try:
    # 访问一个测试页面(包含下拉框)
    driver.get("https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_select")
    # 切换到iframe(因为这个页面有iframe框架)
    driver.switch_to.frame("iframeResult")
    # 找到下拉框
    cars_select = driver.find_element(By.ID, "cars")
    # 创建Select对象
    select = Select(cars_select)
    # 方法1:通过可见文本选择
    select.select_by_visible_text("Audi")
    time.sleep(1)
    # 方法2:通过value值选择
    select.select_by_value("opel")
    time.sleep(1)
    # 方法3:通过索引选择(从0开始)
    select.select_by_index(0)  # 选择第一个选项
    time.sleep(1)
    # 获取所有选项
    all_options = select.options
    print("所有选项:")
    for option in all_options:
        print(f"  {option.text} (value: {option.get_attribute('value')})")
    # 获取已选中的选项
    selected_option = select.first_selected_option
    print(f"当前选中: {selected_option.text}")
finally:
    driver.quit()

6.5 处理复选框和单选框

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
import time
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
try:
    # 访问测试页面
    driver.get("https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_input_type_checkbox")
    # 切换到iframe
    driver.switch_to.frame("iframeResult")
    # 找到复选框
    vehicle1 = driver.find_element(By.ID, "vehicle1")  # 自行车
    vehicle2 = driver.find_element(By.ID, "vehicle2")  # 汽车
    vehicle3 = driver.find_element(By.ID, "vehicle3")  # 船
    # 检查复选框状态
    print(f"自行车是否选中: {vehicle1.is_selected()}")
    print(f"汽车是否选中: {vehicle2.is_selected()}")
    print(f"船是否选中: {vehicle3.is_selected()}")
    # 选中复选框(如果未选中)
    if not vehicle1.is_selected():
        vehicle1.click()
    time.sleep(1)
    if not vehicle2.is_selected():
        vehicle2.click()
    time.sleep(1)
    # 取消选中(如果已选中)
    if vehicle3.is_selected():
        vehicle3.click()
    time.sleep(1)
    # 重新检查状态
    print(f"自行车是否选中: {vehicle1.is_selected()}")
    print(f"汽车是否选中: {vehicle2.is_selected()}")
    print(f"船是否选中: {vehicle3.is_selected()}")
finally:
    driver.quit()

七、等待机制:让程序"等一等"

网页加载需要时间,我们需要等待元素出现后再操作。

7.1 强制等待(不推荐)

import time
time.sleep(5)  # 强制等待5秒,不管元素是否加载完成

缺点:如果元素提前加载完成,也要等;如果超时未加载,会报错。

7.2 隐式等待(全局等待)

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
# 设置隐式等待10秒
driver.implicitly_wait(10)
# 之后的所有find_element操作都会最多等待10秒
driver.get("https://www.baidu.com")
element = driver.find_element("id", "kw")  # 最多等10秒

优点:设置一次,全局生效。

7.3 显式等待(推荐)

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
try:
    driver.get("https://www.baidu.com")
    # 创建等待对象(最多等10秒,每0.5秒检查一次)
    wait = WebDriverWait(driver, 10, 0.5)
    # 等待元素出现
    search_box = wait.until(
        EC.presence_of_element_located((By.ID, "kw"))
    )
    print("搜索框已出现")
    # 等待元素可点击
    search_button = wait.until(
        EC.element_to_be_clickable((By.ID, "su"))
    )
    print("搜索按钮可点击")
    # 等待元素可见
    logo = wait.until(
        EC.visibility_of_element_located((By.ID, "lg"))
    )
    print("百度logo可见")
    # 等待文本出现在元素中
    news_link = wait.until(
        EC.text_to_be_present_in_element((By.LINK_TEXT, "新闻"), "新闻")
    )
    print("新闻链接文本正确")
finally:
    driver.quit()

7.4 常用等待条件

条件说明
presence_of_element_located元素出现在DOM中(不一定可见)
visibility_of_element_located元素可见(有宽高,非隐藏)
element_to_be_clickable元素可点击
text_to_be_present_in_element元素包含特定文本
title_contains页面标题包含特定文本
alert_is_present出现警告框

7.5 等待机制完整示例

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
try:
    # 1. 设置隐式等待
    driver.implicitly_wait(5)
    # 2. 访问慢速网站测试等待
    driver.get("https://the-internet.herokuapp.com/dynamic_loading/2")
    # 3. 点击开始按钮
    start_button = driver.find_element(By.XPATH, "//button[text()='Start']")
    start_button.click()
    # 4. 创建显式等待对象
    wait = WebDriverWait(driver, 10)
    # 5. 等待加载完成文字出现
    finish_text = wait.until(
        EC.visibility_of_element_located((By.ID, "finish"))
    )
    print(f"加载完成,文字内容: {finish_text.text}")
    # 6. 等待特定文本出现
    wait.until(
        EC.text_to_be_present_in_element((By.ID, "finish"), "Hello World!")
    )
    print("成功等到'Hello World!'文本")
finally:
    time.sleep(2)
    driver.quit()

八、综合实战:自动化登录并爬取数据

现在我们来完成一个完整的实战案例:登录并爬取Bing图片的描述信息。

8.1 项目目标

  • 访问Bing图片搜索
  • 搜索"小黑子"图片
  • 滚动加载更多图片
  • 获取每张图片的标题和描述
  • 保存数据到文件

8.2 完整代码(带详细注释)

"""
Bing图片爬虫 - Selenium新手实战教程
功能:自动搜索并获取Bing图片信息
"""
# 导入所需库
import os
import time
import json
import csv
from datetime import datetime
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager
class BingImageCrawler:
    """Bing图片爬虫类"""
    def __init__(self, headless=False):
        """
        初始化爬虫
        参数:
            headless: 是否使用无头模式(不显示浏览器窗口)
                      默认False显示窗口,适合新手调试
        """
        print("=" * 50)
        print("Bing图片爬虫 - 初始化中...")
        print("=" * 50)
        # 创建保存数据的文件夹
        self.data_dir = "bing_images_data"
        if not os.path.exists(self.data_dir):
            os.makedirs(self.data_dir)
            print(f"创建文件夹: {self.data_dir}")
        # 设置浏览器选项
        options = webdriver.ChromeOptions()
        # 如果设置为无头模式,不显示浏览器窗口
        if headless:
            options.add_argument('--headless')
            print("启用无头模式(不显示浏览器窗口)")
        # 其他配置
        options.add_argument('--no-sandbox')
        options.add_argument('--disable-dev-shm-usage')
        options.add_argument('--disable-gpu')
        options.add_argument('--window-size=1920,580')  # 设置窗口大小
        # 使用DriverManager自动管理浏览器驱动
        print("正在下载/配置Chrome浏览器驱动...")
        service = Service(ChromeDriverManager().install())
        # 启动浏览器
        self.driver = webdriver.Chrome(service=service, options=options)
        # 设置等待时间
        self.wait = WebDriverWait(self.driver, 5)
        print("浏览器启动成功!")
    def search_images(self, keyword, max_images=10):
        """
        搜索图片
        参数:
            keyword: 搜索关键词,如"小黑子"
            max_images: 最大图片数量
        返回:
            图片数据列表
        """
        print(f"\n开始搜索: {keyword}")
        try:
            # 1. 访问Bing图片搜索
            search_url = f"https://cn.bing.com/images/search?q={keyword}"
            self.driver.get(search_url)
            print(f"访问URL: {search_url}")
            # 等待页面加载
            time.sleep(2)
            # 2. 等待搜索框出现(确认页面加载完成)
            try:
                search_box = self.wait.until(
                    EC.presence_of_element_located((By.ID, "sb_form_q"))
                )
                print("页面加载完成")
            except:
                print("页面加载异常,但继续执行...")
            # 3. 滚动加载更多图片
            print("开始滚动加载图片...")
            loaded_count = self._scroll_to_load_images(max_images)
            # 4. 获取图片数据
            print("开始解析图片信息...")
            images_data = self._parse_images(loaded_count)
            if images_data:
                print(f"成功获取 {len(images_data)} 张图片信息")
            else:
                print("未找到图片数据")
            return images_data
        except Exception as e:
            print(f"搜索过程中发生错误: {str(e)}")
            return []
    def _scroll_to_load_images(self, max_images):
        """
        滚动页面加载更多图片
        返回:
            加载的图片数量
        """
        images_count = 0
        scroll_count = 0
        max_scroll = 1  # 最大滚动次数
        while images_count < max_images and scroll_count < max_scroll:
            # 获取当前图片数量
            current_images = self.driver.find_elements(
                By.CSS_SELECTOR, '.imgpt .iusc'
            )
            images_count = len(current_images)
            print(f"  已加载 {images_count} 张图片")
            # 如果已达到目标数量,停止滚动
            if images_count >= max_images:
                break
            # 滚动到底部
            self.driver.execute_script(
                "window.scrollTo(0, document.body.scrollHeight);"
            )
            # 等待新图片加载
            time.sleep(1.5)
            scroll_count += 1
            # 检查是否有"加载更多"按钮
            try:
                load_more = self.driver.find_element(By.CLASS_NAME, 'btn_seemore')
                if load_more.is_displayed():
                    load_more.click()
                    print("  点击'加载更多'按钮")
                    time.sleep(2)
            except:
                pass
        print(f"滚动完成,共加载 {images_count} 张图片")
        return images_count
    def _parse_images(self, max_count):
        """
        解析图片信息
        返回:
            图片数据列表
        """
        images_data = []
        seen_urls = set()  # 用于跟踪已经处理过的图片URL
        # 查找所有图片元素
        image_elements = self.driver.find_elements(
            By.CSS_SELECTOR, '.imgpt .iusc'
        )[:max_count]  # 只取前max_count张
        for idx, img_element in enumerate(image_elements):
            try:
                # 获取图片的m属性(包含图片信息的JSON)
                m_value = img_element.get_attribute('m')
                if m_value:
                    # 解析JSON数据
                    img_info = json.loads(m_value)
                    # 获取图片URL
                    image_url = img_info.get('murl', '')
                    # 检查是否已经处理过这张图片,避免重复
                    if image_url in seen_urls:
                        continue
                    seen_urls.add(image_url)
                    # 提取我们需要的信息
                    image_data = {
                        '序号': len(images_data) + 1,  # 使用实际添加到列表中的顺序编号
                        '标题': img_info.get('t', '无标题'),
                        '描述': img_info.get('desc', '无描述'),
                        '图片URL': image_url,
                        '缩略图URL': img_info.get('turl', ''),
                        '宽度': img_info.get('w', '未知'),
                        '高度': img_info.get('h', '未知'),
                        '文件类型': img_info.get('ity', '未知'),
                        '来源网站': img_info.get('purl', ''),
                        '域名': img_info.get('p', ''),
                        '采集时间': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                    }
                    images_data.append(image_data)
                    # 显示进度
                    if len(images_data) % 10 == 0:
                        print(f"  已解析 {len(images_data)} 张图片...")
            except Exception as e:
                print(f"  解析第 {idx + 1} 张图片时出错: {str(e)}")
                continue
        return images_data
    def save_data(self, images_data, keyword):
        """
        保存数据到文件
        参数:
            images_data: 图片数据列表
            keyword: 搜索关键词(用于命名文件)
        """
        if not images_data:
            print("没有数据可保存")
            return
        # 生成文件名(包含时间戳)
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        base_filename = f"{keyword}_{timestamp}"
        # 1. 保存为JSON文件
        json_file = os.path.join(self.data_dir, f"{base_filename}.json")
        with open(json_file, 'w', encoding='utf-8') as f:
            json.dump(images_data, f, ensure_ascii=False, indent=2)
        # 2. 保存为CSV文件(用Excel可以打开)
        csv_file = os.path.join(self.data_dir, f"{base_filename}.csv")
        with open(csv_file, 'w', encoding='utf-8', newline='') as f:
            # 写入表头
            fieldnames = images_data[0].keys()
            writer = csv.DictWriter(f, fieldnames=fieldnames)
            writer.writeheader()
            # 写入数据
            for img in images_data:
                writer.writerow(img)
        # 3. 保存为简易文本文件(方便查看)
        txt_file = os.path.join(self.data_dir, f"{base_filename}.txt")
        with open(txt_file, 'w', encoding='utf-8') as f:
            f.write(f"搜索关键词: {keyword}\n")
            f.write(f"采集时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
            f.write(f"图片数量: {len(images_data)}\n")
            f.write("=" * 50 + "\n\n")
            for img in images_data:
                f.write(f"图片 {img['序号']}:\n")
                f.write(f"  标题: {img['标题']}\n")
                f.write(f"  描述: {img['描述']}\n")
                f.write(f"  尺寸: {img['宽度']}x{img['高度']}\n")
                f.write(f"  类型: {img['文件类型']}\n")
                f.write(f"  图片URL: {img['图片URL'][:80]}...\n")
                f.write("-" * 30 + "\n")
        print(f"\n数据已保存到:")
        print(f"  JSON文件: {json_file}")
        print(f"  CSV文件: {csv_file}")
        print(f"  文本文件: {txt_file}")
    def display_sample_data(self, images_data, count=10):
        """
        显示示例数据
        参数:
            images_data: 图片数据列表
            count: 显示前几条数据
        """
        if not images_data:
            print("没有数据可显示")
            return
        print(f"\n前 {min(count, len(images_data))} 条数据示例:")
        print("=" * 60)
        for i, img in enumerate(images_data[:count]):
            print(f"{img['序号']}. {img['标题']}")
            print(f"   描述: {img['描述'][:80]}..." if len(img['描述']) > 80 else f"   描述: {img['描述']}")
            print(f"   尺寸: {img['宽度']}x{img['高度']}")
            print(f"   类型: {img['文件类型']}")
            print()
    def close(self):
        """关闭浏览器"""
        self.driver.quit()
        print("浏览器已关闭")
def main():
    """主程序"""
    print("=" * 50)
    print("Bing图片爬虫 - 新手实战教程")
    print("=" * 50)
    # 用户配置
    keyword = "小黑子"  # 可以修改为其他关键词,如"动物"、"汽车"等
    max_images = 10  # 想要获取的图片数量
    headless = False  # 新手建议设为False,可以看到浏览器操作
    # 创建爬虫实例
    crawler = BingImageCrawler(headless=headless)
    try:
        # 搜索图片
        images_data = crawler.search_images(keyword, max_images)
        if images_data:
            # 显示示例数据
            crawler.display_sample_data(images_data, count=3)
            # 保存数据
            crawler.save_data(images_data, keyword)
            # 用户交互
            print("\n" + "=" * 50)
            choice = input("是否查看所有图片标题?(y/n): ").lower()
            if choice == 'y':
                print("\n所有图片标题:")
                for img in images_data:
                    print(f"  {img['序号']:2d}. {img['标题']}")
        else:
            print("未能获取图片数据,请检查网络或重试")
    except KeyboardInterrupt:
        print("\n用户中断操作")
    except Exception as e:
        print(f"\n程序运行出错: {str(e)}")
        print("可能的原因:")
        print("  1. 网络连接问题")
        print("  2. 浏览器驱动问题,请重新运行程序")
        print("  3. 网页结构已变化,需要更新代码")
    finally:
        # 确保浏览器被关闭
        input("\n按回车键退出程序...")
        crawler.close()
# 程序入口
if __name__ == "__main__":
    main()

8.3 代码分步解析

第一步:导入库

import os          # 文件操作
import time        # 时间等待
import json        # JSON数据处理
import csv         # CSV文件处理
from datetime import datetime  # 时间处理

第二步:创建爬虫类

class BingImageCrawler:
    def __init__(self, headless=False):
        # 初始化代码

第三步:搜索图片

def search_images(self, keyword, max_images=10):
    # 访问Bing
    # 等待加载
    # 滚动加载
    # 解析数据

第四步:滚动加载

def _scroll_to_load_images(self, max_images):
    # 不断滚动直到加载足够图片
    # 处理"加载更多"按钮

第五步:解析数据

def _parse_images(self, max_count):
    # 获取每个图片元素的JSON数据
    # 提取标题、描述、URL等信息

第六步:保存数据

def save_data(self, images_data, keyword):
    # 保存为JSON格式
    # 保存为CSV格式(Excel可打开)
    # 保存为文本格式

8.4 如何运行程序

  • 保存代码:将上面的完整代码保存为 bing_crawler.py
  • 运行程序
python bing_crawler.py
  • 你会看到
    • 自动打开Chrome浏览器
    • 访问Bing图片搜索
    • 搜索"小黑子"图片
    • 自动滚动加载更多图片
    • 获取图片信息
    • 保存到文件
    • 在控制台显示结果
  • 查看结果
    • 在程序所在目录会创建 bing_images_data 文件夹
    • 里面包含3个文件:
    • 小黑子_时间戳.json:完整JSON数据
    • 小黑子_时间戳.csv:Excel可打开的表格
    • 小黑子_时间戳.txt:易读的文本格式

8.5 修改配置尝试

你可以修改代码中的配置:

# 修改搜索关键词
keyword = "动物"  # 改为"汽车"、"美食"、"星空"等
# 修改图片数量
max_images = 20   # 想要获取的图片数量
# 修改是否显示浏览器
headless = True   # True不显示浏览器(后台运行),False显示浏览器

九、常见问题与解决方法

问题1:找不到元素(NoSuchElementException)

错误信息

selenium.common.exceptions.NoSuchElementException: Message: no such element

可能原因

  • 元素还没加载出来
  • 元素ID/名称已改变
  • 页面有iframe框架

解决方法

# 1. 增加等待时间
element = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "element_id"))
)
# 2. 使用其他定位方式
# 如果id找不到,试试name、class、xpath等
# 3. 检查是否有iframe
driver.switch_to.frame("iframe_name_or_id")  # 切换到iframe
# 操作元素...
driver.switch_to.default_content()  # 切换回主页面

问题2:元素不可点击(ElementNotInteractableException)

错误信息

ElementNotInteractableException: element not interactable

可能原因

  • 元素被其他元素遮挡
  • 元素不可见(display: none)
  • 元素还没加载完成

解决方法

# 1. 等待元素可点击
element = WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.ID, "element_id"))
)
# 2. 使用JavaScript点击
driver.execute_script("arguments[0].click();", element)
# 3. 滚动到元素位置
driver.execute_script("arguments[0].scrollIntoView();", element)
element.click()

问题3:超时错误(TimeoutException)

错误信息

TimeoutException: Message: timeout waiting for element

解决方法

# 1. 增加等待时间
wait = WebDriverWait(driver, 20)  # 从10秒增加到20秒
# 2. 设置更频繁的检查
wait = WebDriverWait(driver, 10, 0.1)  # 每0.1秒检查一次
# 3. 检查网络或网站状态

问题4:浏览器驱动问题

错误信息

WebDriverException: Message: 'chromedriver' executable needs to be in PATH

解决方法
确保安装了webdriver-manager并正确使用:

# 正确的方式
from webdriver_manager.chrome import ChromeDriverManager
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)

十、学习建议与下一步

10.1 给新手的建议

  • 从简单开始:先运行示例代码,理解每行代码的作用
  • 多练习:修改代码中的参数,观察变化
  • 善用打印:使用print()输出中间结果,方便调试
  • 分步调试:不要一次性写太多代码,写完一小段就测试

10.2 练习题目

  • 基础练习:修改代码,爬取"动物"或"汽车"图片
  • 进阶练习:添加功能,自动下载前5张图片到本地
  • 挑战练习:爬取其他网站,如豆瓣电影、知乎热点等

10.3 下一步学习方向

  • 处理复杂网站:学习处理登录、验证码、Ajax加载
  • 提高效率:学习多线程、分布式爬虫
  • 避免被封:学习使用代理、随机延迟、伪装浏览器
  • 数据存储:学习使用数据库(MySQL、MongoDB)

十一、总结

通过本教程,你已经学会了:

✅ Selenium基础:安装、启动浏览器、基本操作
✅ 元素定位:8种定位方式,找到网页上的任何元素
✅ 元素操作:点击、输入、获取信息、处理表单
✅ 等待机制:显式等待、隐式等待,处理动态加载
✅ 实战项目:完整的Bing图片爬虫,包含数据保存

        Selenium是一个强大的工具,不仅可以用于爬虫,还可以用于自动化测试、自动化办公等。现在你已经有了坚实的基础,可以继续探索更多高级功能了!

        记住:学习编程最好的方式就是动手实践。复制代码运行一次,然后尝试修改它,最后尝试自己从头写一个类似的项目。

        祝你学习顺利!如果有问题,可以随时查阅Selenium官方文档或在线搜索解决方案。

到此这篇关于Python Selenium 从零开始掌握浏览器自动化(超详细新手教程)的文章就介绍到这了,更多相关Python Selenium 浏览器自动化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解Python实现图像分割增强的两种方法

    详解Python实现图像分割增强的两种方法

    图像分割就是把图像分成若干个特定的、具有独特性质的区域并提出感兴趣目标的技术和过程。本文将为大家分享两个用Python实现像分割增强的方法,需要的可以参考一下
    2022-03-03
  • python实现矩阵的示例代码

    python实现矩阵的示例代码

    本文主要介绍了python实现矩阵的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Python 记录日志的灵活性和可配置性介绍

    Python 记录日志的灵活性和可配置性介绍

    这篇文章给大家介绍了关于日志记录库的灵活性和可配置性,目的在于证明它如何设计的,对python 日志记录相关知识感兴趣的朋友跟随脚本之家小编一起学习吧
    2018-02-02
  • Python基础练习之用户登录实现代码分享

    Python基础练习之用户登录实现代码分享

    这篇文章主要介绍了Python基础练习之用户登录实现代码分享,还是比较不错的,这里分享给大家,供需要的朋友参考。
    2017-11-11
  • python实现视频读取和转化图片

    python实现视频读取和转化图片

    今天小编就为大家分享一篇python实现视频读取和转化图片,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-12-12
  • 使用Python去除字符串中某个字符的多种实现方式比较

    使用Python去除字符串中某个字符的多种实现方式比较

    python中字符串是不可变的,所以无法直接删除字符串之间的特定字符,下面这篇文章主要给大家介绍了关于使用Python去除字符串中某个字符的多种实现方式比较的相关资料,需要的朋友可以参考下
    2022-06-06
  • python 基于dlib库的人脸检测的实现

    python 基于dlib库的人脸检测的实现

    这篇文章主要介绍了python 基于dlib库的人脸检测的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • Python利用pydub进行音频处理的完整指南

    Python利用pydub进行音频处理的完整指南

    pydub是一个轻量级的音频处理库,安装方便,使用简单,本文主要为大家详细介绍了Python如何使用处理一个大体积音频文件,感兴趣的小伙伴可以了解下
    2025-09-09
  • 浅析Python中如何处理Socket超时

    浅析Python中如何处理Socket超时

    在网络编程中,Socket是实现网络通信的基础,本文将深入探讨Python中如何处理Socket超时,并提供完整的代码示例和最佳实践,希望对大家有所帮助
    2025-11-11
  • 使用Python的内建模块collections的教程

    使用Python的内建模块collections的教程

    这篇文章主要介绍了使用Python的内建模块collections的教程,示例代码基于Python2.x版本,需要的朋友可以参考下
    2015-04-04

最新评论