如何解决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
相关产品推荐
相关产品推荐

