Files
philandClaude 25086fc01b Add comprehensive RSS scraper implementation with security and testing
- Modular architecture with separate modules for scraping, parsing, security, validation, and caching
- Comprehensive security measures including HTML sanitization, rate limiting, and input validation
- Robust error handling with custom exceptions and retry logic
- HTTP caching with ETags and Last-Modified headers for efficiency
- Pre-compiled regex patterns for improved performance
- Comprehensive test suite with 66 tests covering all major functionality
- Docker support for containerized deployment
- Configuration management with environment variable support
- Working parser that successfully extracts 32 articles from Warhammer Community

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-06 09:15:06 -06:00

59 lines
2.0 KiB
Python

"""RSS feed generation functionality."""
import os
import logging
from typing import List, Dict, Any
from feedgen.feed import FeedGenerator
from .config import Config
from .validation import validate_output_path
from .exceptions import FileOperationError
logger = logging.getLogger(__name__)
def generate_rss_feed(articles: List[Dict[str, Any]], feed_url: str) -> bytes:
"""Generate RSS feed from articles list."""
logger.info(f"Generating RSS feed for {len(articles)} articles")
# Initialize the RSS feed generator
fg = FeedGenerator()
fg.title(Config.FEED_TITLE)
fg.link(href=feed_url)
fg.description(Config.FEED_DESCRIPTION)
# Add the sorted articles to the RSS feed
for article in articles:
fe = fg.add_entry()
fe.title(article['title'])
fe.link(href=article['link'])
fe.pubDate(article['date'])
# Generate the RSS feed
return fg.rss_str(pretty=True)
def save_rss_feed(rss_content: bytes, output_dir: str) -> str:
"""Save RSS feed to file."""
try:
rss_path = validate_output_path(os.path.join(output_dir, Config.RSS_FILENAME), output_dir)
with open(rss_path, 'wb') as f:
f.write(rss_content)
logger.info(f'RSS feed saved to: {rss_path}')
return rss_path
except Exception as e:
raise FileOperationError(f"Failed to save RSS feed: {e}")
def save_debug_html(html_content: str, output_dir: str) -> None:
"""Save HTML content for debugging purposes."""
try:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_content, 'html.parser')
html_path = validate_output_path(os.path.join(output_dir, Config.DEBUG_HTML_FILENAME), output_dir)
with open(html_path, 'w', encoding='utf-8') as f:
f.write(soup.prettify())
logger.info(f'Debug HTML saved to: {html_path}')
except Exception as e:
# HTML saving is not critical, just log the error
logger.warning(f"Failed to save debug HTML: {e}")