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

如何解决Selenium爬取谷歌地图评论输出结构错乱错行问题

问题根源

你当前脚本出现评论拆分、数据错位的核心原因有3点:

  • 元素定位逻辑错误:全局抓取所有同用户名、评分、评论、时间类名的元素后直接用zip拼接,谷歌地图评论DOM中长评论展开、带附图/商家回复的评论会插入额外同class标签,会导致四个字段的列表长度不一致,拼接时直接错位,甚至把同一条评论的换行拆成独立条目。
  • 字段映射写反:循环赋值时将评分字段存了发布时间内容、发布时间字段存了评论内容,本身就存在字段串位问题。
  • 滚动加载逻辑不完整:固定仅滚动2次就停止,未等所有评论加载完成,且未处理评论内容里的换行符,导出csv时会被识别为新行。
修复方案

核心修改原则:不要全局单独抓取各字段元素,先定位每一条独立评论的父容器,再在单个容器内提取对应字段,从根源上避免不同评论的元素混淆。同时替换高版本Selenium已废弃的find_element_by_*旧写法,修正字段映射、滚动逻辑、换行问题。

修正后的可运行核心代码:

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 pandas as pd
import time

PATH = "chromedriver.exe"
options = webdriver.ChromeOptions()
driver = webdriver.Chrome(executable_path=PATH, options=options)
wait = WebDriverWait(driver, 10)

url = 'https://www.google.com/maps/place/Lazeo+Paris+11e/@48.8532051,2.3859464,17z/data=!3m1!4b1!4m5!3m4!1s0x47e6738875606957:0xdfb3822564e33888!8m2!3d48.8532051!4d2.3881404'
driver.get(url)
time.sleep(5)

# 点击进入评论页
wait.until(EC.element_to_be_clickable((By.XPATH, '//*[@id="QA0Szd"]/div/div/div[1]/div[2]/div/div[1]/div/div/div[2]/div[1]/div[1]/div[2]/div/div[1]/span[1]/span/span/span[2]/span[1]/button'))).click()
time.sleep(3)

# 滚动加载所有评论
SCROLL_PAUSE_TIME = 2
scroll_container = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="QA0Szd"]/div/div/div[1]/div[2]/div/div[1]/div/div/div[2]')))
last_height = driver.execute_script("return arguments[0].scrollHeight", scroll_container)
while True:
    driver.execute_script('arguments[0].scrollTo(0, arguments[0].scrollHeight);', scroll_container)
    time.sleep(SCROLL_PAUSE_TIME)
    new_height = driver.execute_script("return arguments[0].scrollHeight", scroll_container)
    if new_height == last_height:
        break
    last_height = new_height

# 展开所有长评论
more_buttons = driver.find_elements(By.XPATH, '//button[text()="More"]')
for btn in more_buttons:
    try:
        driver.execute_script("arguments[0].click();", btn)
    except:
        pass
time.sleep(2)

# 逐条提取评论数据
review_items = driver.find_elements(By.CLASS_NAME, "jftiEf")
name_list = []
stars_list = []
review_list = []
duration_list = []

for item in review_items:
    # 单条评论内提取字段,加异常捕获避免空值中断
    try:
        name = item.find_element(By.CLASS_NAME, "d4r55").text
    except:
        name = ""
    try:
        # 从aria-label读评分,比取text更稳定
        stars = item.find_element(By.CLASS_NAME, "kvMYJc").get_attribute("aria-label")
    except:
        stars = ""
    try:
        # 替换评论内换行符,避免导出csv时拆行
        review = item.find_element(By.CLASS_NAME, "wiI7pd").text.strip().replace("\n", " ")
    except:
        review = ""
    try:
        duration = item.find_element(By.CLASS_NAME, "rsqaWe").text
    except:
        duration = ""
    
    name_list.append(name)
    stars_list.append(stars)
    review_list.append(review)
    duration_list.append(duration)

# 导出数据
review_df = pd.DataFrame(
    {'name': name_list,
     'rating': stars_list,
     'review': review_list,
     'duration': duration_list})
review_df.to_csv('google_review.csv', index=False, encoding='utf-8-sig')
print(review_df)

driver.quit()
优化点说明
  • 每条评论以独立父容器为单位提取字段,完全避免跨评论元素错位问题。
  • 评论内容内的换行符统一替换为空格,不会出现单条评论被拆成csv多行的问题。
  • 评分从元素的aria-label属性读取,不会因为样式加载问题拿到空值。
  • 滚动逻辑改为判断容器高度不再变化才停止,确保所有评论都加载完成,不会漏数。
  • 点击展开长评论时用JS触发,避免元素被遮挡导致点击失败。
  • 每个字段提取加异常捕获,遇到空值不会中断整个爬取流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 22:15:45