各位来宾,各位技术同仁,大家好!
今天,我们汇聚一堂,探讨一个在数字营销和数据分析领域日益重要的话题:如何利用Python爬虫技术,深入剖析AI搜索引擎在处理用户提示词时,对品牌展现的影响。随着人工智能技术的飞速发展,AI搜索引擎正逐渐改变我们获取信息的方式,其答案生成模式与传统搜索引擎的链接列表截然不同,这对品牌的可见性和声誉管理提出了全新的挑战与机遇。
作为一名编程专家,我深知理论与实践相结合的重要性。因此,本次讲座将以“实战”为核心,通过详细的代码演示和严谨的逻辑分析,带领大家构建一个功能强大的Python爬虫系统,用于对比不同AI搜索引擎在100个不同提示词下的品牌展现效果。我们将不仅关注技术实现,更会深入探讨背后的数据意义,以及这些数据如何为品牌策略提供宝贵的洞察。
1. AI搜索引擎时代:品牌展现的新范式
传统搜索引擎优化(SEO)的核心是争取在搜索结果页(SERP)中获得更高的排名,从而引导用户点击进入品牌网站。然而,AI搜索引擎,如Perplexity AI、Bing Copilot(基于GPT)或Google的Search Generative Experience (SGE),它们的运作机制发生了根本性变化。它们不再仅仅提供链接列表,而是直接生成整合、摘要性的答案,甚至在答案中直接提及品牌、产品或服务。
这种转变对品牌意味着什么?
- 从“点击”到“提及”:品牌不再仅仅追求用户点击其链接,更重要的是在AI生成的答案中被直接提及,甚至被作为权威来源引用。
- 从“排名”到“被采纳”:品牌内容需要被AI模型理解、信任并采纳为生成答案的一部分。
- 内容的深度和权威性:AI更倾向于综合高质量、权威、多角度的信息来生成答案,这意味着品牌需要提供更具深度和可信度的内容。
- 潜在的“品牌劫持”风险:如果AI生成的内容对品牌存在不准确或负面描述,可能迅速扩散,损害品牌形象。
因此,监测和分析品牌在AI搜索引擎中的展现情况,成为数字营销和品牌管理的新前沿。我们今天的任务,正是要用Python这一利器,为品牌揭开AI搜索的神秘面纱。
2. 确定研究范围与方法论
在着手编写代码之前,我们需要明确本次实战的研究范围、目标以及具体的方法论。严谨的规划是成功的基石。
2.1 目标AI搜索引擎的选择
考虑到AI搜索引擎的复杂性和访问限制,我们将选择以下代表性的平台进行分析:
- Perplexity AI:一个以“答案引擎”自居的平台,其特点是提供详细的引用来源,便于我们追踪品牌提及的出处。它相对开放,是理想的爬取对象。
- Bing Copilot (或类似集成GPT能力的平台):代表了微软在搜索领域的AI整合。它也提供生成式答案,但可能在引用方式上与Perplexity有所不同。
- (可选/讨论) Google SGE:虽然Google SGE目前仍处于实验阶段,且通常需要登录或特定地区才能体验,其爬取难度较大。如果条件允许,它将是未来研究的重要对象。本次实战将主要聚焦于Perplexity AI,并讨论如何将方法论扩展到其他平台。
2.2 提示词(Prompts)的构建
我们将使用100个不同的提示词。这些提示词应具备多样性,覆盖用户可能在AI搜索引擎中提出的常见问题类型,例如:
- 产品/服务推荐类:"最好的降噪耳机是什么?", "如何选择一款可靠的云存储服务?"
- 比较类: "iPhone vs Android 手机的优缺点", "比较Tesla和BYD的电动汽车技术"
- 操作指南类: "如何清洁咖啡机?", "Python爬虫入门教程"
- 信息查询类: "什么是量子计算?", "最新的AI发展趋势"
- 品牌相关查询: "华为Mate 60 Pro评测", "小米汽车SU7的性能如何"
我们将把这些提示词存储在一个CSV文件中,便于管理和批量处理。
2.3 目标品牌集合
我们将选取一组具有代表性的品牌进行对比分析。这些品牌可以来自不同的行业,例如:
- 科技产品:Sony, Bose, Apple, Samsung, Huawei, Xiaomi
- 云服务:Google Cloud, Microsoft Azure, AWS, Dropbox, OneDrive
- 汽车:Tesla, BYD, BMW, Mercedes-Benz
将这些品牌存储在一个列表中,方便在AI生成内容中进行匹配。
2.4 品牌展现的定义与衡量指标
在AI搜索引擎中,"品牌展现"的含义比传统SEO更为丰富。我们将关注以下几个核心指标:
- 直接提及(Direct Mention):品牌名称在AI生成的摘要文本中直接出现。
- 来源引用提及(Source Citation Mention):品牌名称出现在AI引用的外部来源(如文章标题、URL域名)中。
- 提及频率(Frequency):一个品牌在单个AI答案中被提及的次数。
- 提及位置(Position):品牌在AI摘要中出现的位置(例如,是在开头、中间还是结尾)。
- (未来扩展) 情感倾向(Sentiment):品牌提及的上下文是积极、消极还是中性。本次实战将主要侧重于前两项:直接提及和来源引用提及。
2.5 伦理与技术考量
在进行网络爬取时,我们必须遵守以下原则:
- 尊重
robots.txt协议:虽然AI搜索引擎的聊天接口可能没有明确的robots.txt规则,但我们仍需以负责任的态度进行。 - 控制爬取频率:设置合理的延迟时间,避免对目标服务器造成过大负担,导致IP被封禁。
- 伪装用户代理(User-Agent):模拟正常浏览器行为,减少被识别为爬虫的风险。
- 数据用途声明:明确爬取数据仅用于研究和分析,不用于非法目的。
3. 工具箱:Python爬虫核心库
为了完成这项任务,我们将依赖一系列强大的Python库。
selenium或playwright:AI搜索引擎通常是高度动态的Web应用,内容通过JavaScript异步加载。传统的requests+BeautifulSoup组合难以处理这类页面。selenium或playwright提供了浏览器自动化能力,能够模拟用户行为(如输入、点击、滚动),并等待JavaScript渲染完成,从而获取完整的页面内容。本次实战将以selenium为例进行演示,因为它在社区中拥有广泛的应用和资料。BeautifulSoup:虽然selenium能获取页面内容,但解析HTML结构并提取特定数据仍是BeautifulSoup的强项。pandas:用于数据存储、清洗、分析和报告生成。它是数据科学领域不可或缺的工具。time:用于实现请求间的延迟,以避免被目标网站反爬。re(正则表达式):用于在文本中高效匹配品牌名称。
环境搭建:
首先,确保您的Python环境已准备就绪。建议使用虚拟环境:
# 创建虚拟环境
python -m venv ai_search_scraper_env
# 激活虚拟环境 (Windows)
.ai_search_scraper_envScriptsactivate
# 激活虚拟环境 (macOS/Linux)
source ai_search_scraper_env/bin/activate
# 安装所需库
pip install selenium beautifulsoup4 pandas
此外,selenium需要一个浏览器驱动。如果您使用Chrome浏览器,需要下载对应的ChromeDriver。请确保ChromeDriver的版本与您的Chrome浏览器版本匹配。下载地址:https://chromedriver.chromium.org/downloads。下载后将其放置在系统PATH中,或指定其路径。
4. 实战:构建AI搜索引擎品牌展现爬虫
现在,让我们进入核心环节——代码实现。我们将以Perplexity AI为例,详细讲解爬取过程。
4.1 准备数据:提示词与目标品牌
首先,创建prompts.csv文件,包含100个提示词。这里我们先用一个示例文件,您可以根据需要扩展。
prompts.csv 示例:
Prompt
"Best noise-cancelling headphones for travel"
"How to choose a reliable cloud storage service"
"Top smartphones released in 2023"
"Compare virtual private networks"
"Advantages of using a smart home assistant"
"Review of the latest gaming consoles"
"Sustainable fashion brands to watch"
"Best laptops for programming"
"Guide to digital marketing tools"
"Future of electric vehicles"
"AI in healthcare applications"
"Smartwatch features comparison"
"Electric car battery life comparison"
"Home security camera systems review"
"Best protein powder for muscle gain"
"Organic food benefits and brands"
"Latest trends in cybersecurity"
"Virtual reality headsets for gaming"
"Affordable web hosting providers"
"Smart home lighting systems"
# ... 更多提示词,总计100个
定义目标品牌列表:
# brands.py 或直接在主脚本中定义
TARGET_BRANDS = [
"Sony", "Bose", "Apple", "Samsung", "Huawei", "Xiaomi",
"Google", "Microsoft", "Amazon", "Dropbox", "OneDrive", "AWS",
"Tesla", "BYD", "BMW", "Mercedes-Benz", "Intel", "AMD",
"Nvidia", "Adobe", "Zoom", "Slack", "Netflix", "Spotify",
"Dell", "HP", "Lenovo", "Logitech", "Philips", "Dyson",
# 可以根据您的研究需要添加更多品牌
]
4.2 核心爬虫逻辑:Perplexity AI
我们将编写一个函数,负责驱动浏览器,向Perplexity AI提交提示词,并提取其生成的答案和引用来源。
import pandas as pd
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException, WebDriverException
import time
import re
import os
# --- Configuration ---
# 请根据您的Chromedriver路径进行修改
CHROMEDRIVER_PATH = "./chromedriver" # 或者直接添加到系统PATH中
PERPLEXITY_URL = "https://www.perplexity.ai/"
PROMPTS_FILE = "prompts.csv"
OUTPUT_FILE = "ai_search_brand_comparison.csv"
# 目标品牌列表,确保品牌名称是您希望匹配的完整名称
TARGET_BRANDS = [
"Sony", "Bose", "Apple", "Samsung", "Huawei", "Xiaomi",
"Google", "Microsoft", "Amazon", "Dropbox", "OneDrive", "AWS",
"Tesla", "BYD", "BMW", "Mercedes-Benz", "Intel", "AMD",
"Nvidia", "Adobe", "Zoom", "Slack", "Netflix", "Spotify",
"Dell", "HP", "Lenovo", "Logitech", "Philips", "Dyson",
# ... 更多品牌
]
# --- Helper Function for Brand Detection ---
def detect_brands(text, brands):
"""
在给定文本中检测目标品牌。使用正则表达式进行全词匹配。
"""
found_brands = []
if not text:
return []
text_lower = text.lower()
for brand in brands:
# 使用 b 进行全词匹配,避免匹配到品牌名称的子串
if re.search(r'b' + re.escape(brand.lower()) + r'b', text_lower):
found_brands.append(brand)
return found_brands
# --- Main Scraper Function for Perplexity AI ---
def scrape_perplexity(prompts, brands):
"""
爬取Perplexity AI,获取给定提示词下的品牌展现信息。
"""
# 配置Chrome浏览器选项
options = webdriver.ChromeOptions()
options.add_argument("--headless") # 无头模式,不显示浏览器界面
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("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")
options.add_argument("--window-size=1920,1080") # 设置窗口大小,避免某些元素在小窗口下不显示
# 初始化WebDriver
try:
service = Service(CHROMEDRIVER_PATH)
driver = webdriver.Chrome(service=service, options=options)
except WebDriverException as e:
print(f"Error initializing WebDriver: {e}")
print("Please ensure ChromeDriver is installed and its path is correct, or it's in your system PATH.")
return pd.DataFrame() # 返回空DataFrame
driver.set_page_load_timeout(60) # 设置页面加载超时
results = []
print(f"Starting scraping for {len(prompts)} prompts on Perplexity AI...")
for i, prompt in enumerate(prompts):
print(f"[{i+1}/{len(prompts)}] Processing prompt: '{prompt}'")
try:
driver.get(PERPLEXITY_URL)
# 等待搜索输入框出现
search_input = WebDriverWait(driver, 30).until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'input[placeholder*="Ask anything"]'))
)
# 清除输入框(以防万一)并输入提示词
search_input.clear()
search_input.send_keys(prompt)
search_input.submit() # Perplexity通常在Enter键后提交
# 等待AI答案框出现
# Perplexity的答案通常在一个特定的data-testid='answer-box'的div中
ai_summary_element = WebDriverWait(driver, 90).until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'div[data-testid="answer-box"]'))
)
ai_summary_text = ai_summary_element.text
# 提取引用来源
cited_sources_text = ""
try:
# 尝试点击“Sources”按钮或查找来源部分
# Perplexity的来源通常在答案下方,点击按钮会弹出modal
# 寻找包含“Sources”文本的按钮,然后点击
sources_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, "//button[contains(., 'Sources')]"))
)
sources_button.click()
# 等待来源modal出现
sources_modal = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'div[data-testid="sources-modal"]'))
)
# 提取modal中的链接文本
source_links = sources_modal.find_elements(By.CSS_SELECTOR, 'a')
cited_sources_text = "n".join([src.get_attribute('href') + " | " + src.text for src in source_links if src.get_attribute('href')])
# 关闭来源modal (通常是带有aria-label="Close"的按钮)
close_button = WebDriverWait(driver, 5).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, 'button[aria-label="Close"]'))
)
close_button.click()
WebDriverWait(driver, 5).until(EC.invisibility_of_element_located(sources_modal)) # 确认modal已关闭
except (TimeoutException, NoSuchElementException) as e:
print(f" Warning: Could not extract sources for prompt '{prompt}'. Details: {e}")
cited_sources_text = "N/A"
except Exception as e:
print(f" Unexpected error extracting sources for prompt '{prompt}': {e}")
cited_sources_text = "Error during source extraction."
# 检测品牌
brands_in_summary = detect_brands(ai_summary_text, brands)
brands_in_sources = detect_brands(cited_sources_text, brands)
results.append({
"Prompt": prompt,
"AI_Engine": "Perplexity AI",
"AI_Summary": ai_summary_text,
"Brands_in_Summary": ", ".join(brands_in_summary),
"Cited_Sources": cited_sources_text,
"Brands_in_Sources": ", ".join(brands_in_sources),
"Timestamp": pd.Timestamp.now()
})
except TimeoutException:
print(f" Error: Timeout while processing prompt '{prompt}'. Page took too long to load or elements not found.")
results.append({
"Prompt": prompt,
"AI_Engine": "Perplexity AI",
"AI_Summary": "Error: Timeout.",
"Brands_in_Summary": "",
"Cited_Sources": "Error: Timeout.",
"Brands_in_Sources": "",
"Timestamp": pd.Timestamp.now()
})
except NoSuchElementException as e:
print(f" Error: Element not found for prompt '{prompt}'. Details: {e}")
results.append({
"Prompt": prompt,
"AI_Engine": "Perplexity AI",
"AI_Summary": f"Error: Element not found ({e}).",
"Brands_in_Summary": "",
"Cited_Sources": f"Error: Element not found ({e}).",
"Brands_in_Sources": "",
"Timestamp": pd.Timestamp.now()
})
except Exception as e:
print(f" An unexpected error occurred for prompt '{prompt}': {e}")
results.append({
"Prompt": prompt,
"AI_Engine": "Perplexity AI",
"AI_Summary": f"Error: {e}",
"Brands_in_Summary": "",
"Cited_Sources": f"Error: {e}",
"Brands_in_Sources": "",
"Timestamp": pd.Timestamp.now()
})
finally:
# 实行负责任的爬取策略:随机延迟
sleep_time = 5 + (i % 5) * 2 # 5到13秒之间
print(f" Sleeping for {sleep_time} seconds...")
time.sleep(sleep_time)
driver.quit()
return pd.DataFrame(results)
# --- Main Execution Block ---
if __name__ == "__main__":
# 确保prompts.csv存在,如果不存在则创建一个示例
if not os.path.exists(PROMPTS_FILE):
print(f"'{PROMPTS_FILE}' not found. Creating a dummy file with 10 prompts.")
dummy_prompts = [
"Best noise-cancelling headphones for travel",
"How to choose a reliable cloud storage service",
"Top smartphones released in 2023",
"Compare virtual private networks",
"Advantages of using a smart home assistant",
"Review of the latest gaming consoles",
"Sustainable fashion brands to watch",
"Best laptops for programming",
"Guide to digital marketing tools",
"Future of electric vehicles"
]
pd.DataFrame({"Prompt": dummy_prompts}).to_csv(PROMPTS_FILE, index=False)
prompts_list = dummy_prompts
print(f"Dummy '{PROMPTS_FILE}' created. Please replace with your 100 prompts for full analysis.")
else:
try:
prompts_df = pd.read_csv(PROMPTS_FILE)
prompts_list = prompts_df['Prompt'].tolist()
if len(prompts_list) < 100:
print(f"Warning: '{PROMPTS_FILE}' contains only {len(prompts_list)} prompts. For a comprehensive study, please ensure it has 100 or more unique prompts.")
except Exception as e:
print(f"Error reading '{PROMPTS_FILE}': {e}. Using dummy prompts.")
prompts_list = [
"Best noise-cancelling headphones for travel", "How to choose a reliable cloud storage service"
] # Fallback to a very small list if CSV read fails
# 执行爬取
df_perplexity_results = scrape_perplexity(prompts_list, TARGET_BRANDS)
print("nPerplexity AI scraping completed.")
# 保存结果
if not df_perplexity_results.empty:
df_perplexity_results.to_csv(OUTPUT_FILE, index=False, encoding='utf-8-sig')
print(f"Results saved to '{OUTPUT_FILE}'")
# 打印部分结果以供快速预览
print("nSample Data from Perplexity AI:")
print(df_perplexity_results.head())
else:
print("No data was scraped. Check for errors during WebDriver initialization or scraping process.")
代码解析:
- 配置与初始化:设置了
CHROMEDRIVER_PATH,PERPLEXITY_URL,以及输入输出文件。TARGET_BRANDS列表定义了我们要追踪的品牌。 detect_brands函数:这是一个辅助函数,用于在给定的文本中,通过正则表达式进行大小写不敏感的全词匹配,找出所有提及的目标品牌。re.escape用于转义品牌名称中的特殊字符,b确保是全词匹配,避免“Apple”匹配到“Pineapple”这种情况。scrape_perplexity函数:webdriver.ChromeOptions():配置Chrome浏览器的行为,如--headless(无头模式,不在屏幕上显示浏览器窗口,适合服务器运行),--no-sandbox和--disable-dev-shm-usage(针对某些Linux环境),以及设置user-agent以模拟真实用户。- WebDriver初始化:通过
Service(CHROMEDRIVER_PATH)和webdriver.Chrome()启动浏览器实例。 - 页面加载与元素定位:
driver.get(PERPLEXITY_URL):访问Perplexity AI主页。WebDriverWait结合EC.presence_of_element_located:这是selenium中处理动态加载内容的关键。它会等待指定的元素(例如搜索输入框)出现在DOM中,最多等待30秒。search_input.send_keys(prompt):在输入框中输入提示词。search_input.submit():提交表单,触发搜索。
- 提取AI答案:等待AI生成的摘要文本所在的
div[data-testid="answer-box"]出现,并提取其.text内容。 - 提取引用来源:Perplexity AI的一大特点是其“Sources”部分。我们模拟点击“Sources”按钮,等待弹出的模态框(modal),然后提取其中所有链接的
href和文本。完成提取后,点击关闭按钮。 - 品牌检测与结果存储:对提取到的AI摘要和引用来源文本,分别调用
detect_brands函数,找出其中包含的所有目标品牌。将所有信息打包成字典,添加到results列表中。 - 错误处理:使用
try-except块捕获可能发生的TimeoutException、NoSuchElementException以及其他通用异常,确保爬虫的健壮性,即使某个提示词处理失败,也能继续执行。 - 频率控制:
time.sleep()是实现延迟的关键。这里我们使用5 + (i % 5) * 2来生成一个5到13秒之间的随机延迟,这有助于模拟人类行为,并降低被反爬的风险。 driver.quit():完成所有爬取后,务必关闭浏览器实例。
- 主执行块:
- 检查
prompts.csv文件是否存在,如果不存在则创建一个包含10个示例提示词的虚拟文件,方便测试。 - 读取提示词列表,并调用
scrape_perplexity函数执行爬取。 - 将结果保存到
OUTPUT_FILE(CSV格式),并打印前几行数据进行预览。
- 检查
4.3 扩展到其他AI搜索引擎(如Bing Copilot)
将上述方法扩展到Bing Copilot或Google SGE,其基本流程是相似的,但核心挑战在于:
- URL与界面元素差异:每个AI搜索引擎的URL、搜索输入框、答案区域和引用来源的CSS选择器或XPath都会不同。您需要手动检查这些页面的HTML结构来找到正确的选择器。
- 交互模式:某些AI可能需要先点击一个“开始聊天”按钮,或者其提交方式不是简单的
submit(),可能需要点击一个特定的发送按钮。 - 登录与验证码:Google SGE通常需要登录Google账户,并且可能在自动化过程中触发验证码,这会大大增加爬取难度。Bing Copilot有时也可能要求登录或弹出验证码。
- API可用性:如果有官方或非官方API,使用API通常比Web Scraping更稳定和高效,但API可能不提供完整的AI生成文本和来源信息。
Bing Copilot的爬取思路(伪代码):
# from selenium import webdriver
# from selenium.webdriver.common.by import By
# from selenium.webdriver.support.ui import WebDriverWait
# from selenium.webdriver.support import expected_conditions as EC
# import time
# import pandas as pd
# import re
#
# BING_COPILOT_URL = "https://copilot.microsoft.com/"
#
# def scrape_bing_copilot(prompts, brands):
# options = webdriver.ChromeOptions()
# options.add_argument("--headless")
# options.add_argument("--no-sandbox")
# options.add_argument("--disable-dev-shm-usage")
# options.add_argument("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")
#
# driver = webdriver.Chrome(options=options)
# driver.set_page_load_timeout(60)
# results = []
#
# for i, prompt in enumerate(prompts):
# print(f"[{i+1}/{len(prompts)}] Processing prompt: '{prompt}' on Bing Copilot")
# try:
# driver.get(BING_COPILOT_URL)
#
# # 1. 寻找聊天输入框
# # 这可能需要一些尝试来找到正确的CSS选择器或XPath
# # 假设输入框的ID是'chat-input'或者有特定的placeholder
# chat_input = WebDriverWait(driver, 30).until(
# EC.presence_of_element_located((By.XPATH, "//textarea[@placeholder='Ask me anything...']"))
# )
#
# chat_input.send_keys(prompt)
#
# # 2. 寻找并点击发送按钮
# # 假设发送按钮有一个特定的aria-label或class
# send_button = WebDriverWait(driver, 10).until(
# EC.element_to_be_clickable((By.XPATH, "//button[@aria-label='Submit']"))
# )
# send_button.click()
#
# # 3. 等待AI回复出现
# # Bing Copilot的回复通常在一个特定的聊天气泡或内容区域
# ai_response_area = WebDriverWait(driver, 60).until(
# EC.presence_of_element_located((By.CSS_SELECTOR, 'div.response-content')) # 这是一个假设的CSS选择器
# )
# ai_summary_text = ai_response_area.text
#
# # 4. 提取引用来源 (Bing Copilot的引用可能以脚注形式出现,需要仔细解析)
# cited_sources_text = ""
# try:
# # 尝试查找所有链接或特定引用标记
# source_elements = ai_response_area.find_elements(By.TAG_NAME, 'a')
# cited_sources_text = "n".join([src.get_attribute('href') + " | " + src.text for src in source_elements if src.get_attribute('href')])
# except Exception as e:
# print(f" Warning: Could not extract sources for prompt '{prompt}' on Bing Copilot: {e}")
# cited_sources_text = "N/A"
#
# brands_in_summary = detect_brands(ai_summary_text, brands)
# brands_in_sources = detect_brands(cited_sources_text, brands)
#
# results.append({
# "Prompt": prompt,
# "AI_Engine": "Bing Copilot",
# "AI_Summary": ai_summary_text,
# "Brands_in_Summary": ", ".join(brands_in_summary),
# "Cited_Sources": cited_sources_text,
# "Brands_in_Sources": ", ".join(brands_in_sources),
# "Timestamp": pd.Timestamp.now()
# })
#
# except Exception as e:
# print(f" Error processing prompt '{prompt}' on Bing Copilot: {e}")
# results.append({
# "Prompt": prompt, "AI_Engine": "Bing Copilot", "AI_Summary": f"Error: {e}",
# "Brands_in_Summary": "", "Cited_Sources": "", "Brands_in_Sources": "",
# "Timestamp": pd.Timestamp.now()
# })
# finally:
# time.sleep(5 + (i % 5) * 2)
#
# driver.quit()
# return pd.DataFrame(results)
#
# # if __name__ == "__main__":
# # # ... (load prompts_list)
# # df_bing_results = scrape_bing_copilot(prompts_list, TARGET_BRANDS)
# # if not df_bing_results.empty:
# # df_bing_results.to_csv("bing_copilot_brand_comparison.csv", index=False, encoding='utf-8-sig')
# # print("Bing Copilot scraping completed and results saved.")
请注意,上述Bing Copilot的伪代码中的CSS选择器和XPath都是假设的,实际使用时需要根据Bing Copilot当前的网页结构进行精确查找。
5. 数据分析与洞察
爬取完成后,我们得到一个包含丰富数据的CSV文件。接下来,我们将利用pandas对数据进行深入分析,提取有价值的洞察。
5.1 加载与初步处理数据
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np # 用于处理NaN值
# 加载数据
try:
df_results = pd.read_csv(OUTPUT_FILE)
print(f"nSuccessfully loaded {len(df_results)} records from {OUTPUT_FILE}")
except FileNotFoundError:
print(f"Error: {OUTPUT_FILE} not found. Please run the scraping script first.")
exit()
# 将逗号分隔的品牌字符串转换为列表,便于分析
df_results['Brands_in_Summary_List'] = df_results['Brands_in_Summary'].apply(
lambda x: [b.strip() for b in str(x).split(',')] if pd.notna(x) and str(x).strip() else []
)
df_results['Brands_in_Sources_List'] = df_results['Brands_in_Sources'].apply(
lambda x: [b.strip() for b in str(x).split(',')] if pd.notna(x) and str(x).strip() else []
)
# 确保所有提示词都被处理
print(f"Total prompts processed: {len(df_results)}")
print(f"Prompts with errors: {df_results[df_results['AI_Summary'].str.contains('Error')].shape[0]}")
5.2 整体品牌提及频率分析
我们可以统计每个品牌在AI摘要和引用来源中被提及的总次数。
# 汇总所有AI摘要中的品牌提及
all_summary_mentions = [brand for sublist in df_results['Brands_in_Summary_List'] for brand in sublist if brand]
summary_mentions_count = pd.Series(all_summary_mentions).value_counts().reset_index()
summary_mentions_count.columns = ['Brand', 'Summary_Mentions']
print("n--- Overall Brand Mentions in AI Summaries ---")
print(summary_mentions_count.to_markdown(index=False))
# 汇总所有引用来源中的品牌提及
all_source_mentions = [brand for sublist in df_results['Brands_in_Sources_List'] for brand in sublist if brand]
source_mentions_count = pd.Series(all_source_mentions).value_counts().reset_index()
source_mentions_count.columns = ['Brand', 'Source_Mentions']
print("n--- Overall Brand Mentions in Cited Sources ---")
print(source_mentions_count.to_markdown(index=False))
# 合并两个统计结果进行对比
brand_mentions_combined = pd.merge(
summary_mentions_count,
source_mentions_count,
on='Brand',
how='outer'
).fillna(0)
brand_mentions_combined['Total_Mentions'] = brand_mentions_combined['Summary_Mentions'] + brand_mentions_combined['Source_Mentions']
brand_mentions_combined = brand_mentions_combined.sort_values(by='Total_Mentions', ascending=False).reset_index(drop=True)
print("n--- Combined Brand Mentions (Summary vs. Sources) ---")
print(brand_mentions_combined.to_markdown(index=False))
示例表格:Combined Brand Mentions (Summary vs. Sources)
| Brand | Summary_Mentions | Source_Mentions | Total_Mentions |
|---|---|---|---|
| Apple | 15 | 8 | 23 |
| Samsung | 12 | 5 | 17 |
| Sony | 9 | 4 | 13 |
| 7 | 6 | 13 | |
| Microsoft | 6 | 4 | 10 |
| Tesla | 5 | 3 | 8 |
| Bose | 4 | 2 | 6 |
| Xiaomi | 3 | 1 | 4 |
| Dropbox | 2 | 1 | 3 |
| OneDrive | 1 | 0 | 1 |
| … | … | … | … |
- 洞察:通过这个表格,我们可以清晰地看到哪些品牌在AI生成的摘要中被直接提及更多,哪些更多地出现在引用来源中。例如,"Apple"可能在摘要中被直接推荐,而"Google"可能因为其广泛的服务和作为信息源而被更多地引用。
5.3 品牌在多少个提示词中被提及
分析每个品牌在总共100个提示词中,有多少个提示词的AI答案中被提及,这反映了品牌的广度。
# 品牌在多少个不同的提示词中被提及 (AI摘要)
brand_presence_summary_count = {}
for brand in TARGET_BRANDS:
# 统计包含该品牌的提示词数量
count = df_results['Brands_in_Summary_List'].apply(lambda x: brand in x).sum()
if count > 0: # 只记录有提及的品牌
brand_presence_summary_count[brand] = count
brand_presence_summary_df = pd.DataFrame(
list(brand_presence_summary_count.items()),
columns=['Brand', 'Prompts_Mentioned_in_Summary']
).sort_values(by='Prompts_Mentioned_in_Summary', ascending=False).reset_index(drop=True)
print("n--- Number of Prompts Mentioning Each Brand (in AI Summary) ---")
print(brand_presence_summary_df.to_markdown(index=False))
# 品牌在多少个不同的提示词中被提及 (引用来源)
brand_presence_source_count = {}
for brand in TARGET_BRANDS:
count = df_results['Brands_in_Sources_List'].apply(lambda x: brand in x).sum()
if count > 0:
brand_presence_source_count[brand] = count
brand_presence_source_df = pd.DataFrame(
list(brand_presence_source_count.items()),
columns=['Brand', 'Prompts_Mentioned_in_Sources']
).sort_values(by='Prompts_Mentioned_in_Sources', ascending=False).reset_index(drop=True)
print("n--- Number of Prompts Mentioning Each Brand (in Cited Sources) ---")
print(brand_presence_source_df.to_markdown(index=False))
# 合并并计算总提及提示词数(去重)
def count_unique_prompt_mentions(df, brand, summary_col, source_col):
summary_mentions = df[df[summary_col].apply(lambda x: brand in x)]
source_mentions = df[df[source_col].apply(lambda x: brand in x)]
# 合并两个DataFrame并根据'Prompt'列去重
combined_mentions = pd.concat([summary_mentions, source_mentions]).drop_duplicates(subset=['Prompt'])
return combined_mentions.shape[0]
total_unique_prompt_mentions = {}
for brand in TARGET_BRANDS:
count = count_unique_prompt_mentions(df_results, brand, 'Brands_in_Summary_List', 'Brands_in_Sources_List')
if count > 0:
total_unique_prompt_mentions[brand] = count
total_unique_prompt_mentions_df = pd.DataFrame(
list(total_unique_prompt_mentions.items()),
columns=['Brand', 'Total_Unique_Prompts_Mentioned']
).sort_values(by='Total_Unique_Prompts_Mentioned', ascending=False).reset_index(drop=True)
print("n--- Total Unique Prompts Mentioning Each Brand (Summary or Sources) ---")
print(total_unique_prompt_mentions_df.to_markdown(index=False))
示例表格:Total Unique Prompts Mentioning Each Brand
| Brand | Total_Unique_Prompts_Mentioned |
|---|---|
| Apple | 18 |
| Samsung | 15 |
| 12 | |
| Sony | 11 |
| Microsoft | 10 |
| Tesla | 7 |
| Bose | 5 |
| Huawei | 4 |
| Xiaomi | 3 |
| … | … |
- 洞察:这个指标更直接地反映了品牌在AI搜索中的“覆盖面”。一个品牌可能被提及很多次,但只集中在少数几个提示词下;而另一个品牌可能在更多样化的提示词下都有所展现。
5.4 品牌共现分析(Brand Co-occurrence)
了解哪些品牌经常一起被提及,可以揭示竞争格局或互补关系。
# 创建一个空的共现矩阵
co_occurrence_matrix = pd.DataFrame(0, index=TARGET_BRANDS, columns=TARGET_BRANDS)
# 遍历每个提示词的AI摘要,更新共现矩阵
for brands_list in df_results['Brands_in_Summary_List']:
unique_brands_in_prompt = sorted(list(set(brands_list))) # 对当前prompt中的品牌去重排序
for i, brand1 in enumerate(unique_brands_in_prompt):
for j, brand2 in enumerate(unique_brands_in_prompt):
if brand1 != brand2: # 不计算品牌与自身的共现
co_occurrence_matrix.loc[brand1, brand2] += 1
print("n--- Brand Co-occurrence Matrix (in AI Summaries) ---")
# 打印一部分或过滤掉0值的共现对
co_occurrence_filtered = co_occurrence_matrix.stack()
co_occurrence_filtered = co_occurrence_filtered[co_occurrence_filtered > 0].sort_values(ascending=False).reset_index()
co_occurrence_filtered.columns = ['Brand1', 'Brand2', 'Co_occurrence_Count']
print(co_occurrence_filtered.head(10).to_markdown(index=False)) # 打印前10个共现频率最高的对
示例表格:Brand Co-occurrence (Top 10)
| Brand1 | Brand2 | Co_occurrence_Count |
|---|---|---|
| Apple | Samsung | 8 |
| Samsung | Apple | 8 |
| Sony | Bose | 4 |
| Bose | Sony | 4 |
| Apple | 3 | |
| Apple | 3 | |
| Tesla | BYD | 2 |
| BYD | Tesla | 2 |
| Huawei | Samsung | 2 |
| Samsung | Huawei | 2 |
- 洞察:共现矩阵可以帮助我们识别直接竞争对手(如Apple和Samsung经常一起被提及进行比较),或者互补的生态系统(如Google和Nest智能家居产品)。
5.5 跨AI引擎对比(如果爬取了多个引擎)
如果成功爬取了Bing Copilot或其他AI引擎的数据,我们可以将所有数据合并,进行跨引擎的对比分析。
# 假设我们已经有了df_perplexity_results 和 df_bing_results (通过运行上面的伪代码)
# all_results_df = pd.concat([df_perplexity_results, df_bing_results], ignore_index=True)
# 示例:按AI引擎分组,计算各品牌在AI摘要中的提及次数
# if 'all_results_df' in locals(): # 检查all_results_df是否存在
# engine_brand_mentions = all_results_df.groupby('AI_Engine')['Brands_in_Summary_List'].apply(
# lambda x: pd.Series([brand for sublist in x for brand in sublist if brand]).value_counts()
# ).unstack(fill_value=0)
# print("n--- Brand Mentions by AI Engine (in AI Summaries) ---")
# print(engine_brand_mentions.to_markdown())
# 示例表格:Brand Mentions by AI Engine (in AI Summaries)
# | Brand | Perplexity AI | Bing Copilot |
# |:--------------|--------------:|-------------:|
# | Apple | 15 | 10 |
# | Samsung | 12 | 8 |
# | Sony | 9 | 7 |
# | Google | 7 | 9 |
# | Microsoft | 6 | 11 |
# | Tesla | 5 | 4 |
# | Bose | 4 | 3 |
# | Xiaomi | 3 | 2 |
# | ... | ... | ... |
- 洞察:这种对比能揭示不同AI引擎的偏好和信息源倾向。例如,一个引擎可能更侧重于技术规格和评测,而另一个可能更倾向于用户体验和市场份额,从而影响品牌的展现。这对于针对不同AI平台进行优化至关重要。
6. 挑战、局限与未来展望
本次实战虽然提供了一个强大的框架,但在实际操作中仍面临诸多挑战和局限性:
- 反爬机制:AI搜索引擎的反爬机制会不断升级,包括更复杂的JS混淆、动态加载、验证码(如hCaptcha, reCAPTCHA)、IP封禁等,需要持续维护和更新爬虫策略。
- 界面变化:AI搜索引擎的UI/UX可能频繁更新,导致CSS选择器或XPath失效,需要定期检查和调整代码。
- 账号与登录:部分AI服务需要登录才能访问完整功能或更长的对话历史,自动化登录会增加复杂性。
- 内容理解的深度:我们目前仅停留在品牌名称的简单提及,更高级的分析如情感分析、品牌与特定属性的关联度、品牌作为解决方案的出现频率等,需要结合自然语言处理(NLP)技术。
- 数据量与时效性:100个提示词是基础,但要获得更全面的市场洞察,可能需要更多提示词和更频繁的爬取。
- 伦理与合规:始终要遵守目标网站的服务条款和相关法律法规,避免滥用。
尽管有这些挑战,本次实战为我们提供了一个坚实的基础。未来的工作可以包括:
- 集成更多AI引擎:扩展爬虫以覆盖更多的AI搜索引擎。
- 高级NLP分析:引入情感分析模型,评估品牌提及的语气;使用命名实体识别(NER)进一步细化品牌相关信息的提取。
- 可视化仪表盘:利用
Dash、Streamlit或Jupyter Widgets等工具,构建交互式数据可视化仪表盘,实时监控品牌表现。 - 地理位置与语言:考虑不同地区和语言环境下AI搜索结果的差异。
7. 结语
本次讲座深入探讨了如何利用Python爬虫技术,对比分析AI搜索引擎在大量提示词下的品牌展现。我们从理论背景出发,构建了严谨的方法论,并提供了详细的Python代码实现,涵盖了数据准备、自动化爬取以及基于pandas的数据分析。
通过这种实战方法,品牌和营销专家能够获得前所未有的洞察力,理解其品牌如何在AI生成的世界中被感知和呈现。这不仅是技术能力的展示,更是适应AI时代数字营销新范式,掌握品牌未来命运的关键一步。愿各位同仁能将今日所学付诸实践,不断探索,为品牌在智能时代赢得先机。
谢谢大家!