Table of contents

How to Parse HTML Content Using DOMDocument in PHP

PHP's DOMDocument class is a powerful built-in tool for parsing and manipulating HTML and XML documents. It provides a comprehensive set of methods for navigating, extracting, and modifying HTML content, making it an excellent choice for web scraping projects. This guide will walk you through everything you need to know about using DOMDocument for HTML parsing.

What is DOMDocument?

DOMDocument is part of PHP's DOM extension, which implements the W3C Document Object Model (DOM) API. It allows you to load HTML documents and access their elements programmatically. Unlike simple string parsing methods, DOMDocument creates a structured tree representation of the HTML, enabling robust and reliable data extraction.

Basic HTML Parsing with DOMDocument

Here's a simple example of how to load and parse HTML content:

<?php
// Create a new DOMDocument instance
$dom = new DOMDocument();

// Suppress warnings for malformed HTML
libxml_use_internal_errors(true);

// HTML content to parse
$html = '
<html>
<body>
    <div class="container">
        <h1>Welcome to My Website</h1>
        <p>This is a sample paragraph.</p>
        <ul>
            <li>Item 1</li>
            <li>Item 2</li>
            <li>Item 3</li>
        </ul>
    </div>
</body>
</html>
';

// Load HTML content
$dom->loadHTML($html);

// Get the document element
$body = $dom->getElementsByTagName('body')->item(0);
echo $body->textContent;
?>

Loading HTML from Different Sources

Loading from a String

<?php
$dom = new DOMDocument();
libxml_use_internal_errors(true);

$htmlString = '<div><p>Hello World</p></div>';
$dom->loadHTML($htmlString);
?>

Loading from a File

<?php
$dom = new DOMDocument();
libxml_use_internal_errors(true);

// Load from local file
$dom->loadHTMLFile('path/to/file.html');
?>

Loading from URL

<?php
$dom = new DOMDocument();
libxml_use_internal_errors(true);

// Fetch HTML content from URL
$htmlContent = file_get_contents('https://example.com');
$dom->loadHTML($htmlContent);
?>

Extracting Data Using DOMDocument

Finding Elements by Tag Name

<?php
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML($html);

// Get all paragraph elements
$paragraphs = $dom->getElementsByTagName('p');

foreach ($paragraphs as $paragraph) {
    echo $paragraph->textContent . "\n";
}
?>

Using XPath for Advanced Selection

XPath provides powerful querying capabilities similar to CSS selectors:

<?php
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML($html);

// Create XPath object
$xpath = new DOMXPath($dom);

// Find elements by class
$elements = $xpath->query("//div[@class='container']");
foreach ($elements as $element) {
    echo $element->textContent . "\n";
}

// Find elements by ID
$elementById = $xpath->query("//div[@id='header']");

// Find elements with specific text content
$linkWithText = $xpath->query("//a[text()='Click Here']");

// Complex queries
$specificItems = $xpath->query("//ul/li[position() > 1]");
?>

Extracting Attributes

<?php
$dom = new DOMDocument();
libxml_use_internal_errors(true);

$html = '<a href="https://example.com" title="Example Link">Visit Example</a>';
$dom->loadHTML($html);

$links = $dom->getElementsByTagName('a');
foreach ($links as $link) {
    $href = $link->getAttribute('href');
    $title = $link->getAttribute('title');
    $text = $link->textContent;

    echo "URL: $href\n";
    echo "Title: $title\n";
    echo "Text: $text\n";
}
?>

Advanced HTML Parsing Techniques

Parsing Tables

<?php
function parseTable($html) {
    $dom = new DOMDocument();
    libxml_use_internal_errors(true);
    $dom->loadHTML($html);

    $xpath = new DOMXPath($dom);
    $rows = $xpath->query("//table//tr");

    $tableData = [];
    foreach ($rows as $row) {
        $cells = $xpath->query(".//td | .//th", $row);
        $rowData = [];

        foreach ($cells as $cell) {
            $rowData[] = trim($cell->textContent);
        }

        if (!empty($rowData)) {
            $tableData[] = $rowData;
        }
    }

    return $tableData;
}

$tableHtml = '
<table>
    <tr>
        <th>Name</th>
        <th>Age</th>
        <th>City</th>
    </tr>
    <tr>
        <td>John Doe</td>
        <td>30</td>
        <td>New York</td>
    </tr>
    <tr>
        <td>Jane Smith</td>
        <td>25</td>
        <td>Los Angeles</td>
    </tr>
</table>
';

$result = parseTable($tableHtml);
print_r($result);
?>

Parsing Forms

<?php
function parseForm($html) {
    $dom = new DOMDocument();
    libxml_use_internal_errors(true);
    $dom->loadHTML($html);

    $xpath = new DOMXPath($dom);
    $forms = $xpath->query("//form");

    $formData = [];
    foreach ($forms as $form) {
        $formInfo = [
            'action' => $form->getAttribute('action'),
            'method' => $form->getAttribute('method'),
            'fields' => []
        ];

        $inputs = $xpath->query(".//input | .//select | .//textarea", $form);
        foreach ($inputs as $input) {
            $formInfo['fields'][] = [
                'name' => $input->getAttribute('name'),
                'type' => $input->getAttribute('type'),
                'value' => $input->getAttribute('value')
            ];
        }

        $formData[] = $formInfo;
    }

    return $formData;
}
?>

Error Handling and Best Practices

Proper Error Handling

<?php
function safeParseHTML($html) {
    $dom = new DOMDocument();

    // Enable user error handling
    libxml_use_internal_errors(true);
    libxml_clear_errors();

    // Attempt to load HTML
    $result = $dom->loadHTML($html);

    if (!$result) {
        $errors = libxml_get_errors();
        foreach ($errors as $error) {
            echo "XML Error: " . trim($error->message) . "\n";
        }
        libxml_clear_errors();
        return false;
    }

    return $dom;
}
?>

Handling Encoding Issues

<?php
function parseHTMLWithEncoding($html, $encoding = 'UTF-8') {
    $dom = new DOMDocument();
    libxml_use_internal_errors(true);

    // Ensure proper encoding
    $html = mb_convert_encoding($html, 'HTML-ENTITIES', $encoding);

    // Load with explicit encoding declaration
    $dom->loadHTML('<?xml encoding="' . $encoding . '">' . $html);

    return $dom;
}
?>

Real-World Web Scraping Example

Here's a practical example that scrapes product information from an e-commerce page:

<?php
class ProductScraper {
    private $dom;
    private $xpath;

    public function __construct() {
        $this->dom = new DOMDocument();
        libxml_use_internal_errors(true);
    }

    public function scrapeProducts($html) {
        $this->dom->loadHTML($html);
        $this->xpath = new DOMXPath($this->dom);

        $products = [];
        $productNodes = $this->xpath->query("//div[@class='product']");

        foreach ($productNodes as $productNode) {
            $product = [
                'name' => $this->extractText(".//h3[@class='product-name']", $productNode),
                'price' => $this->extractText(".//span[@class='price']", $productNode),
                'image' => $this->extractAttribute(".//img", 'src', $productNode),
                'link' => $this->extractAttribute(".//a", 'href', $productNode),
                'rating' => $this->extractRating($productNode)
            ];

            $products[] = array_filter($product); // Remove empty values
        }

        return $products;
    }

    private function extractText($query, $context = null) {
        $nodes = $this->xpath->query($query, $context);
        return $nodes->length > 0 ? trim($nodes->item(0)->textContent) : null;
    }

    private function extractAttribute($query, $attribute, $context = null) {
        $nodes = $this->xpath->query($query, $context);
        return $nodes->length > 0 ? $nodes->item(0)->getAttribute($attribute) : null;
    }

    private function extractRating($productNode) {
        $ratingNodes = $this->xpath->query(".//div[@class='rating']//span[@class='star filled']", $productNode);
        return $ratingNodes->length;
    }
}

// Usage
$scraper = new ProductScraper();
$html = file_get_contents('https://example-store.com/products');
$products = $scraper->scrapeProducts($html);

foreach ($products as $product) {
    echo "Product: " . $product['name'] . "\n";
    echo "Price: " . $product['price'] . "\n";
    echo "Rating: " . $product['rating'] . " stars\n\n";
}
?>

Performance Optimization Tips

Memory Management

<?php
// Clear DOM to free memory
unset($dom);

// For large documents, consider processing in chunks
function processLargeHTML($html) {
    $dom = new DOMDocument();
    libxml_use_internal_errors(true);

    // Process document
    $dom->loadHTML($html);

    // Extract needed data
    $data = extractData($dom);

    // Clean up
    unset($dom);

    return $data;
}
?>

Caching Parsed Results

<?php
function getCachedHTML($url, $cacheTime = 3600) {
    $cacheFile = 'cache/' . md5($url) . '.html';

    if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < $cacheTime) {
        return file_get_contents($cacheFile);
    }

    $html = file_get_contents($url);
    file_put_contents($cacheFile, $html);

    return $html;
}
?>

Comparing DOMDocument with Other Tools

While DOMDocument is excellent for server-side HTML parsing, modern web applications often require JavaScript execution. For such cases, you might need to consider tools like Puppeteer for handling dynamic content or browser automation for complex interactions.

Common Pitfalls and Solutions

Malformed HTML

<?php
// DOMDocument can handle most malformed HTML
$dom = new DOMDocument();
$dom->recover = true; // Enable recovery mode
$dom->strictErrorChecking = false;
libxml_use_internal_errors(true);
?>

Memory Leaks

<?php
// Always clear errors and unset objects
libxml_clear_errors();
unset($dom, $xpath);
?>

Conclusion

DOMDocument is a robust and versatile tool for parsing HTML content in PHP. Its DOM-based approach provides reliable access to HTML elements and attributes, making it ideal for web scraping projects. By following the examples and best practices outlined in this guide, you can efficiently extract data from HTML documents while avoiding common pitfalls.

Remember to always handle errors gracefully, manage memory usage for large documents, and consider the specific requirements of your scraping project when choosing between DOMDocument and other parsing tools.

Try WebScraping.AI for Your Web Scraping Needs

Looking for a powerful web scraping solution? WebScraping.AI provides an LLM-powered API that combines Chromium JavaScript rendering with rotating proxies for reliable data extraction.

Key Features:

  • AI-powered extraction: Ask questions about web pages or extract structured data fields
  • JavaScript rendering: Full Chromium browser support for dynamic content
  • Rotating proxies: Datacenter and residential proxies from multiple countries
  • Easy integration: Simple REST API with SDKs for Python, Ruby, PHP, and more
  • Reliable & scalable: Built for developers who need consistent results

Getting Started:

Get page content with AI analysis:

curl "https://api.webscraping.ai/ai/question?url=https://example.com&question=What is the main topic?&api_key=YOUR_API_KEY"

Extract structured data:

curl "https://api.webscraping.ai/ai/fields?url=https://example.com&fields[title]=Page title&fields[price]=Product price&api_key=YOUR_API_KEY"

Try in request builder

Related Questions

Get Started Now

WebScraping.AI provides rotating proxies, Chromium rendering and built-in HTML parser for web scraping
Icon