如何用Python Selenium高效抓取Yahoo Finance论坛带回复的评论?
抓取Yahoo Finance社区评论及回复的有效方案
一、自动展开所有回复
Yahoo Finance的评论回复默认折叠,需通过循环操作加载全部内容:
- 先滚动页面加载所有主评论:循环执行
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);"),每次滚动后等待2-3秒,直到页面高度不再变化(说明所有主评论已加载完成)。 - 遍历每个主评论容器,定位其中的「View more replies」按钮(可通过文本或CSS选择器定位,比如
//button[contains(text(), 'View more replies')]),循环点击该按钮,直到按钮消失(用WebDriverWait判断元素是否不存在)。每次点击后需等待回复加载完成。
二、关联主评论与回复(无唯一ID的解决方法)
官方未给评论分配唯一ID,可通过容器层级关联和自定义标识解决:
- 以主评论的父容器为基准:先定位所有主评论的容器元素(需根据页面实际结构调整选择器,比如
.comment-container),对每个容器单独处理——在容器内提取主评论内容,再在同一容器内提取所有回复,天然保证主评论和回复的关联关系。 - 生成自定义唯一标识:对每条主评论,用「发布时间+作者昵称+内容哈希值」组合生成标识(比如
hashlib.md5(f"{time}_{author}_{content}".encode()).hexdigest()),避免重复抓取,也方便后续数据去重。
三、处理已删除的评论
已删除的评论通常会显示固定提示文本(比如「Comment has been removed」),提取时直接判断:
- 在提取评论内容前,先检查评论元素内是否包含删除提示文本,若包含则标记该评论为「已删除」,跳过内容提取或仅记录状态;若未包含,则正常提取作者、时间、内容等信息。
核心代码示例
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 hashlib import random def get_comment_id(time_str, author, content): # 生成自定义唯一标识 raw_str = f"{time_str}_{author}_{content}" return hashlib.md5(raw_str.encode()).hexdigest() driver = webdriver.Chrome() driver.get("https://finance.yahoo.com/quote/TSLA/community?p=TSLA") wait = WebDriverWait(driver, 10) # 滚动加载所有主评论 last_height = driver.execute_script("return document.body.scrollHeight") while True: driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") time.sleep(random.uniform(2,4)) new_height = driver.execute_script("return document.body.scrollHeight") if new_height == last_height: break last_height = new_height # 遍历所有主评论容器 comments = [] comment_containers = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".Py(10px) P(0)"))) for container in comment_containers: comment_data = {} # 处理主评论 try: # 判断是否已删除 container.find_element(By.CSS_SELECTOR, ".Fz(14px) C($c-fuji-grey-l)") comment_data["status"] = "deleted" except: comment_data["status"] = "normal" comment_data["author"] = container.find_element(By.CSS_SELECTOR, ".C(#959595) Fz(12px)").text comment_data["time"] = container.find_element(By.CSS_SELECTOR, ".Fz(12px) C(#959595)").text.split("·")[-1].strip() comment_data["content"] = container.find_element(By.CSS_SELECTOR, ".Mt(1) Fz(14px) Lh(1.4)").text comment_data["id"] = get_comment_id(comment_data["time"], comment_data["author"], comment_data["content"]) # 展开所有回复 while True: try: view_more_btn = container.find_element(By.XPATH, ".//button[contains(text(), 'View more replies')]") driver.execute_script("arguments[0].click();", view_more_btn) time.sleep(random.uniform(1,3)) except: break # 提取回复 replies = [] reply_elements = container.find_elements(By.CSS_SELECTOR, ".Py(8px) Bdbw(1px) Bdbc($c-fuji-grey-c)") for reply in reply_elements: reply_data = {} try: reply.find_element(By.CSS_SELECTOR, ".Fz(14px) C($c-fuji-grey-l)") reply_data["status"] = "deleted" except: reply_data["status"] = "normal" reply_data["author"] = reply.find_element(By.CSS_SELECTOR, ".C(#959595) Fz(12px)").text reply_data["time"] = reply.find_element(By.CSS_SELECTOR, ".Fz(12px) C(#959595)").text.split("·")[-1].strip() reply_data["content"] = reply.find_element(By.CSS_SELECTOR, ".Mt(1) Fz(14px) Lh(1.4)").text replies.append(reply_data) comment_data["replies"] = replies comments.append(comment_data) # 输出或存储数据 print(comments) driver.quit()
注意事项
- 页面元素选择器可能随Yahoo Finance更新变化,需定期检查并调整CSS/XPath选择器。
- 使用随机延迟替代固定等待时间,降低触发反爬机制的概率。
- 若遇到登录限制,可提前登录账号后保存浏览器Cookie,再用Selenium加载Cookie绕过登录。
内容的提问来源于stack exchange,提问作者nganlong
相关产品推荐
相关产品推荐

