实战:利用 Python 分析你的网页在 Perplexity 中的‘答案贡献度’评分

各位来宾,各位技术同仁,大家好!

非常荣幸今天能在这里,与大家共同探讨一个在AI时代日益凸显的关键议题:如何利用Python,深入分析并优化我们的网页内容,使其在Perplexity这类AI驱动的问答搜索引擎中,获得更高的“答案贡献度”评分。

在互联网内容爆炸式增长的今天,传统的SEO策略已不足以应对所有挑战。随着Perplexity.ai等新一代AI搜索引擎的崛起,用户获取信息的方式正在发生根本性变革。这些平台不再仅仅是列出相关网页链接,而是直接理解查询意图,合成信息,并提供精炼的答案,同时引用其信息来源。这给我们带来了新的机遇,也提出了新的要求:我们的内容不仅要被发现,更要被AI理解、采纳,并作为其答案的关键构成部分。

“答案贡献度”并非一个Perplexity官方明确发布的API指标,而是我们为了量化和优化自身内容在AI问答场景下的价值,而提出的一个概念性评分。它旨在衡量我们的网页内容在多大程度上能够:

  1. 直接回答用户问题: 提供清晰、准确、全面的信息。
  2. 作为权威来源被引用: 具备可信度、专业性,被AI模型认为是高质量的信源。
  3. 与查询意图高度匹配: 不仅是关键词匹配,更是深层语义上的关联。

本次讲座,我将带领大家从零开始,构建一个基于Python的分析框架,帮助我们理解自己的内容在Perplexity这类AI搜索引擎中的潜在表现,并给出切实可行的优化建议。我们将涵盖数据收集、文本分析、语义理解及评分构建等多个环节。


第一部分:AI搜索的崛起与“答案贡献度”的内涵

1.1 AI搜索:范式转换的起点

传统搜索引擎的核心是“检索”——根据关键词匹配,从海量索引中找出最相关的网页链接。而Perplexity这类AI搜索引擎,则将重心从“检索”转向了“合成”与“理解”。它们利用大型语言模型(LLM)对用户查询进行深度理解,然后综合多个信息源,生成一个连贯、全面的答案。这个过程中,LLM会评估不同来源的权威性、相关性和信息质量,最终决定哪些内容被采纳、哪些被引用。

Perplexity的工作机制简述:

  • 理解查询: 通过自然语言处理(NLP)技术,识别用户查询的真实意图、实体和上下文。
  • 多源检索: 在其索引中查找与查询相关的信息,这些信息可能来自网页、学术论文、新闻等。
  • 信息合成: 利用LLM将检索到的信息进行整合、提炼、组织,形成一个结构化的答案。
  • 引用溯源: 在答案下方或侧边,明确列出所有被采纳的信息来源链接。

1.2 何为“答案贡献度”?

在AI搜索的背景下,“答案贡献度”可以被定义为我们的网页内容被AI搜索引擎(如Perplexity)识别、理解、采纳并作为其生成答案的关键组成部分的程度。这个评分越高,意味着我们的内容越有可能在AI生成的答案中被提及或引用,从而提升我们的可见性和权威性。

构成“答案贡献度”的核心要素:

  • 内容质量与深度: 信息是否准确、全面、深入,是否能解决用户痛点。
  • 语义相关性: 内容是否与潜在用户查询的深层语义高度匹配,而不仅仅是关键词堆砌。
  • 权威性与可信度: 网站自身的专业度、外部引用、作者资质等。
  • 结构化与可读性: 内容是否易于AI模型解析和理解,例如清晰的标题、段落、列表、表格等。
  • 时效性: 对于某些主题,内容是否是最新的、最准确的。

由于Perplexity没有公开的API直接提供这个评分,我们将采取一种逆向工程与模拟分析的方法。我们将从用户可能的查询出发,分析我们自己的网站内容,评估其在上述要素上的表现,从而构建一个内部的、可操作的“答案贡献度”评分模型。


第二部分:构建分析框架——Python技术栈概览

为了实现我们的目标,我们将主要依赖Python及其丰富的科学计算与数据处理库。以下是我们即将使用的主要工具:

类别 库名 主要功能
网页爬取 requests 发送HTTP请求,获取网页内容
BeautifulSoup 解析HTML/XML文档,提取结构化数据
数据存储 pandas 数据结构与数据分析,处理表格数据
文本处理 nltk 自然语言工具包,分词、词形还原、停用词去除等
spaCy 高级NLP库,实体识别、句法分析、词向量等
scikit-learn 机器学习库,TF-IDF、主题模型(LDA/NMF)等
KeyBERT 基于BERT的关键词提取
gensim 文本建模,LSA/LDA等
语义相似度 sentence-transformers 生成句子嵌入,计算语义相似度
外部数据 google-search-results (SerpApi) 模拟搜索引擎查询,获取结果(用于验证或获取相关查询)
数学计算 numpy 高性能数值计算

第三部分:数据收集——获取分析的原材料

要分析我们的网站内容,首先需要获取它。这包括识别用户可能提出的问题(查询),以及爬取我们自己的网站内容。

3.1 识别潜在用户查询

要让我们的内容在AI搜索中贡献答案,我们首先要知道用户会问什么。有几种方法可以获取这些查询:

  • Google Search Console (GSC) 数据: 这是最直接、最准确的方式,因为它反映了真实用户在Google上搜索什么,以及他们如何找到或没有找到我们的网站。GSC API可以自动化提取这些数据。
  • 关键词研究工具: 使用Ahrefs, Semrush, Keyword Planner等工具,获取与我们网站主题相关的高流量、长尾关键词和问题。
  • Perplexity.ai本身: 我们可以手动或半自动化地观察Perplexity在特定主题下的“相关问题”或“深入探索”部分。
  • 论坛/社区数据: 分析Reddit、知乎、Stack Overflow等社区中用户提出的问题。

在本讲座中,我们将演示如何通过GSC数据作为主要来源,并辅以模拟的关键词研究数据。

3.1.1 模拟GSC数据获取(概念性代码)

实际操作中,你需要通过Google Cloud Platform设置API凭据。这里我们假设已经获取到一份包含查询和对应页面URL的数据。

import pandas as pd
from datetime import datetime, timedelta

def get_gsc_queries_mock():
    """
    模拟从Google Search Console API获取查询数据。
    实际应用中,你需要使用 Google Search Console API 客户端库。
    """
    data = {
        'query': [
            '如何用Python分析网页内容',
            'Python爬虫基础教程',
            'Perplexity AI工作原理',
            'EEAT原则在SEO中的应用',
            '网站内容质量评估方法',
            'Python文本相似度计算',
            '自然语言处理入门指南',
            '如何提高网站排名',
            '机器学习在SEO中的作用',
            '大型语言模型与搜索'
        ],
        'page': [
            'https://www.ourwebsite.com/python-web-analysis',
            'https://www.ourwebsite.com/python-crawler-tutorial',
            'https://www.ourwebsite.com/ai-search-explained',
            'https://www.ourwebsite.com/eeat-seo-guide',
            'https://www.ourwebsite.com/content-quality-metrics',
            'https://www.ourwebsite.com/nlp-text-similarity',
            'https://www.ourwebsite.com/nlp-for-beginners',
            'https://www.ourwebsite.com/seo-ranking-factors',
            'https://www.ourwebsite.com/ml-in-seo',
            'https://www.ourwebsite.com/llm-and-search'
        ],
        'clicks': [150, 120, 80, 200, 90, 70, 110, 60, 40, 30],
        'impressions': [5000, 4000, 3000, 6000, 3500, 2500, 4500, 2000, 1500, 1000],
        'ctr': [3.0, 3.0, 2.67, 3.33, 2.57, 2.8, 2.44, 3.0, 2.67, 3.0],
        'position': [5.1, 6.2, 8.5, 3.0, 7.8, 9.1, 6.5, 10.0, 12.3, 15.0]
    }
    df = pd.DataFrame(data)
    print("模拟GSC查询数据已加载。")
    return df

gsc_queries_df = get_gsc_queries_mock()
print(gsc_queries_df.head())

3.2 爬取自己的网站内容

为了分析我们的内容,我们需要将其从网页上提取下来。我们将编写一个简单的爬虫,遍历我们网站上的指定页面,并提取其文本内容、标题、元描述等关键信息。

重要提示:

  • 遵守robots.txt 在爬取任何网站(包括自己的网站)之前,请务必检查其robots.txt文件,并遵守其中的规则。
  • 设置延迟: 为了避免对服务器造成过大负担,请在请求之间设置适当的延迟。
  • 错误处理: 编写健壮的代码来处理网络错误、页面不存在等情况。
import requests
from bs4 import BeautifulSoup
import time
import random

def crawl_website_content(urls):
    """
    爬取指定URL列表的网页内容。
    提取标题、元描述和主要文本内容。
    """
    crawled_data = []
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
    }

    print(f"开始爬取 {len(urls)} 个网页...")
    for i, url in enumerate(urls):
        print(f"正在爬取 ({i+1}/{len(urls)}): {url}")
        try:
            response = requests.get(url, headers=headers, timeout=10)
            response.raise_for_status()  # 检查HTTP错误
            soup = BeautifulSoup(response.text, 'html.parser')

            title = soup.title.string if soup.title else 'N/A'
            meta_description_tag = soup.find('meta', attrs={'name': 'description'})
            meta_description = meta_description_tag['content'] if meta_description_tag else 'N/A'

            # 提取主要文本内容:通常在<p>, <h1>-<h6>, <li>等标签中
            # 需要根据实际网站结构进行调整,这里是一个通用示例
            main_content_tags = soup.find_all(['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'li'])
            content_text = ' '.join([tag.get_text(separator=' ', strip=True) for tag in main_content_tags if tag.get_text(strip=True)])

            crawled_data.append({
                'url': url,
                'title': title,
                'meta_description': meta_description,
                'full_text_content': content_text
            })
            time.sleep(random.uniform(1, 3)) # 随机延迟,避免IP被封

        except requests.exceptions.RequestException as e:
            print(f"爬取 {url} 失败: {e}")
            crawled_data.append({
                'url': url,
                'title': 'Error',
                'meta_description': 'Error',
                'full_text_content': 'Error: ' + str(e)
            })
        except Exception as e:
            print(f"处理 {url} 时发生未知错误: {e}")
            crawled_data.append({
                'url': url,
                'title': 'Error',
                'meta_description': 'Error',
                'full_text_content': 'Error: ' + str(e)
            })
    print("网页爬取完成。")
    return pd.DataFrame(crawled_data)

# 示例:使用GSC数据中的页面URL
# 注意:这里我们使用GSC数据中的页面URL作为示例,实际中可能需要爬取更多页面
# 为了演示,我们假设这些是真实存在的URL
sample_urls_to_crawl = gsc_queries_df['page'].unique().tolist()
# 真实环境中,可能需要一个更全面的URL列表,例如从网站地图或内部链接中获取

# !!!重要:为了避免实际的网络请求和可能的网站负担,这里我们不执行真实的爬取。
# 而是模拟一个爬取结果DataFrame。
# 如果您想运行实际爬虫,请取消注释下一行并将sample_urls_to_crawl替换为您的目标URL。
# website_content_df = crawl_website_content(sample_urls_to_crawl)

# 模拟爬取结果
mock_crawled_data = [
    {'url': 'https://www.ourwebsite.com/python-web-analysis', 'title': 'Python网页内容分析实战', 'meta_description': '学习如何使用Python进行网页内容提取与分析,优化AI搜索贡献度。', 'full_text_content': '本教程详细讲解了使用Python的requests和BeautifulSoup库进行网页内容分析的步骤,包括数据抓取、文本清洗、关键词提取等,旨在帮助用户提升其网站在Perplexity等AI搜索引擎中的答案贡献度。我们深入探讨了TF-IDF、LDA等技术,并提供了丰富的代码示例。'},
    {'url': 'https://www.ourwebsite.com/python-crawler-tutorial', 'title': 'Python爬虫入门与进阶', 'meta_description': '从零开始学习Python爬虫,掌握requests、BeautifulSoup、Selenium等工具。', 'full_text_content': '本教程涵盖了Python爬虫的基础知识,从HTTP请求到HTML解析,再到动态网页抓取。通过本教程,你将学会如何构建高效、稳定的爬虫程序,并了解常见的反爬机制和应对策略。'},
    {'url': 'https://www.ourwebsite.com/ai-search-explained', 'title': 'Perplexity AI:下一代搜索的奥秘', 'meta_description': '深度解析Perplexity AI的工作原理、优势及其对内容创作的影响。', 'full_text_content': 'Perplexity AI代表了AI搜索的新方向,它不仅仅是信息检索,更是智能合成与问答。本文详细阐述了其背后的LLM技术、信息溯源机制,以及作为内容创作者应如何适应这一变化。'},
    {'url': 'https://www.ourwebsite.com/eeat-seo-guide', 'title': 'EEAT原则:内容权威性与可信度指南', 'meta_description': '掌握Google EEAT原则,提升网站的专业性、权威性、经验和可信度。', 'full_text_content': 'EEAT是现代SEO的核心,本指南详细解释了Expertise、Experience、Authoritativeness、Trustworthiness这四大要素,并提供了实践建议,帮助网站构建高质量、高可信度的内容。'},
    {'url': 'https://www.ourwebsite.com/content-quality-metrics', 'title': '网站内容质量评估的量化指标', 'meta_description': '探讨并实践多种量化指标,评估和提升网站内容的整体质量。', 'full_text_content': '本文章介绍了多种衡量网站内容质量的指标,包括可读性、原创性、深度、关键词覆盖率等。我们还将讨论如何使用Python工具自动化这些评估过程。'},
    {'url': 'https://www.ourwebsite.com/nlp-text-similarity', 'title': 'Python实现文本相似度计算:从TF-IDF到语义嵌入', 'meta_description': '深入学习Python中计算文本相似度的各种方法,包括词袋模型、TF-IDF和深度学习的语义嵌入。', 'full_text_content': '文本相似度是NLP中的一个核心任务,广泛应用于信息检索、推荐系统等。本文通过Python代码示例,详细对比了TF-IDF、Word2Vec、Sentence Transformers等方法的原理和应用。'},
    {'url': 'https://www.ourwebsite.com/nlp-for-beginners', 'title': '自然语言处理(NLP)入门与实战', 'meta_description': '为初学者设计的NLP指南,涵盖基础概念、常用库及实战项目。', 'full_text_content': '本入门指南旨在帮助初学者快速掌握自然语言处理的核心概念,包括分词、词性标注、命名实体识别、文本分类等。我们将使用NLTK和spaCy库进行实践。'},
    {'url': 'https://www.ourwebsite.com/seo-ranking-factors', 'title': '2024年SEO核心排名因素深度解析', 'meta_description': '了解最新的SEO排名因素,优化网站以提升搜索引擎可见性。', 'full_text_content': '本文详细分析了2024年Google搜索引擎的核心排名因素,包括页面体验、内容质量、链接建设、EEAT等。提供了全面的优化策略。'},
    {'url': 'https://www.ourwebsite.com/ml-in-seo', 'title': '机器学习在SEO中的应用:从数据分析到智能优化', 'meta_description': '探索机器学习技术如何赋能SEO,实现更智能的网站优化和内容策略。', 'full_text_content': '机器学习正在改变SEO的面貌。本文探讨了其在关键词研究、内容推荐、用户行为预测等方面的应用,并展望了未来趋势。'},
    {'url': 'https://www.ourwebsite.com/llm-and-search', 'title': '大型语言模型(LLM)如何重塑搜索引擎', 'meta_description': '分析LLM技术对传统搜索引擎的影响,以及AI搜索的发展方向。', 'full_text_content': '大型语言模型如GPT系列和BERT正在深刻影响搜索引擎的工作方式。本文探讨了LLM如何提升搜索结果的相关性、生成更自然的答案,并预测了未来搜索的演变。'}
]
website_content_df = pd.DataFrame(mock_crawled_data)
print("n模拟爬取结果:")
print(website_content_df.head())

第四部分:内容分析——深度挖掘网页价值

有了爬取到的内容和潜在用户查询,我们就可以开始进行深度分析,评估每个页面在回答用户问题方面的潜力。

4.1 文本预处理

原始文本通常包含噪音,需要进行清洗和标准化,才能用于后续的NLP任务。

import re
import nltk
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
import string

# 下载NLTK资源 (仅需运行一次)
try:
    nltk.data.find('corpora/stopwords')
except nltk.downloader.DownloadError:
    nltk.download('stopwords')
try:
    nltk.data.find('corpora/wordnet')
except nltk.downloader.DownloadError:
    nltk.download('wordnet')
try:
    nltk.data.find('taggers/averaged_perceptron_tagger')
except nltk.downloader.DownloadError:
    nltk.download('averaged_perceptron_tagger')

stop_words = set(stopwords.words('english'))
lemmatizer = WordNetLemmatizer()

def preprocess_text(text):
    """
    对文本进行清洗、分词、去除停用词、词形还原。
    """
    if not isinstance(text, str):
        return ""
    # 转换为小写
    text = text.lower()
    # 移除标点符号
    text = text.translate(str.maketrans('', '', string.punctuation))
    # 移除数字
    text = re.sub(r'd+', '', text)
    # 分词
    tokens = nltk.word_tokenize(text)
    # 去除停用词并词形还原
    processed_tokens = [
        lemmatizer.lemmatize(word) for word in tokens if word not in stop_words and len(word) > 1
    ]
    return " ".join(processed_tokens)

print("n开始文本预处理...")
website_content_df['processed_content'] = website_content_df['full_text_content'].apply(preprocess_text)
gsc_queries_df['processed_query'] = gsc_queries_df['query'].apply(preprocess_text)
print("文本预处理完成。")
print(website_content_df[['url', 'processed_content']].head())

4.2 关键词提取与主题建模

理解页面核心内容,关键词和主题是关键。

4.2.1 关键词提取(TF-IDF)

TF-IDF(Term Frequency-Inverse Document Frequency)是一种常用的统计方法,用于评估一个词语对于一个文档集或一个语料库中的其中一份文档的重要程度。

from sklearn.feature_extraction.text import TfidfVectorizer

def extract_keywords_tfidf(text_series, top_n=5):
    """
    使用TF-IDF提取每个文档的关键词。
    """
    vectorizer = TfidfVectorizer(max_df=0.85, min_df=2, stop_words=list(stop_words))
    tfidf_matrix = vectorizer.fit_transform(text_series)
    feature_names = vectorizer.get_feature_names_out()

    keywords_list = []
    for i in range(len(text_series)):
        row = tfidf_matrix[i].toarray()[0]
        # 获取当前文档的TF-IDF分数,并按降序排列
        top_indices = row.argsort()[-top_n:][::-1]
        top_keywords = [(feature_names[idx], row[idx]) for idx in top_indices if row[idx] > 0]
        keywords_list.append([kw[0] for kw in top_keywords])
    return keywords_list

print("n开始TF-IDF关键词提取...")
website_content_df['keywords_tfidf'] = extract_keywords_tfidf(website_content_df['processed_content'])
print("TF-IDF关键词提取完成。")
print(website_content_df[['url', 'keywords_tfidf']].head())

4.2.2 主题建模(LDA)

Latent Dirichlet Allocation (LDA) 是一种主题模型,可以从文档集合中发现抽象的“主题”,每个主题由一组相关联的词汇组成,每个文档则被表示为这些主题的混合。

from sklearn.decomposition import LatentDirichletAllocation
from sklearn.feature_extraction.text import CountVectorizer

def perform_lda_topic_modeling(text_series, num_topics=5, top_n_words=5):
    """
    执行LDA主题建模,并为每个文档分配主题。
    """
    # 使用CountVectorizer创建词袋模型
    count_vectorizer = CountVectorizer(max_df=0.85, min_df=2, stop_words=list(stop_words))
    count_matrix = count_vectorizer.fit_transform(text_series)
    feature_names = count_vectorizer.get_feature_names_out()

    # 训练LDA模型
    lda = LatentDirichletAllocation(n_components=num_topics, random_state=42)
    lda.fit(count_matrix)

    # 获取每个主题的关键词
    topic_keywords = []
    for topic_idx, topic in enumerate(lda.components_):
        top_features_ind = topic.argsort()[:-top_n_words - 1:-1]
        top_features = [feature_names[i] for i in top_features_ind]
        topic_keywords.append(f"Topic {topic_idx}: {', '.join(top_features)}")

    # 获取每个文档的主题分布
    doc_topic_distribution = lda.transform(count_matrix)

    # 将每个文档最可能的主题索引添加到DataFrame
    doc_main_topics = [dist.argmax() for dist in doc_topic_distribution]

    return topic_keywords, doc_main_topics, doc_topic_distribution

print("n开始LDA主题建模...")
lda_topics, doc_main_topics, doc_topic_dist = perform_lda_topic_modeling(
    website_content_df['processed_content'], num_topics=3
)
website_content_df['main_topic_idx'] = doc_main_topics
print("LDA主题建模完成。发现主题:")
for topic_str in lda_topics:
    print(topic_str)
print(website_content_df[['url', 'main_topic_idx']].head())

4.3 可读性评估

内容的可读性直接影响用户体验,也间接影响AI模型对内容的理解和处理效率。Flesch-Kincaid可读性测试是一种常用的评估方法。

import textstat

def calculate_readability(text):
    """
    计算文本的Flesch-Kincaid阅读难度。
    分数越高,阅读难度越低。
    """
    if not isinstance(text, str) or len(text) < 10: # 避免空字符串或过短文本报错
        return 0.0
    try:
        return textstat.flesch_kincaid_grade(text)
    except Exception: # 捕获textstat可能出现的错误
        return 0.0

print("n开始计算可读性分数...")
website_content_df['readability_score'] = website_content_df['full_text_content'].apply(calculate_readability)
print("可读性分数计算完成。")
print(website_content_df[['url', 'readability_score']].head())

4.4 语义相似度计算

这是评估“答案贡献度”的核心环节。我们需要比较用户查询(或潜在查询)与我们网页内容的语义相似度。我们将使用sentence-transformers库来生成句子嵌入(sentence embeddings),这能更好地捕捉文本的深层语义。

from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np

# 加载预训练的Sentence Transformer模型
# 'paraphrase-multilingual-MiniLM-L12-v2' 支持多种语言,包括中文和英文
# 如果主要处理英文,可以使用 'all-MiniLM-L6-v2' 或 'all-mpnet-base-v2'
try:
    model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
    print("Sentence Transformer模型加载成功。")
except Exception as e:
    print(f"Sentence Transformer模型加载失败,请检查网络或安装:{e}")
    print("尝试使用备用模型或手动下载。")
    # 如果模型加载失败,这里可以考虑使用一个简单的TF-IDF+余弦相似度作为备用方案
    # 但语义效果会差很多。为了演示,我们假设模型加载成功。
    model = None # 标记模型未成功加载

def calculate_semantic_similarity(text1_list, text2_list, model):
    """
    计算两组文本之间的语义相似度(余弦相似度)。
    输入:两个文本列表。
    返回:相似度矩阵。
    """
    if model is None:
        print("错误:Sentence Transformer模型未成功加载,无法计算语义相似度。")
        return np.zeros((len(text1_list), len(text2_list))) # 返回一个零矩阵作为占位符

    # 生成文本嵌入
    embeddings1 = model.encode(text1_list, convert_to_tensor=True)
    embeddings2 = model.encode(text2_list, convert_to_tensor=True)

    # 计算余弦相似度
    similarity_matrix = cosine_similarity(embeddings1.cpu().numpy(), embeddings2.cpu().numpy())
    return similarity_matrix

if model:
    print("n开始计算查询与网页内容的语义相似度...")
    # 提取所有查询和所有网页内容
    all_queries = gsc_queries_df['query'].tolist()
    all_page_contents = website_content_df['full_text_content'].tolist()

    # 计算查询与页面内容的相似度矩阵
    # 矩阵的行对应查询,列对应页面
    query_page_similarity_matrix = calculate_semantic_similarity(all_queries, all_page_contents, model)
    print("语义相似度计算完成。")
    print(f"查询-页面相似度矩阵形状: {query_page_similarity_matrix.shape}")

    # 将相似度分数添加到GSC DataFrame中
    # 对于每个查询,找到与它最相似的页面及其分数
    best_match_scores = query_page_similarity_matrix.max(axis=1) # 每个查询与所有页面中的最大相似度
    best_match_page_indices = query_page_similarity_matrix.argmax(axis=1) # 每个查询最大相似度对应的页面索引

    gsc_queries_df['max_semantic_similarity_to_page'] = best_match_scores
    gsc_queries_df['best_matching_page_url'] = [
        website_content_df.iloc[idx]['url'] for idx in best_match_page_indices
    ]

    print("n查询与最佳匹配页面的语义相似度:")
    print(gsc_queries_df[['query', 'best_matching_page_url', 'max_semantic_similarity_to_page']].head())
else:
    print("n跳过语义相似度计算,因为模型未加载。")
    gsc_queries_df['max_semantic_similarity_to_page'] = 0.0
    gsc_queries_df['best_matching_page_url'] = 'N/A'

第五部分:模拟外部验证——Perplexity视角下的内容潜力

虽然我们无法直接获取Perplexity的内部评分,但我们可以通过模拟其可能依赖的外部信号,来间接评估我们内容的“答案贡献度”潜力。一个有效的方法是观察传统搜索引擎(如Google)在特定查询下的顶部结果,并与我们自己的内容进行对比。Perplexity在很大程度上也依赖于高质量的、排名靠前的网页作为其信息来源。

这里我们将利用一个搜索引擎结果页(SERP)API(例如SerpApi,或Google Custom Search API)来获取真实世界的搜索结果。

注意: SerpApi是一个付费服务,但提供免费试用额度。这里我们将演示其概念和用法。

# from serpapi import GoogleSearch # 需要安装 serpapi 库: pip install google-search-results
import os

# 假设您已设置SERPAPI_API_KEY环境变量
# 或者直接在这里赋值: os.environ["SERPAPI_API_KEY"] = "YOUR_API_KEY"

def get_serp_results_mock(query, api_key=None, num_results=5):
    """
    模拟从SERP API获取搜索结果。
    在实际应用中,这将调用SerpApi。
    """
    print(f"模拟获取查询 '{query}' 的SERP结果...")
    # 模拟数据,实际中会通过API获取
    mock_results = {
        '如何用Python分析网页内容': [
            {'title': 'Python网页分析教程 - 知名技术博客', 'link': 'https://techblog.com/python-web-analysis'},
            {'title': '使用BeautifulSoup进行网页数据提取 - 开发者社区', 'link': 'https://devcommunity.org/beautifulsoup-tutorial'},
            {'title': '我们的网站:Python网页内容分析实战', 'link': 'https://www.ourwebsite.com/python-web-analysis'},
            {'title': 'Web Scraping with Python - 知乎', 'link': 'https://www.zhihu.com/question/web-scraping-python'}
        ],
        'Perplexity AI工作原理': [
            {'title': 'Perplexity AI Explained - AI研究机构', 'link': 'https://airesearch.org/perplexity-explained'},
            {'title': 'Perplexity AI:下一代搜索的奥秘 - 我们的网站', 'link': 'https://www.ourwebsite.com/ai-search-explained'},
            {'title': 'AI搜索的未来:Perplexity深度解析 - 科技媒体', 'link': 'https://techmedia.com/ai-search-future'}
        ],
        'EEAT原则在SEO中的应用': [
            {'title': 'Google EEAT指南 - 官方SEO博客', 'link': 'https://official-seo.com/eeat-guide'},
            {'title': 'EEAT原则:内容权威性与可信度指南 - 我们的网站', 'link': 'https://www.ourwebsite.com/eeat-seo-guide'},
            {'title': 'EEAT for SEO: A Comprehensive Guide - 知名SEO工具', 'link': 'https://seotool.com/eeat-guide'}
        ]
    }

    return mock_results.get(query, [])[:num_results]

def analyze_serp_presence(queries_df, website_domain="www.ourwebsite.com"):
    """
    分析我们的网站在SERP结果中的出现情况和排名。
    """
    serp_analysis_results = []

    # 选取一些有代表性的查询进行分析
    sample_queries = queries_df['query'].sample(min(5, len(queries_df)), random_state=42).tolist()

    for query in sample_queries:
        results = get_serp_results_mock(query) # 实际调用时,这里会是 GoogleSearch(params).get_dict()

        our_site_rank = -1
        is_present = False

        for i, result in enumerate(results):
            if website_domain in result.get('link', ''):
                our_site_rank = i + 1
                is_present = True
                break

        serp_analysis_results.append({
            'query': query,
            'our_site_in_top_results': is_present,
            'our_site_rank': our_site_rank,
            'top_competitor_links': [res['link'] for res in results if website_domain not in res.get('link', '')]
        })
        time.sleep(1) # 模拟API调用延迟

    return pd.DataFrame(serp_analysis_results)

print("n开始模拟SERP分析...")
serp_df = analyze_serp_presence(gsc_queries_df, website_domain="www.ourwebsite.com")
print("SERP分析完成。")
print(serp_df.head())

从SERP结果中我们可以提取的洞察:

  • 我们网站的可见性: 我们的页面是否出现在高排名位置?
  • 竞争对手分析: 哪些竞争对手的内容在高排名?它们的标题、描述和内容结构有什么特点?这些可以为我们提供优化方向。
  • 内容差距识别: 如果某个查询我们没有进入前几名,或者没有相关页面,说明存在内容空白或质量问题。

结合我们的语义相似度分数,如果一个查询与我们页面的语义相似度很高,但我们却没有出现在SERP前列,这可能意味着:

  • 我们的内容质量仍需提升。
  • 我们的外部权威性(如链接)不足。
  • 页面技术SEO存在问题。
  • AI模型可能也不会优先选择我们的内容。

第六部分:构建“答案贡献度”评分模型

现在我们已经收集并分析了大量数据,是时候将这些指标整合起来,构建我们的“答案贡献度”评分了。这是一个自定义的评分,其权重可以根据实际业务需求进行调整。

我们将考虑以下几个核心维度:

  1. 语义相关性 (Semantic Relevance): 我们的内容与用户查询的语义匹配程度。
  2. 内容深度与广度 (Content Depth & Breadth): 通过主题模型和关键词覆盖来衡量。
  3. 内容质量 (Content Quality): 通过可读性、原创性(这里我们假设爬取的都是原创内容)和结构化程度(标题、列表等数量)来衡量。
  4. 外部信号 (External Signals – Proxy): 网站在传统SERP中的表现作为间接指标。

6.1 定义评分维度和权重

我们为每个维度分配一个权重,总和为1。

# 定义评分权重
WEIGHTS = {
    'semantic_relevance': 0.4,
    'content_depth': 0.2,
    'content_quality': 0.2,
    'serp_visibility_proxy': 0.2
}

# 确保权重总和为1
assert sum(WEIGHTS.values()) == 1.0, "权重总和必须为1.0"

def calculate_answer_contribution_score(page_url, gsc_queries_df, website_content_df, serp_df):
    """
    计算单个页面的答案贡献度评分。
    """
    page_data = website_content_df[website_content_df['url'] == page_url].iloc[0]

    # 1. 语义相关性 (Semantic Relevance)
    # 考虑所有与该页面最匹配的查询的平均相似度
    relevant_queries = gsc_queries_df[gsc_queries_df['best_matching_page_url'] == page_url]
    if not relevant_queries.empty:
        avg_semantic_similarity = relevant_queries['max_semantic_similarity_to_page'].mean()
    else:
        avg_semantic_similarity = 0.0

    # 2. 内容深度与广度 (Content Depth & Breadth)
    # 可以用关键词数量、主题覆盖率、内容长度等来衡量
    keyword_count = len(page_data['keywords_tfidf'])
    # 假设一个平均页面有5个关键词,对关键词数量进行归一化
    normalized_keyword_count = min(keyword_count / 10, 1.0) # 假设10个关键词为满分

    # 文本长度归一化
    content_length = len(page_data['full_text_content'])
    normalized_content_length = min(content_length / 2000, 1.0) # 假设2000字为满分

    content_depth_score = (normalized_keyword_count + normalized_content_length) / 2

    # 3. 内容质量 (Content Quality)
    # 可读性分数归一化(Flesch-Kincaid分数通常在0-100之间,我们假设理想在70-80)
    normalized_readability = max(0, min(page_data['readability_score'] / 100, 1.0)) # 归一化到0-1

    # 结构化程度:这里我们可以简单假设标题数量、列表数量等,但需要更复杂的HTML解析
    # 为了简化,我们假设标题越多,结构化越好。这里用一个占位符。
    # 实际应用中,需要重新爬取并提取这些结构化数据
    num_headings = page_data['full_text_content'].count('h2') + page_data['full_text_content'].count('h3') # 粗略估计
    normalized_structure = min(num_headings / 5, 1.0) # 假设5个小标题为满分

    content_quality_score = (normalized_readability + normalized_structure) / 2

    # 4. 外部信号代理 (SERP Visibility Proxy)
    # 衡量该页面在主要查询下的SERP表现
    page_serp_data = serp_df[serp_df['best_matching_page_url'] == page_url] # 这里的SERP数据是针对查询的,需要调整逻辑

    # 重新思考serp_visibility_proxy的计算方式
    # 对于每个页面,我们看它在多少个GSC查询中是最佳匹配页面,并且在SERP中表现良好
    # 假设我们定义“表现良好”为进入SERP前5名
    relevant_queries_with_serp = pd.merge(
        relevant_queries,
        serp_df[['query', 'our_site_rank']],
        on='query',
        how='left'
    )

    good_serp_matches = relevant_queries_with_serp[
        (relevant_queries_with_serp['our_site_rank'] != -1) &
        (relevant_queries_with_serp['our_site_rank'] <= 5)
    ]

    if not relevant_queries.empty:
        # 如果一个页面是很多相关查询的最佳匹配,并且在这些查询中SERP排名靠前,则分数高
        serp_visibility_score = len(good_serp_matches) / len(relevant_queries)
    else:
        serp_visibility_score = 0.0

    # 综合评分
    final_score = (
        WEIGHTS['semantic_relevance'] * avg_semantic_similarity +
        WEIGHTS['content_depth'] * content_depth_score +
        WEIGHTS['content_quality'] * content_quality_score +
        WEIGHTS['serp_visibility_proxy'] * serp_visibility_score
    )

    return final_score

print("n开始计算每个页面的答案贡献度评分...")
# 为每个页面计算评分
website_content_df['answer_contribution_score'] = website_content_df['url'].apply(
    lambda url: calculate_answer_contribution_score(url, gsc_queries_df, website_content_df, serp_df)
)
print("答案贡献度评分计算完成。")
print(website_content_df[['url', 'title', 'answer_contribution_score']].sort_values(
    by='answer_contribution_score', ascending=False
).head())

6.2 评分结果可视化与解释

我们可以将结果进行排序,找出表现最佳和最差的页面,并深入分析其原因。

import matplotlib.pyplot as plt
import seaborn as sns

if not website_content_df.empty:
    plt.figure(figsize=(12, 6))
    sns.barplot(
        x='answer_contribution_score',
        y='title',
        data=website_content_df.sort_values(by='answer_contribution_score', ascending=False),
        palette='viridis'
    )
    plt.xlabel('答案贡献度评分')
    plt.ylabel('页面标题')
    plt.title('网站页面答案贡献度评分概览')
    plt.tight_layout()
    # plt.show() # 在非交互式环境中通常不显示,而是保存
    plt.savefig('answer_contribution_score_overview.png')
    print("n答案贡献度评分概览图已保存为 'answer_contribution_score_overview.png'")

    # 输出详细表格
    print("n详细答案贡献度评分表:")
    score_table = website_content_df[['url', 'title', 'answer_contribution_score', 'readability_score', 'main_topic_idx']]
    print(score_table.sort_values(by='answer_contribution_score', ascending=False).to_markdown(index=False))

对评分的解读:

  • 高分页面: 这些页面在语义相关性、内容深度和质量、以及(潜在的)SERP可见性方面表现良好。它们是网站的“明星内容”,应继续维护和推广。AI搜索引擎很可能将其作为优质信息源。
  • 低分页面: 这些页面可能存在以下问题:
    • 语义不匹配: 内容与用户实际查询的意图不符,或者内容过于宽泛/狭窄。
    • 内容深度不足: 信息不够全面,无法充分回答用户问题。
    • 可读性差: 语言晦涩,结构混乱,AI模型难以有效提取信息。
    • 缺乏外部认可: 在传统搜索结果中排名不佳,可能也暗示AI模型对其权威性存疑。

第七部分:行动建议与持续优化

获得了“答案贡献度”评分后,最重要的是将其转化为可执行的优化策略。

7.1 内容优化策略

  1. 针对性内容拓展:

    • 低语义相关性页面: 重新审视这些页面的目标查询。是不是应该更新内容以更好地匹配相关查询?或者这些查询应该由新的、更专注的页面来回答?
    • 主题覆盖不足的页面: 结合LDA分析,如果某个页面没有明确的主题,或者其主题与预期不符,可能需要增加相关词汇、概念,深化讨论。
    • 高潜力低排名页面: 如果某个页面与大量查询语义高度相关,但“答案贡献度”不高(特别是serp_visibility_proxy较低),则重点提升其内容质量和外部权威性。
  2. 提升内容质量与可读性:

    • 检查低可读性页面: 简化句子结构,使用更常见的词汇,增加段落和标题,使用列表和表格来组织信息。确保语言简洁明了,易于人类和AI理解。
    • 结构化数据应用: 在内容中合理使用Schema Markup(如FAQPage, HowTo, Article等),这能帮助AI模型更好地理解内容的结构和意图。虽然本讲座未直接涉及Schema,但它对AI理解至关重要。
    • 多媒体内容整合: 图像、视频、图表等不仅能提升用户体验,也能为AI提供更丰富的上下文信息。
  3. 权威性建设:

    • 专家撰写与审查: 确保内容由领域专家撰写或经过专家审查,并在页面上明确展示作者信息和资质。这是EEAT原则的核心。
    • 引用高质量来源: 在内容中引用权威的外部研究、数据和专家观点,并提供准确的链接。
    • 建立外部链接: 积极争取高质量的外部网站链接到您的内容,这是提升网站Domain Authority的关键。

7.2 持续监控与迭代

“答案贡献度”分析并非一次性任务,而是一个持续优化的过程:

  1. 定期数据刷新: 定期重新爬取网站内容,更新GSC查询数据,并重新计算评分。
  2. 模型调整: 根据业务目标和对AI搜索的理解加深,调整评分模型中的权重。
  3. A/B测试: 对优化后的页面进行A/B测试,观察其在实际GSC数据(点击、展示、排名)和“答案贡献度”评分上的变化。
  4. 关注AI搜索趋势: 持续关注Perplexity等AI搜索引擎的功能更新、算法变化,及时调整内容策略。

最后的思考

在AI驱动的搜索时代,我们的内容不再仅仅是“被找到”,而是要“被理解”、“被采纳”、“被信任”。利用Python构建的这个“答案贡献度”分析框架,为我们提供了一个量化的工具,去审视和提升我们的内容资产。它迫使我们从AI的视角出发,思考如何提供更直接、更权威、更易于理解的答案。

这不仅仅是技术上的挑战,更是内容策略上的转型。拥抱AI,意味着我们需要创作那些不仅能满足用户,也能服务于智能系统的优质内容。通过持续的分析和优化,我们能够确保我们的声音在日益复杂的数字生态系统中,依然响亮而清晰。

感谢大家的聆听!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注