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>标签,就能保持表格完整性,测试案例表明,该方法能完美保留表格边框、跨列合并等复杂样式
