PHP 网页正文提取

wen PHP项目 4

本文目录导读:

PHP 网页正文提取

  1. 方案1:使用第三方库(推荐)
  2. 方案2:使用正则表达式提取
  3. 方案3:使用DOMDocument和XPath
  4. 方案4:综合使用的完整示例
  5. 注意事项
  6. 推荐库列表

我来提供几种PHP网页正文提取的方案,从简单到复杂:

方案1:使用第三方库(推荐)

使用 html2text

composer require html2text/html2text
<?php
require 'vendor/autoload.php';
use Html2Text\Html2Text;
$html = file_get_contents('https://example.com/article');
$converter = new Html2Text($html);
echo $converter->getText();

使用 goutte (基于Symfony DomCrawler)

composer require fabpot/goutte
<?php
require 'vendor/autoload.php';
use Goutte\Client;
$client = new Client();
$crawler = $client->request('GET', 'https://example.com/article');
内容
$content = $crawler->filter('article')->first()->text();
echo $content;

方案2:使用正则表达式提取

<?php
class ContentExtractor {
    private $html;
    public function __construct($html) {
        $this->html = $html;
    }
    /**
     * 简单正文提取
     */
    public function extractSimple() {
        // 去除script和style标签
        $html = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $this->html);
        $html = preg_replace('/<style\b[^>]*>(.*?)<\/style>/is', '', $html);
        // 去除注释
        $html = preg_replace('/<!--(.*?)-->/is', '', $html);
        // 去除HTML标签
        $text = strip_tags($html);
        // 处理空白字符
        $text = preg_replace('/\s+/', ' ', $text);
        $text = trim($text);
        return $text;
    }
    /**
     * 高级正文提取(基于常见正文标签)
     */
    public function extractAdvanced() {
        $patterns = [
            '/<article[^>]*>(.*?)<\/article>/is',
            '/<div[^>]*class=["\']article["\'][^>]*>(.*?)<\/div>/is',
            '/<div[^>]*id=["\']content["\'][^>]*>(.*?)<\/div>/is',
            '/<div[^>]*class=["\']content["\'][^>]*>(.*?)<\/div>/is',
            '/<div[^>]*class=["\']post["\'][^>]*>(.*?)<\/div>/is',
        ];
        foreach ($patterns as $pattern) {
            if (preg_match($pattern, $this->html, $matches)) {
                $content = $this->cleanHtml($matches[1]);
                return $content;
            }
        }
        return $this->extractSimple();
    }
    private function cleanHtml($html) {
        $html = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $html);
        $html = preg_replace('/<style\b[^>]*>(.*?)<\/style>/is', '', $html);
        $html = preg_replace('/<!--(.*?)-->/is', '', $html);
        $text = strip_tags($html);
        $text = preg_replace('/\s+/', ' ', $text);
        return trim($text);
    }
}
// 使用示例
$html = file_get_contents('your_html_file.html');
$extractor = new ContentExtractor($html);
$content = $extractor->extractAdvanced();
echo $content;

方案3:使用DOMDocument和XPath

<?php
class DOMContentExtractor {
    private $dom;
    private $xpath;
    public function __construct($html) {
        $this->dom = new DOMDocument();
        // 使用libxml来避免HTML5标签警告
        libxml_use_internal_errors(true);
        $this->dom->loadHTML('<?xml encoding="UTF-8">' . $html, LIBXML_NOERROR);
        libxml_clear_errors();
        $this->xpath = new DOMXPath($this->dom);
    }
    /**
     * 根据常用选择器提取正文
     */
    public function extractBySelectors() {
        $selectors = [
            '//article',
            '//*[contains(@class, "article")]',
            '//*[contains(@class, "content")]',
            '//*[contains(@class, "post")]',
            '//div[@id="content"]',
        ];
        foreach ($selectors as $selector) {
            $nodes = $this->xpath->query($selector);
            if ($nodes->length > 0) {
                return $this->getTextContent($nodes->item(0));
            }
        }
        return null;
    }
    /**
     * 智能提取:根据文本密度
     */
    public function extractSmart() {
        $blocks = $this->xpath->query('//div | //p | //article | //section');
        $bestBlock = null;
        $maxScore = 0;
        foreach ($blocks as $block) {
            $text = $block->textContent;
            $score = $this->calculateTextDensity($text);
            if ($score > $maxScore) {
                $maxScore = $score;
                $bestBlock = $block;
            }
        }
        if ($bestBlock) {
            return $this->getTextContent($bestBlock);
        }
        return null;
    }
    private function calculateTextDensity($text) {
        // 文本密度计算
        $text = trim(preg_replace('/\s+/', ' ', $text));
        $chars = mb_strlen($text);
        $links = substr_count($text, '<a');
        // 简单的文本密度评分
        return $chars - ($links * 10);
    }
    private function getTextContent(DOMNode $node) {
        $text = $node->textContent;
        return trim(preg_replace('/\s+/', ' ', $text));
    }
}
// 使用示例
$html = file_get_contents('your_html_file.html');
$extractor = new DOMContentExtractor($html);
$content = $extractor->extractSmart();
echo $content;

方案4:综合使用的完整示例

<?php
require 'vendor/autoload.php';
use DiDom\Document;
class ArticleExtractor {
    private $url;
    private $content;
    public function __construct($url) {
        $this->url = $url;
    }
    public function fetch() {
        // 获取HTML
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $this->url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');
        $html = curl_exec($ch);
        curl_close($ch);
        // 使用DiDom解析
        $document = new Document($html);
        return $this->extractContent($document);
    }
    private function extractContent(Document $document) {
        $selectors = [
            'article',
            '.article',
            '.content',
            '.post',
            '#content',
            '.main-content'
        ];
        foreach ($selectors as $selector) {
            $elements = $document->find($selector);
            if (count($elements) > 0) {
                $this->content = $elements[0]->text();
                return $this->content;
            }
        }
        return null;
    }
    public function getTitle(Document $document) {
        $titleElement = $document->find('title');
        if (count($titleElement) > 0) {
            return $titleElement[0]->text();
        }
        return null;
    }
}
// 使用
try {
    $extractor = new ArticleExtractor('https://example.com/article');
    $contents = $extractor->fetch();
    echo $contents;
} catch (Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

注意事项

  1. 编码问题:确保处理UTF-8编码
  2. 链接检测:可以过滤掉包含大量链接的区块
  3. 图片处理:可以选择保留或移除图片
  4. 性能优化:对大HTML文件使用流式处理
  5. 反爬虫:注意网站的使用条款

推荐库列表

  • Html2Text:简单转换
  • DOMDocument + XPath:PHP内置,灵活
  • Goutte:Web爬虫和测试
  • DiDom:简单易用的DOM操作
  • Readability.php:类似Mozilla的Readability算法

选择哪个方案取决于你的具体需求,最简单的场景可以用正则表达式方案,复杂的抽取建议使用DOMDocument或第三方库。

抱歉,评论功能暂时关闭!