from bs4 import BeautifulSoup import re s = BeautifulSoup(open('pfl.html',encoding='utf-8',errors='ignore').read(),'lxml') print("=== STRUCTURE / A11Y SCAN: pfl_claim_process ===") html=s.find('html') print("lang attribute:", html.get('lang') if html else 'none') imgs=s.find_all('img') noalt=[i for i in imgs if i.get('alt') is None] emptyalt=[i for i in imgs if i.get('alt')==''] print(f"images: {len(imgs)} | missing alt attr: {len(noalt)} | decorative alt='': {len(emptyalt)}") hs=[(int(h.name[1]), h.get_text(' ',strip=True)[:60]) for h in s.find_all(re.compile('^h[1-6]$'))] print(f"\nheadings: {len(hs)}") prev=0; skips=[] for lvl,txt in hs: if prev and lvl>prev+1: skips.append((prev,lvl,txt)) prev=lvl print("h1 count:", sum(1 for l,_ in hs if l==1)) print("heading-level skips (WCAG 1.3.1):", len(skips)) for a,b,t in skips[:8]: print(f" h{a} -> h{b} at: {t}") # accordion triggers exp=s.find_all(attrs={'aria-expanded':True}) print(f"\nelements with aria-expanded: {len(exp)}") vals=set(e.get('aria-expanded') for e in exp) print(" values present:", vals) # links links=s.find_all('a') generic=[a.get_text(' ',strip=True) for a in links if a.get_text(' ',strip=True).lower() in ('click here','here','more','read more','learn more','this page','link')] empty=[a for a in links if not a.get_text(strip=True) and not a.find('img') and not a.get('aria-label')] print(f"\nlinks: {len(links)} | non-descriptive text: {len(generic)} | empty accessible name: {len(empty)}") # the mismatched link for a in links: t=a.get_text(' ',strip=True) if 'Stop or Continue' in t or 'Continue Your Benefits' in t: print(f"\n LINK TEXT : {t}\n HREF : {a.get('href')}") # tabindex / target=_blank tb=[a for a in links if a.get('target')=='_blank'] print(f"\nlinks opening new window: {len(tb)}") # iframes ifr=s.find_all('iframe') print(f"iframes: {len(ifr)} | missing title: {sum(1 for i in ifr if not i.get('title'))}")