File size: 5,288 Bytes
b458f3d 19f9d48 b458f3d a88e274 4ec2569 a88e274 4ec2569 b458f3d 4ec2569 b458f3d 4ec2569 b458f3d 4ec2569 a88e274 4ec2569 a88e274 4ec2569 b3f7149 4ec2569 b3f7149 4ec2569 a88e274 4ec2569 a88e274 4ec2569 a88e274 4ec2569 a88e274 4ec2569 19f9d48 4ec2569 19f9d48 14aaae8 b458f3d 14aaae8 c1d121b 14aaae8 b458f3d c1d121b 14aaae8 b458f3d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
class ImageAnalyzer:
def analyze_site(self, site_data):
"""
Analyzes the crawled site data for missing ALT text.
:param site_data: Dict { page_url: [image_dicts] }
:return: Dict containing summary and detailed report.
"""
total_images = 0
total_missing_alt = 0
total_poor_quality = 0 # Track all poor quality images
total_short_alt_legacy = 0 # Track only strictly short ones
pages_report = []
# Compile regex for filename patterns
import re
# Pattern 1: Common Camera Prefixes (e.g., DSC_001, IMG_1234, Screenshot-1)
prefix_pattern = re.compile(r'^(dsc|img|pic|screenshot|photo)[\-_]?\d+', re.IGNORECASE)
# Pattern 2: General Slug + Number (e.g., product-12345, item_01) - enforces no spaces
slug_pattern = re.compile(r'^[a-z0-9\-_]+[-_]\d+$', re.IGNORECASE)
for page_url, images in site_data.items():
missing_images = []
poor_quality_images = []
for img in images:
total_images += 1
alt_text = img.get('alt')
# 1. Strictly Missing
if not alt_text or alt_text.strip() == "":
missing_images.append(img['src'])
total_missing_alt += 1
continue # Skip further checks if missing
cleaned_alt = alt_text.strip()
lower_alt = cleaned_alt.lower()
word_count = len(cleaned_alt.split())
is_poor = False
reason = ""
# 2. Advanced Poor Quality Checks
# A) File Name / Extension Check (Highest Priority)
if any(lower_alt.endswith(ext) for ext in ['.jpg', '.png', '.jpeg', '.webp', '.gif', '.svg']):
is_poor = True
reason = "Filename extension detected"
elif prefix_pattern.search(cleaned_alt):
is_poor = True
reason = "Filename pattern detected (prefix)"
elif slug_pattern.match(cleaned_alt):
is_poor = True
reason = "Filename pattern detected (slug)"
# B) Generic / Filler Text (Smart check)
# Flag if alt equals or contains generic terms.
# Exception: "Brand Name Logo" (usually > 2 words or specific)
# If word count is low (< 3) AND contains a generic term, it's likely poor.
# If it is EXACTLY a generic term, it is definitely poor.
generic_terms = {'image', 'photo', 'picture', 'logo', 'banner', 'icon', 'thumbnail', 'placeholder', 'img', 'spacer'}
if not is_poor:
if lower_alt in generic_terms:
# Exact match found (e.g., "logo", "image") -> Bad
is_poor = True
reason = "Generic filler text"
else:
# Check partial match for short phrases (likely "My Logo", "Chart Image")
# If phrase is long (>= 3 words), it might be descriptive enough (e.g., "Eminent Tactiles Logo")
# So we only flag partial generic matches if word count is small (< 3)
has_generic = any(term in lower_alt.split() for term in generic_terms)
if has_generic and word_count < 3:
is_poor = True
reason = "Generic filler text (partial match)"
# C) Too Short / Sparse (Lowest Priority)
if not is_poor:
if len(cleaned_alt) < 5:
is_poor = True
reason = "Too short (< 5 chars)"
elif word_count < 2:
# Single word check
is_poor = True
reason = "Too few words (needs >= 2)"
if is_poor:
# Store with reason
poor_quality_images.append({'src': img['src'], 'alt': alt_text, 'reason': reason})
total_poor_quality += 1
# User Intent: "short alt list and that count are add in poor not it show separately"
# Action: Consolidate everything into 'poor_quality' and remove specific 'short_alt' reporting.
pages_report.append({
"page_url": page_url,
"missing_alt_count": len(missing_images),
"poor_quality_count": len(poor_quality_images), # Contains ALL poor images (Generic, Filename, Short)
"images_without_alt": list(set(missing_images)),
"images_with_poor_alt": poor_quality_images
})
return {
"summary": {
"total_pages_scanned": len(site_data),
"total_images_found": total_images,
"total_images_missing_alt": total_missing_alt,
"total_images_poor_quality": total_poor_quality
},
"details": pages_report
}
|