外贸独立站3类页面合格度,怎么用脚本一次跑完

给外贸独立站做内容改版,最容易卡在验收:产品页的参数补全了没有、文章页能不能答上标题那个问题、问答页有几条。这些判断过去都靠人眼看,改完一批就没人再回头看一遍。

这篇把三类页面的判断标准写成可计算的指标,配一段能跑的脚本。

先说清定位。这些指标是启发式的自检工具,用来发现问题与看趋势,不是任何平台的判定标准,也不能拿它的分数去对外说效果。

一、为什么要把写法变成指标

三类页面的写法要求本身很清楚:产品页的参数与认证要能被提取,文章页要有一句直接回答标题的话,问答页要有成条的问答与对应的标记。

问题在于不可持续。一次性改完可以,但产品线在增、工艺在变,半年之后没人知道哪些页面又退回去了。

变成指标之后,改版前跑一次、改完跑一次,看的是变化量而不是绝对值。这一层与外部观测是两套数据:站内的合格度是自己可控的,站外被 AI 引用与由此带来的点击都是被动接收的。

二、三个指标的定义与合格线

指标 定义 计算方式 合格线
参数可提取率 页面上的参数有多少写在文字与表格里 文字与表格中的参数条数 ÷ 全部参数条数(含图片里的) 由站点自定,建议先取当前值再看提升
标题答案匹配度 标题问句能不能在正文里找到直答句 标题关键词命中率 × 前 300 字内是否出现同义判断句 启发式打分,只用于排序
问答覆盖度 问答条目数与结构化数据标记是否对应 问句型小标题条数、问答标记条数,两者取小 标记数不少于条目数的八成

三张合格线的量纲都是自己定的。跨站比较没有意义,因为不同品类的参数密度差得很远,同一套阈值没法通用。

三、抓取与打分脚本

脚本做三件事:取回页面的 HTML、按三个指标打分、把结果写成表。抓取用 requests 加解析库就够,页面数量在几百这个量级不需要上异步。

复制代码
# page_score.py
# pip install requests beautifulsoup4
import csv, json, re
import requests
from bs4 import BeautifulSoup

# 带单位的参数写法:数值 + 单位
PARAM_WITH_UNIT = re.compile(r'\d+(?:\.\d+)?\s*(?:mm|cm|kg|g|MPa|N|h|%|\u00b0C|小时|天)')
# 问句型小标题的粗判:以疑问词开头或结尾带问号
QUESTION_HEAD = re.compile(r'^(.{2,40}?)(?:\uff1f|\?)$')
TITLE_WORD = re.compile(r'[\u4e00-\u9fa5A-Za-z]{2,}')

def fetch(url, timeout=20):
    r = requests.get(url, headers={'User-Agent':
        'Mozilla/5.0 (compatible; site-audit/1.0)'}, timeout=timeout)
    r.raise_for_status()
    return BeautifulSoup(r.text, 'html.parser')

def score_param(soup):
    """参数可提取率:文字与表格里的参数 占 全部参数(含图片替代文字)的比例"""
    text = ' '.join(t.get_text(' ', strip=True)
                    for t in soup.find_all(['p', 'li', 'td', 'th', 'h2', 'h3']))
    in_text = len(PARAM_WITH_UNIT.findall(text))
    in_alt = 0
    for img in soup.find_all('img'):
        alt = img.get('alt') or ''
        in_alt += len(PARAM_WITH_UNIT.findall(alt))
    total = in_text + in_alt
    return round(100.0 * in_text / total, 1) if total else None

def score_answer(soup, title):
    """标题答案匹配度:标题关键词在正文前 300 字里的命中率"""
    words = set(TITLE_WORD.findall(title))
    body = ' '.join(p.get_text(' ', strip=True) for p in soup.find_all('p'))
    head = body[:300]
    if not words:
        return None
    hit = sum(1 for w in words if w in head)
    return round(100.0 * hit / len(words), 1)

def score_faq(soup):
    """问答覆盖度:问句型小标题条数 与 问答标记条数"""
    qs = [h for h in soup.find_all(['h2', 'h3'])
          if QUESTION_HEAD.match(h.get_text(strip=True))]
    marked = len(soup.select('[itemtype*="Question"]'))
    return {'questions': len(qs), 'marked': marked}

def audit(urls):
    rows = []
    for kind, url in urls:
        soup = fetch(url)
        title = (soup.title.get_text(strip=True) if soup.title else '')
        rows.append({
            'kind': kind,
            'url': url,
            'param_rate': score_param(soup),
            'answer_match': score_answer(soup, title),
            'faq': score_faq(soup),
        })
    return rows

if __name__ == '__main__':
    targets = [(r[0], r[1]) for r in csv.reader(open('urls.csv', encoding='utf-8'))]
    rows = audit(targets)
    with open('score.csv', 'w', newline='', encoding='utf-8') as f:
        w = csv.DictWriter(f, fieldnames=['kind', 'url', 'param_rate', 'answer_match', 'faq'])
        w.writeheader()
        w.writerows(rows)
    print(json.dumps(rows[:3], ensure_ascii=False, indent=2))

输入是一张两张列的清单:页面类型与地址。输出是一张分数表,可以直接和上一次的结果并排比。

几个实现上的注意点。参数正则里的单位表要按自己的品类补,机械类要加公差与硬度,纺织类要加克重与幅宽。问句型小标题的粗判只看是否以问号结尾,长标题需要再截断一次。问答标记那一段按实际使用的语法调整,用 JSON-LD 的站要改成解析脚本内容。

四、把三项指标接进改版流程

接法有两种,成本都不高。

轻量做法是放在发版清单里。每次产品页或文章页改动之后跑一次,分数掉的页面回到修改列表。这套做法不需要额外的服务。我是先在自己站上挑了二十来个页面跑了一遍,把分数表存下来,隔周再跑一次,才看清哪些页面是真的在退化。

稍重一点的做法是接进构建流程,把脚本挂在部署的下一步,输出结果存成带日期的文件。这样就有了时间序列,能看出哪些页面在缓慢退化。

建议把站内分数与站外观测分开存。站内分数在代码库里跟着版本走,站外的曝光与引用另存一份,两张表靠 URL 关联,不要混成一张表,否则口径会乱。

顺带说一句元数据的处理。页面标题、meta 描述、结构化数据、图片替代文字这四类字段,脚本里都能顺手取到,建议在分数表里各占一列。它们不影响三类页面的主体分数,但退化的速度往往比正文快。

五、判读时容易踩的三个坑

第一个坑是把参数可提取率当成越高越好。把无意义的数字堆进正文也能刷高这个分数,评出来的页面反而更差。这个指标要看的是"降下来又涨回去"的变化,不是绝对值。

第二个坑是拿标题答案匹配度当结论。它是关键词级别的粗判,同义词和改写句都会漏掉,只适合用来排序,挑出最不像的几页去看一眼。

第三个坑是只跑一次就下判断。单次分数的作用有限,同一批页面连着跑四周,趋势才有信息量。这与独立站SEO 里看排名的做法一样,单日数据基本没有意义。

六、这套做法的边界

三个指标都是代理量。它们能指出"这里可能有问题",不能证明"改完就会变好"。任何把它当成绩效指标的做法都会失真。

它也不覆盖内容质量本身。一段参数写得对不对、一个工艺结论是不是过时,脚本判不了,这部分还是得有人过。脚本的作用是让人的注意力落在少数几页上,不是替代判断。

独立站搭建阶段把这三类页面的字段位置留出来,后期的分数维护成本会低很多;我们这边的站用的是 NeoGress,产品参数位与问答段在后台是对应字段,改版时脚本能直接取到,不用再去猜结构。适不适合你的项目,看团队里有没有人能固定每周跑一次。

最后一个问题:你们现在是用什么方式记录页面改版前后的变化?评论区说一下做法,我看看有没有更适合接进自动化流程的形式。

相关推荐
benchmark_cc1 小时前
批量获取股票数据后,如何统一转换成 DataFrame?从数据结构到量化研究的完整实践
数据结构·python·数据分析·量化交易·股票数据·quantdash
X北辰北1 小时前
C++ 进阶第二阶段总结|STL容器全家桶、迭代器失效、STL算法、序列化入门(工程必备)
开发语言·c++·算法
溪语流沙1 小时前
面试加分项!Manacher:O(n)求最长回文子串的对称之美
java·python·leetcode·面试·职场和发展
树獭哥1 小时前
Deep Agents 学习笔记(一):从 Agent Harness 到第一个 Deep Agent
人工智能·python
旖旎夜光2 小时前
【LangGraph实战】LangGraph 学习笔记(五):信息裁剪、人机交互与时间旅行
笔记·python·学习·ai·人机交互·langgraph
Helix2502 小时前
Python单元测试实战:pytest框架从入门到企业级测试体系搭建指南
python·单元测试·实战·mock·pytest·测试覆盖率·fixture
伯恩bourne2 小时前
对比 @Configuration(Full) vs @Component(Lite)
java·开发语言
软件开发技术深度爱好者2 小时前
ndexTTS-2和 CosyVoice之TTS(Text-to-Speech)使用python示例
开发语言·python