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
相关产品推荐
相关产品推荐

