import html
import json
import logging
import re
from services.dates import parse_datetime
logger = logging.getLogger(__name__)
# JSON-LD structured data blocks (schema.org) that most news sites emit for SEO —
# and Next.js's serialized page state. In both cases the headlines (and dates)
# are already present in the HTML, so no JavaScript execution is required.
_JSON_LD_RE = re.compile(
r"""""",
re.IGNORECASE | re.DOTALL,
)
_NEXT_DATA_RE = re.compile(
r"""""",
re.IGNORECASE | re.DOTALL,
)
_ARTICLE_TYPES = {
'newsarticle', 'article', 'report', 'analysisnewsarticle',
'opinionnewsarticle', 'reviewnewsarticle', 'blogposting',
'liveblogposting', 'backgroundnewsarticle', 'reportagenewsarticle',
}
_URL_KEYS = ('url', 'href', 'link', 'canonicalUrl', 'slug', 'uri')
def _has_url(obj):
for key in _URL_KEYS:
value = obj.get(key)
if isinstance(value, str) and value.strip():
return True
return False
def _schema_type(obj):
"""Last path segment of an object's ``@type``, lowercased (handles URLs)."""
if not isinstance(obj, dict):
return ''
t = obj.get('@type')
if isinstance(t, list):
t = t[0] if t else None
if not isinstance(t, str):
return ''
return t.strip().rstrip('/').rsplit('/', 1)[-1].lower()
def _iter_json_scripts(content):
"""Yield unescaped JSON bodies of JSON-LD and Next.js SSR ``