
Security News
Socket Releases Free Certified Patches for Nuxt Security Vulnerabilities
Socket releases free Certified Patches for high-severity Nuxt vulnerabilities, including server-side remote code execution through server island props.
@tyronerossjr/blog-scraper
Advanced tools
Powerful web scraping SDK for extracting blog articles and content. No LLM required.
Powerful web scraping SDK for extracting blog articles and content. No LLM required.
✨ No LLM needed - Uses Mozilla Readability (92.2% F1 score) for content extraction 🎯 3-tier filtering - URL patterns → content validation → quality scoring ⚡ Fast - Extracts articles in 2-5 seconds 🔧 Modular - Use high-level API or individual components 📦 Zero config - Works out of the box 🌐 Multi-source - RSS feeds, sitemaps, and HTML pages
npm install @tyronerossjr/blog-scraper
import { scrape } from '@tyronerossjr/blog-scraper';
// Simple usage - scrape a blog
const result = await scrape('https://example.com/blog');
console.log(`Found ${result.articles.length} articles`);
console.log(`Processing time: ${result.processingTime}ms`);
// Access articles
result.articles.forEach(article => {
console.log(article.title);
console.log(article.url);
console.log(article.fullContentMarkdown); // Markdown format
console.log(article.qualityScore); // 0-1 quality score
});
scrape(url, options?)Extract articles from a URL with automatic source detection.
import { scrape } from '@tyronerossjr/blog-scraper';
const result = await scrape('https://example.com', {
// Optional configuration
sourceType: 'auto', // 'auto' | 'rss' | 'sitemap' | 'html'
maxArticles: 50, // Maximum articles to return
extractFullContent: true, // Extract full article content
denyPaths: ['/about', '/contact'], // URL patterns to exclude
qualityThreshold: 0.6 // Minimum quality score (0-1)
});
Returns:
{
url: string;
detectedType: 'rss' | 'sitemap' | 'html';
confidence: 'high' | 'medium' | 'low';
articles: ScrapedArticle[];
extractionStats: {
attempted: number;
successful: number;
failed: number;
filtered: number;
totalDiscovered: number;
afterDenyFilter: number;
afterContentValidation: number;
afterQualityFilter: number;
};
processingTime: number;
errors: string[];
timestamp: string;
}
quickScrape(url)Fast URL-only extraction (no full content).
import { quickScrape } from '@tyroneross/blog-scraper';
const urls = await quickScrape('https://example.com/blog');
// Returns: ['url1', 'url2', 'url3', ...]
Use individual components for granular control.
import { ContentExtractor } from '@tyroneross/blog-scraper';
const extractor = new ContentExtractor();
const content = await extractor.extractContent('https://example.com/article');
console.log(content.title);
console.log(content.textContent);
console.log(content.wordCount);
console.log(content.readingTime);
import { calculateArticleQualityScore, getQualityBreakdown } from '@tyroneross/blog-scraper';
const score = calculateArticleQualityScore(extractedContent);
console.log(`Quality score: ${score}`); // 0-1
// Get detailed breakdown
const breakdown = getQualityBreakdown(extractedContent);
console.log(breakdown);
// {
// contentValidation: 0.6,
// publishedDate: 0.12,
// author: 0.08,
// schema: 0.08,
// readingTime: 0.12,
// total: 1.0,
// passesThreshold: true
// }
import { calculateArticleQualityScore } from '@tyroneross/blog-scraper';
const score = calculateArticleQualityScore(content, {
contentWeight: 0.8, // Increase content importance
dateWeight: 0.05, // Decrease date importance
authorWeight: 0.05,
schemaWeight: 0.05,
readingTimeWeight: 0.05,
threshold: 0.7 // Stricter threshold
});
import { RSSDiscovery } from '@tyroneross/blog-scraper';
const discovery = new RSSDiscovery();
const feeds = await discovery.discoverFeeds('https://example.com');
feeds.forEach(feed => {
console.log(feed.url);
console.log(feed.title);
console.log(feed.confidence); // 0-1
});
import { SitemapParser } from '@tyroneross/blog-scraper';
const parser = new SitemapParser();
const entries = await parser.parseSitemap('https://example.com/sitemap.xml');
entries.forEach(entry => {
console.log(entry.url);
console.log(entry.lastmod);
console.log(entry.priority);
});
import { HTMLScraper } from '@tyroneross/blog-scraper';
const scraper = new HTMLScraper();
const articles = await scraper.extractFromPage('https://example.com/blog', {
selectors: {
articleLinks: ['article a', '.post-link'],
titleSelectors: ['h1', '.post-title'],
dateSelectors: ['time', '.published-date']
},
filters: {
minTitleLength: 10,
maxTitleLength: 200
}
});
import { ScrapingRateLimiter } from '@tyroneross/blog-scraper';
// Create custom rate limiter
const limiter = new ScrapingRateLimiter({
maxConcurrent: 5,
minTime: 1000 // 1 second between requests
});
// Use in your scraping logic
await limiter.execute('example.com', async () => {
// Your scraping code here
});
import { CircuitBreaker } from '@tyroneross/blog-scraper';
const breaker = new CircuitBreaker('my-operation', {
failureThreshold: 5,
resetTimeout: 60000 // 1 minute
});
const result = await breaker.execute(async () => {
// Your operation here
});
import { scrape } from '@tyronerossjr/blog-scraper';
const result = await scrape('https://techcrunch.com', {
denyPaths: [
'/',
'/about',
'/contact',
'/tag/*', // Exclude all tag pages
'/author/*' // Exclude all author pages
],
maxArticles: 20
});
import {
SourceOrchestrator,
ContentExtractor,
calculateArticleQualityScore
} from '@tyroneross/blog-scraper';
// Step 1: Discover articles
const orchestrator = new SourceOrchestrator();
const discovered = await orchestrator.processSource('https://example.com', {
sourceType: 'auto'
});
// Step 2: Extract content
const extractor = new ContentExtractor();
const extracted = await Promise.all(
discovered.articles
.slice(0, 10)
.map(a => extractor.extractContent(a.url))
);
// Step 3: Score and filter
const scored = extracted
.filter(Boolean)
.map(content => ({
content,
score: calculateArticleQualityScore(content!)
}))
.filter(item => item.score >= 0.7);
console.log(`Found ${scored.length} high-quality articles`);
import { scrape } from '@tyronerossjr/blog-scraper';
const result = await scrape('https://example.com', {
sourceType: 'rss', // Only use RSS feeds
extractFullContent: false, // Don't extract full content
maxArticles: 100
});
Tier 1: URL Deny Patterns
Tier 2: Content Validation
Tier 3: Quality Scoring
Full TypeScript support with exported types:
import type {
ScrapedArticle,
ScraperTestResult,
ScrapeOptions,
ExtractedContent,
QualityScoreConfig
} from '@tyroneross/blog-scraper';
MIT © Tyrone Ross
Contributions welcome! Please open an issue or PR.
Built with ❤️ using Mozilla Readability
FAQs
Powerful web scraping SDK for extracting blog articles and content. No LLM required.
We found that @tyronerossjr/blog-scraper demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket releases free Certified Patches for high-severity Nuxt vulnerabilities, including server-side remote code execution through server island props.

Security News
An open letter signed by 50 companies, from NVIDIA and Microsoft to Mistral and Hugging Face, urges Washington not to restrict open weight AI.

Security News
/Research
A fake corepack.org site is impersonating the Node.js tool and delivers an infostealer and proxyware to developers who download it.