You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Selenium爬取TripAdvisor酒店评论分页失效如何解决

核心问题定位

你的代码分页爬取失败是几个低级错误叠加导致的:

  • 定位Next按钮时用By.CLASS_NAME传入了带空格的多类名ui_button nav next primary ,Selenium的CLASS_NAME定位器仅支持单个类名,带空格的参数永远找不到目标元素,你之前注释掉的XPath定位写法才是正确的。
  • 长评论展开逻辑仅触发了第一个"Read more"按钮,同页其他折叠评论不会被展开,会漏爬内容。
  • 点击下一页后没有等待评论区重新加载,直接执行提取逻辑会拿到上一页的旧数据,甚至触发元素不存在的报错。
  • CSV写入逻辑不统一:表头用逗号做分隔符,内容用分号做分隔符,后续用表格工具打开会出现列错位。
最优修复方案

你已经观察到TripAdvisor的分页URL规律:每页10条评论,从第二页开始URL会拼接-or{offset}-字段,offset值从10开始每页递增10。直接构造URL跳转的稳定性远高于模拟点击Next按钮,不会被前端弹窗、元素遮挡、动态属性变化影响。
修复逻辑如下:

  • 第一页访问原始URL,后续页面直接按规则拼接URL跳转
  • 每一页加载完成后先滚动到评论区触发懒加载,逐个点击所有可见的"Read more"按钮展开长评论
  • 等评论内容完全渲染后再提取标题和正文
  • 统一CSV分隔符,避免格式错乱

修复后可直接运行的代码

import time
import csv
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
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

# 配置项
TOTAL_PAGES = 10  # 需要爬取的总页数
BASE_URL = "https://www.tripadvisor.com/Hotel_Review-g562644-d1490165-Reviews-Parador_de_Alcala_de_Henares-Alcala_De_Henares.html"
PAGE_URL_TPL = "https://www.tripadvisor.com/Hotel_Review-g562644-d1490165-Reviews-or{offset}-Parador_de_Alcala_de_Henares-Alcala_De_Henares.html"

# 初始化CSV文件,统一用分号作为分隔符
with open('reviews_hotel_9.csv', 'w', encoding="utf-8", newline='') as f:
    writer = csv.writer(f, delimiter=';')
    writer.writerow(['titles', 'reviews'])

# 启动浏览器
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver.maximize_window()

# 加载首页并处理cookie弹窗
driver.get(BASE_URL)
time.sleep(3)
try:
    driver.find_element(By.XPATH, '//*[@id="onetrust-accept-btn-handler"]').click()
except:
    pass

# 逐页爬取
for page_idx in range(TOTAL_PAGES):
    print(f"正在爬取第 {page_idx+1} 页")
    # 滚动到评论区位置,触发懒加载
    driver.execute_script("window.scrollTo(0, document.querySelector('[data-test-target=reviews-tab]').offsetTop)")
    time.sleep(2)

    # 逐个展开所有折叠的长评论
    try:
        expand_btns = WebDriverWait(driver, 10).until(
            EC.presence_of_all_elements_located((By.XPATH, '//span[text()="Read more"]/parent::button'))
        )
        for btn in expand_btns:
            try:
                driver.execute_script("arguments[0].click();", btn)
                time.sleep(0.2)
            except:
                continue
    except TimeoutException:
        pass

    # 提取当前页所有评论标题和内容
    titles = driver.find_elements(By.XPATH, '//div[@class="KgQgP MC _S b S6 H5 _a"]/a/span')
    reviews = driver.find_elements(By.XPATH, '//q[@class="QewHA H4 _a"]/span')

    # 写入CSV
    with open('reviews_hotel_9.csv', 'a', encoding="utf-8", newline='') as f:
        writer = csv.writer(f, delimiter=';')
        for i in range(len(titles)):
            try:
                writer.writerow([titles[i].text.strip(), reviews[i].text.strip()])
            except:
                continue

    # 非最后一页时跳转到下一页,等待评论区加载完成再进入下一轮
    if page_idx != TOTAL_PAGES - 1:
        next_offset = (page_idx + 1) * 10
        driver.get(PAGE_URL_TPL.format(offset=next_offset))
        WebDriverWait(driver, 20).until(
            EC.presence_of_element_located((By.XPATH, '//q[@class="QewHA H4 _a"]/span'))
        )
        time.sleep(1)

driver.quit()
print("全部页面爬取完成")
额外优化建议
  • 切换全语言选项时不要用写死的component_14这类ID,这类ID是前端动态生成的,页面刷新就会变化,直接通过"All languages"文本定位元素稳定性更高。
  • 爬取时可以给每页间隔加个0.5-2秒的随机延迟,避免请求太频繁触发反爬拦截。
  • 如果需要爬取该酒店的全部评论,可以先从首页提取评论总条数,除以10向上取整得到总页数,不需要手动写死页数。

内容的提问来源于stack exchange,提问作者Ventor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 19:15:39