"""Commercial-delivery readiness report, separate from technical/SEO pass. It does NOT certify a site's business claims, copyright clearance, legal compliance, WCAG conformance or any real-world server/SEO outcome. It reports missing items. """ from __future__ import annotations from pathlib import Path from bs4 import BeautifulSoup import json REQUIRED=('index.html','about/index.html','contact/index.html','products/index.html','brands/index.html','news/index.html','cases/index.html','404.html') DEMO_MARKERS=('example.com','example.test','这是可替换的','虚构示例','演示内容','演示产品','此为 SiteForge','请在后台配置') def inspect(dist:Path)->dict: dist=Path(dist) blockers=[];warnings=[];metrics={} for f in REQUIRED: if not (dist/f).is_file():blockers.append({'code':'page_missing','path':f,'message':'缺少标准栏目页面'}) homepage=dist/'index.html' if homepage.is_file(): soup=BeautifulSoup(homepage.read_text(encoding='utf-8'),'html.parser') logo=soup.select_one('header img.pro-brand-logo') if not logo:warnings.append({'code':'brand_logo','message':'尚未替换成企业正式 Logo'}) if not soup.find('meta',attrs={'name':'description'}):blockers.append({'code':'seo_description','message':'首页缺少 SEO 描述标签'}) if len(soup.select('h1'))!=1:blockers.append({'code':'home_h1','message':'首页 H1 数量不符合预期'}) else:soup=None # Do not build a 5,000-page HTML string and parse every detail document with # BeautifulSoup just to count two static CSS classes. Streaming makes the # commercial audit linear in file size, rather than consuming excessive CPU. metrics['html_pages']=0 metrics['artwork_fallbacks']=0 metrics['pages_with_body']=0 found_demo=False for path in dist.rglob('*.html'): html=path.read_text(encoding='utf-8',errors='replace') metrics['html_pages']+=1 metrics['artwork_fallbacks']+=html.count('class="pro-art ') metrics['pages_with_body']+=int('pro-rich' in html) if not found_demo and any(marker in html for marker in DEMO_MARKERS):found_demo=True if metrics['artwork_fallbacks']: warnings.append({'code':'placeholder_images','count':metrics['artwork_fallbacks'],'message':'部分页面仍使用示意图,正式发布前请替换为真实且有使用权的图片'}) if found_demo: warnings.append({'code':'demo_content','message':'检测到演示或默认文案,正式发布前请逐页核对'}) if not (dist/'assets'/'commercial.css').is_file(): warnings.append({'code':'commercial_style','message':'当前构建未包含商业视觉样式(可能是历史主题版本)'}) contact=dist/'contact/index.html' if contact.is_file(): con=BeautifulSoup(contact.read_text(encoding='utf-8'),'html.parser') if not con.select_one('form.pro-inquiry') and not con.select_one('a[href^="mailto:"]'): blockers.append({'code':'contact_method','message':'联系页既无已配置表单,也无有效电子邮箱入口'}) elif not con.select_one('form.pro-inquiry'): warnings.append({'code':'form_not_configured','message':'尚未配置 HTTPS 询盘接收服务;目前仅提供邮件联系'}) if not any((dist/p).is_file() for p in ('privacy/index.html','privacy-policy/index.html')): warnings.append({'code':'legal_pages','message':'请根据目标国家/地区法律审查是否需要隐私政策与 Cookie 声明'}) return {'ready_for_review':not blockers,'commercially_certified':False,'blockers':blockers,'warnings':warnings, 'metrics':metrics,'note':'仅为本地结构化交付清单,不等于合法合规、内容准确、无障碍、性能或生产上线认证'}