#!/usr/bin/env python3 """汇总 lighthouse 五页报告:分数表 + 未达标项的文件级嫌疑清单。 输入:目录内 page-*.json(lighthouse 全量输出) 输出:/tmp/e2e-shots/lighthouse-report.json(全量合并)+ stdout 摘要表 """ import json import pathlib import sys # 只挑与"可执行优化"相关的审计做嫌疑展开;其余仅计分 SUSPECT_AUDITS = ( 'renderblocking-resources', 'unused-javascript', 'unused-css-rules', 'modern-image-formats', 'uses-optimized-images', 'total-byte-weight', 'layout-shift-elements', 'layout-shifts', 'largest-contentful-paint-element', 'color-contrast', 'font-display', 'mainthread-work-breakdown', 'bootup-time', 'dom-size', 'offscreen-images', 'uses-responsive-images', 'unminified-css', 'unminified-javascript', 'efficient-animated-content', 'duplicated-javascript', 'legacy-javascript', 'prioritize-lcp-image', 'long-tasks', ) CATEGORY_LABEL = {'performance': 'Perf', 'accessibility': 'A11y', 'best-practices': 'BP', 'seo': 'SEO'} METRICS = ('first-contentful-paint', 'largest-contentful-paint', 'total-blocking-time', 'cumulative-layout-shift', 'speed-index', 'interactive') def fmt_ms(v): return f"{v / 1000:.1f}s" if isinstance(v, (int, float)) else str(v) def main(outdir: pathlib.Path): pages = {} rows = [] for f in sorted(outdir.glob('page-*.json')): data = json.loads(f.read_text()) url = data.get('finalDisplayedUrl') or data.get('finalUrl') or f.stem path = '/' + url.split('/', 3)[-1].replace('127.0.0.1:18743', '') if url.count('/') >= 3 else url cats = {k: round(v['score'] * 100) for k, v in data['categories'].items() if v.get('score') is not None} metrics = {m: fmt_ms(data['audits'][m].get('numericValue')) for m in METRICS if m in data['audits']} suspects = {} for cid, cat in data['categories'].items(): if cats.get(cid, 100) >= 100: continue for ref in cat.get('auditRefs', []): aid = ref['id'] a = data['audits'].get(aid, {}) if a.get('score') is not None and a['score'] < 0.9 and aid in SUSPECT_AUDITS: items = (a.get('details', {}) or {}).get('items', []) hint = [] for it in items[:4]: for key in ('url', 'node.selector', 'node.path', 'source.url'): v = it for seg in key.split('.'): v = v.get(seg) if isinstance(v, dict) else None if v: hint.append(str(v).split('?')[0][:110]) break else: hint.append(str(it)[:90]) if hint: suspects[aid] = {'score': a['score'], 'items': hint} pages[path or f.stem] = {'scores': cats, 'metrics': metrics, 'suspects': suspects} rows.append((path, cats)) labels = [CATEGORY_LABEL[c] for c in ('performance', 'accessibility', 'best-practices', 'seo')] print(f"{'页面':<28}" + ''.join(f"{l:>6}" for l in labels)) for path, cats in rows: cells = ''.join(f"{str(cats.get(c, "-"))[:3]:>6}" for c in ('performance', 'accessibility', 'best-practices', 'seo')) mark = ''.join(' ✗' if cats.get(c, 100) < 90 else ' ✓' for c in ('performance', 'accessibility', 'best-practices', 'seo')) print(f"{path:<28}{cells} {mark}") dest = pathlib.Path('/tmp/e2e-shots/lighthouse-report.json') dest.write_text(json.dumps(pages, ensure_ascii=False, indent=1)) print(f"\n全量合并报告: {dest}({dest.stat().st_size} B)") if __name__ == '__main__': main(pathlib.Path(sys.argv[1]))