目录
[2.1 安装Python(如果你还没有)](#2.1 安装Python(如果你还没有))
[2.2 安装Selenium库](#2.2 安装Selenium库)
[2.3 安装浏览器驱动管理工具](#2.3 安装浏览器驱动管理工具)
[4.1 常用操作汇总表](#4.1 常用操作汇总表)
[4.2 详细操作示例](#4.2 详细操作示例)
[5.1 8种定位方式(从易到难)](#5.1 8种定位方式(从易到难))
[5.2 元素定位完整示例](#5.2 元素定位完整示例)
[5.3 元素定位选择建议](#5.3 元素定位选择建议)
[6.1 输入文本](#6.1 输入文本)
[6.2 点击操作](#6.2 点击操作)
[6.3 获取元素信息](#6.3 获取元素信息)
[6.4 处理下拉框](#6.4 处理下拉框)
[6.5 处理复选框和单选框](#6.5 处理复选框和单选框)
[7.1 强制等待(不推荐)](#7.1 强制等待(不推荐))
[7.2 隐式等待(全局等待)](#7.2 隐式等待(全局等待))
[7.3 显式等待(推荐)](#7.3 显式等待(推荐))
[7.4 常用等待条件](#7.4 常用等待条件)
[7.5 等待机制完整示例](#7.5 等待机制完整示例)
[8.1 项目目标](#8.1 项目目标)
[8.2 完整代码(带详细注释)](#8.2 完整代码(带详细注释))
[8.3 代码分步解析](#8.3 代码分步解析)
[8.4 如何运行程序](#8.4 如何运行程序)
[8.5 修改配置尝试](#8.5 修改配置尝试)
问题1:找不到元素(NoSuchElementException)
问题2:元素不可点击(ElementNotInteractableException)
[10.1 给新手的建议](#10.1 给新手的建议)
[10.2 练习题目](#10.2 练习题目)
[10.3 下一步学习方向](#10.3 下一步学习方向)
一、写给新手的话
如果你是第一次接触Selenium,可能会觉得有些复杂。别担心!这篇教程将从最基础的安装开始,一步步带你掌握Selenium的每个细节。我会用最简单的语言和大量示例代码,让你快速上手。
二、准备工作:环境搭建
2.1 安装Python(如果你还没有)
首先确认你安装了Python。打开命令行(Windows按Win+R,输入cmd;Mac打开终端),输入:
bash
python --version
如果看到类似 Python 3.12.7 这样的版本号,说明已安装。如果没有,去Python官网下载安装。
2.2 安装Selenium库
在命令行中输入:
pip install selenium
如果下载慢,可以使用国内镜像:
bash
pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple
2.3 安装浏览器驱动管理工具
传统方式需要手动下载浏览器驱动,但现在有更简单的方法:
pip install webdriver-manager
这个工具会自动帮你下载和配置浏览器驱动。
三、第一个Selenium程序:打开百度
让我们从一个最简单的例子开始:
python
# 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.title |
title = driver.title |
| 获取当前URL | driver.current_url |
url = 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 详细操作示例
python
# 基础操作示例代码
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定位(最简单)
html
<input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off">
python
# HTML元素有id属性时使用(id通常是唯一的)
search_input = driver.find_element("id", "kw")
# 或者
search_input = driver.find_element_by_id("kw")
方式2:通过NAME定位
html
<input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off">
python
python
# name属性可能不唯一,但经常使用
search_input = driver.find_element("name", "wd")
# 或者
search_input = driver.find_element_by_name("wd")
方式3:通过CLASS_NAME定位
html
<input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off">
python
# class可能不唯一,一个元素可能有多个class
search_input = driver.find_element("class name", "s_ipt")
# 或者
search_input = driver.find_element_by_class_name("s_ipt")
方式4:通过TAG_NAME定位
html
<div>内容</div>
<input type="text">
<a href="...">链接</a>
python
# 通过标签名查找(最不精确,通常用来查找多个元素)
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定位
html
<a href="https://news.baidu.com">新闻</a>
<a href="https://www.hao123.com">hao123</a>
python
# 精确匹配链接文本
news_link = driver.find_element("link text", "新闻")
hao123_link = driver.find_element("link text", "hao123")
方式6:通过PARTIAL_LINK_TEXT定位
html
<a href="https://news.baidu.com">百度新闻</a>
<a href="https://www.hao123.com">hao123网址导航</a>
python
# 部分匹配链接文本(包含即可)
baidu_link = driver.find_element("partial link text", "百度") # 匹配"百度新闻"
hao123_link = driver.find_element("partial link text", "hao123") # 匹配"hao123网址导航"
方式7:通过CSS_SELECTOR定位(推荐)
CSS选择器功能强大,类似于CSS样式选择元素:
python
# 通过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就像文件路径,可以定位到任何元素:
python
# 绝对路径(从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 元素定位完整示例
python
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 元素定位选择建议
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| 元素有id | By.ID | 最简单、最快、唯一 |
| 元素有name | By.NAME | 简单常用 |
| 元素有class | By.CLASS_NAME | 简单,但class可能重复 |
| 查找多个同类元素 | By.TAG_NAME | 查找所有同类元素 |
| 精确文本链接 | By.LINK_TEXT | 链接文本不变时使用 |
| 模糊文本链接 | By.PARTIAL_LINK_TEXT | 链接文本部分匹配 |
| 复杂选择 | By.CSS_SELECTOR | 功能强大,语法简洁 |
| 最复杂情况 | By.XPATH | 功能最强大,但稍慢 |
六、元素操作:与网页交互
找到元素后,我们需要与之交互。下面是常用的操作:
6.1 输入文本
python
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 点击操作
python
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 获取元素信息
python
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 处理下拉框
python
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 处理复选框和单选框
python
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 强制等待(不推荐)
python
import time
time.sleep(5) # 强制等待5秒,不管元素是否加载完成
缺点:如果元素提前加载完成,也要等;如果超时未加载,会报错。
7.2 隐式等待(全局等待)
python
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 显式等待(推荐)
python
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 等待机制完整示例
python
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 完整代码(带详细注释)
python
"""
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 代码分步解析
第一步:导入库
python
import os # 文件操作
import time # 时间等待
import json # JSON数据处理
import csv # CSV文件处理
from datetime import datetime # 时间处理
第二步:创建爬虫类
python
class BingImageCrawler:
def __init__(self, headless=False):
# 初始化代码
第三步:搜索图片
python
def search_images(self, keyword, max_images=10):
# 访问Bing
# 等待加载
# 滚动加载
# 解析数据
第四步:滚动加载
python
def _scroll_to_load_images(self, max_images):
# 不断滚动直到加载足够图片
# 处理"加载更多"按钮
第五步:解析数据
python
def _parse_images(self, max_count):
# 获取每个图片元素的JSON数据
# 提取标题、描述、URL等信息
第六步:保存数据
python
def save_data(self, images_data, keyword):
# 保存为JSON格式
# 保存为CSV格式(Excel可打开)
# 保存为文本格式
8.4 如何运行程序
-
保存代码 :将上面的完整代码保存为
bing_crawler.py -
运行程序:
python
python bing_crawler.py
-
你会看到:
-
自动打开Chrome浏览器
-
访问Bing图片搜索
-
搜索"
小黑子"图片 -
自动滚动加载更多图片
-
获取图片信息
-
保存到文件
-
在控制台显示结果
-
-
查看结果:
-
在程序所在目录会创建
bing_images_data文件夹 -
里面包含3个文件:
-
小黑子_时间戳.json:完整JSON数据 -
小黑子_时间戳.csv:Excel可打开的表格 -
小黑子_时间戳.txt:易读的文本格式
-
-
8.5 修改配置尝试
你可以修改代码中的配置:
python
# 修改搜索关键词
keyword = "动物" # 改为"汽车"、"美食"、"星空"等
# 修改图片数量
max_images = 20 # 想要获取的图片数量
# 修改是否显示浏览器
headless = True # True不显示浏览器(后台运行),False显示浏览器
九、常见问题与解决方法
问题1:找不到元素(NoSuchElementException)
错误信息:
python
selenium.common.exceptions.NoSuchElementException: Message: no such element
可能原因:
-
元素还没加载出来
-
元素ID/名称已改变
-
页面有iframe框架
解决方法:
python
# 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)
错误信息:
python
ElementNotInteractableException: element not interactable
可能原因:
-
元素被其他元素遮挡
-
元素不可见(display: none)
-
元素还没加载完成
解决方法:
python
# 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)
错误信息:
python
TimeoutException: Message: timeout waiting for element
解决方法:
python
# 1. 增加等待时间
wait = WebDriverWait(driver, 20) # 从10秒增加到20秒
# 2. 设置更频繁的检查
wait = WebDriverWait(driver, 10, 0.1) # 每0.1秒检查一次
# 3. 检查网络或网站状态
问题4:浏览器驱动问题
错误信息:
python
WebDriverException: Message: 'chromedriver' executable needs to be in PATH
解决方法 :
确保安装了webdriver-manager并正确使用:
python
# 正确的方式
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官方文档或在线搜索解决方案。