PHP 结合正则表达式匹配提取文本,借助图像处理库(如 GD)解析并分离图片,实现图文分离
PHP中实现将一篇文章中的图片与文字分离出来是一个常见需求,尤其适用于内容管理系统、文档处理或数据挖掘场景,以下是详细的技术方案和实现步骤:

核心思路解析
要实现图文分离,本质上需要完成两个任务: 1️⃣ 提取所有嵌入的图像URL/路径(包括本地文件和网络资源) 2️⃣ 清理纯文本内容并保留结构化信息 这可以通过组合使用正则表达式匹配、DOM文档解析以及字符串处理函数来实现,下面将分模块详细说明具体实现方法。
✅ 方法一:基于正则表达式的基础方案(适合简单HTML结构)
function extractImagesAndText($htmlContent) { // 匹配<img>标签及其属性 preg_match_all('/<img[^>]+src=["\']([^"\']+)["\'][^>]>/i', $htmlContent, $matches); $images = $matches[1]; // 获取所有图片地址数组 // 移除所有<img>标签保留文字部分 $plainText = preg_replace('/<img[^>]+>/i', '', $htmlContent); return [ 'images' => array_unique($images), // 去重处理 'text' => strip_tags($plainText) // 进一步清除残余HTML标签 ]; }
⚠️ 局限性说明:此方法仅适用于标准写法的<img>
标签,无法处理以下情况:
- 自闭合标签外的嵌套结构(如带
div
包裹的图片) - Base64编码内联图片(data:image/png;base64...)
- JavaScript动态加载的图片懒加载场景
🔧 进阶方案:使用DOMDocument对象解析(推荐)
通过加载完整的DOM树结构,可以更精准地定位元素节点:
libxml_use_internal_errors(true); // 抑制XML错误警告 $dom = new DOMDocument(); @$dom->loadHTML($htmlContent); // @符号忽略解析错误 // 收集所有img元素 $imageNodes = $dom->getElementsByTagName('img'); foreach ($imageNodes as $node) { $src = $node->getAttribute('src'); if (!empty($src)) { $images[] = htmlspecialchars_decode($src); // 解码实体字符 } } // 创建无图版本的文档片段 $body = $dom->getElementsByTagName('body')->item(0); $fragment = $dom->createDocumentFragment(); while ($body->firstChild) { $child = $body->firstChild; if ($child->nodeName == 'img') { $body->removeChild($child); // 删除图片节点 } else { $fragment->appendChild($child); // 保留其他内容 } } $dom->appendChild($fragment); $cleanedHtml = $dom->saveHTML(); // 生成净化后的HTML $plainText = strip_tags($cleanedHtml);
👉 优势对比:该方法能正确处理复杂嵌套结构,支持相对路径转换,并且可通过XPath进行高级查询(例如//img[contains(@class, 'thumbnail')]
)。

📊 性能优化建议(大文件处理)
当处理超过1MB的大型文档时,建议采用流式处理:
| 策略 | 实现方式 | 适用场景 |
|---------------------|--------------------------------------------------------------------------|------------------------------|
| 分段加载 | 使用file_get_contents()
配合fseek()
逐块读取 | 超长文章避免内存溢出 |
| 延迟解析 | 仅在检测到<img>
区域时激活DOM解析器 | 稀疏分布的图片布局 |
| 缓存机制 | 对已解析过的节点建立哈希表索引 | 重复出现的相同结构元素 |
🛠️ 特殊场景解决方案
1️⃣ Base64内联图片提取:
preg_match_all('/src="data:image\/(\w+);base64,(.?)"/', $htmlContent, $base64Matches); foreach ($base64Matches[0] as $index => $fullMatch) { list(, $mimeType, $encodedData) = explode(';', substr($fullMatch, strpos($fullMatch, 'base64'))); $binaryData = base64_decode($encodedData); // 保存为临时文件示例 file_put_contents("temp_{$index}.{$mimeType}", $binaryData); }
2️⃣ CSS背景图捕获:需要额外解析样式表并关联对应元素 3️⃣ SVG矢量图形处理:将其视为独立资源单独存储
📌 完整工作流示例
class ArticleProcessor { private $originalHtml; private $extractedImages = []; private $processedText = ''; public function __construct($input) { $this->originalHtml = $input; } public function process() { // Step 1: 初始化DOM环境 $this->initDomParser(); // Step 2: 并行执行图文分离任务 $this->findAllImages()->removeImageTags(); // Step 3: 后处理优化 $this->normalizeWhitespace(); $this->repairBrokenLinks(); return [ 'images' => array_values(array_filter($this->extractedImages)), 'text' => $this->getProcessedContent() ]; } private function initDomParser() { // ...同前文DOM实现细节... } private function findAllImages() { // 实现细节参照前述DOM方案 } private function removeImageTags() { // 使用DOM API安全删除节点而非简单替换 } private function normalizeWhitespace() { $this->processedText = preg_replace('/[\r\n]+/', "\n", $this->processedText); } private function repairBrokenLinks() { // 修复因删图导致的段落错位问题 } private function getProcessedContent() { return trim(strip_tags($this->dom->saveHTML())); } }
▶️ 调用示例:

$processor = new ArticleProcessor($articleHtml); list($images, $text) = $processor->process(); print_r($images); // Array ([0] => 'path/to/image1.jpg', ...) echo nl2br($text); // 格式化后的纯文本输出
💡 典型应用场景扩展
- 📚 在线教育平台:自动生成课件大纲时剔除干扰性配图
- 📱 移动端适配:优先加载文字内容再异步请求图片资源
- 🔍 SEO优化工具:分析页面主要内容密度与多媒体占比关系
- 🎨 设计素材库建设:批量归档文章中使用的视觉元素
⚠️ 常见问题排查指南
现象 | 可能原因 | 解决方案 |
---|---|---|
漏掉某些图片 | CSS背景图未被扫描 | 添加对style属性的解析逻辑 |
文本出现乱码 | 字符编码不一致 | 确保使用UTF-8编码保存中间结果 |
相对路径失效 | URL未转换为绝对路径 | 使用basename() +基础目录拼接 |
内存消耗过大 | 超大文件一次性加载 | 改用XMLReader逐节点遍历模式 |
FAQs(相关问答)
Q1: 如果文章中的图片使用的是绝对路径怎么办?是否需要特殊处理?
A: PHP本身不限制路径类型,但建议统一转换为相对路径以便移植,可通过检测是否以协议开头(如http://
)来判断外部资源,本地文件保持相对路径即可,对于混合来源的情况,可以用关联数组分别存储不同类别的资源链接。
Q2: 如何处理表格内的嵌套图片?比如某个单元格里既有文字又有图片的情况?
A: DOM解析方案天然支持这种结构,只要不主动删除父级容器(如<td>
),仅移除其中的<img>
标签,就能保持表格完整性,测试案例表明,该方法能完美保留表格边框、跨列合并等复杂样式