j0k3r/php-readability
Extracts the main article content and title from messy web pages in PHP. Improved fork of php-readability with tests, namespacing, and optional HTML cleanup via Tidy (or libxml). Supports PSR-3 logging for debugging.
Installation
composer require j0k3r/php-readability
Add the service provider to config/app.php (if not auto-discovered):
'providers' => [
// ...
J0k3r\Readability\ReadabilityServiceProvider::class,
],
Basic Usage Extract readable content from a URL or HTML string:
use J0k3r\Readability\Readability;
// From URL
$readability = new Readability();
$article = $readability->getArticle('https://example.com/blog-post');
// From HTML string
$article = $readability->parse($htmlString);
First Use Case Fetch and clean a blog post for a news aggregator:
$url = 'https://example.com/news';
$article = Readability::fromUrl($url);
$cleanTitle = $article->getTitle();
$cleanContent = $article->getContent();
URL Processing Pipeline
$urls = ['url1', 'url2', 'url3'];
$articles = collect($urls)->map(fn($url) => Readability::fromUrl($url));
HTML Sanitization
Use getContent() or getExcerpt() for cleaned output:
$content = $article->getContent(); // Full article
$excerpt = $article->getExcerpt(); // First paragraph
Metadata Extraction
$title = $article->getTitle();
$date = $article->getDate(); // Parsed publication date
$images = $article->getImages(); // Array of featured images
Integration with Laravel
dispatch(new ProcessReadabilityJob($url));
$article = Cache::remember("readability:{$url}", now()->addHour(), fn() =>
Readability::fromUrl($url)
);
Custom Article Processing
Extend the Article class:
class CustomArticle extends \J0k3r\Readability\Article {
public function getAuthor() {
return $this->getMetaData('author') ?? 'Unknown';
}
}
URL Whitelisting
if (!str_contains($url, ['html', 'php'])) {
throw new \InvalidArgumentException('Unsupported URL type');
}
Dynamic Content
Encoding Issues
$article->setContent(mb_convert_encoding($article->getContent(), 'UTF-8'));
Performance
setMaxArticleLength():
$readability->setMaxArticleLength(5000); // Limit to 5KB
$readability->setDebug(true);
$rawHtml = $readability->getRawContent();
Custom Rules
Override default heuristics in config/readability.php:
'rules' => [
'class' => ['custom-class', 'another-selector'],
],
Language Support
$readability->setLanguage('es'); // Spanish
Image Handling
$readability->setExtractImages(false);
Pre/Post-Processing Hook into the pipeline:
$readability->on('beforeParse', function($readability) {
$readability->setContent(str_replace('ads', '', $readability->getContent()));
});
Custom Article Class
Override the default Article class in the service provider:
$this->app->bind(\J0k3r\Readability\Article::class, CustomArticle::class);
API Wrapper Create a facade for cleaner syntax:
// app/Facades/Readability.php
public static function article($url) {
return new Readability()->getArticle($url);
}
How can I help you explore Laravel packages today?