Yelp评论爬取:用户ID获取及非推荐评论区适配问题
Yelp评论爬取与虚假评论检测实操方案
一、核心字段获取逻辑
需要补充的4个字段,全部依赖评论者的个人主页数据,核心逻辑是:从评论区提取用户ID,再爬取用户主页的统计信息和评论时间序列:
- 评论者Yelp注册日期:用户主页顶部的"Joined"日期
- 总评论数:用户主页的评论统计数字
- 平均评分:用户主页显示的平均星级
- 评论发布前后1天内用户发评数:遍历用户所有评论的时间,筛选目标日期前后1天的数量(排除当前评论本身)
二、常规评论区爬取优化与错误排查
1. 用户ID提取方法
评论区中每个用户的名称/头像链接都包含userid参数,比如/user_details?userid=abc123-xyz,用正则表达式userid=([a-zA-Z0-9-]+)即可快速提取。
2. 字段爬取代码实现
import requests from bs4 import BeautifulSoup import pandas as pd from datetime import datetime, timedelta from dateutil.parser import parse # 需安装python-dateutil:pip install python-dateutil def get_user_profile(user_id): headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"} user_url = f"https://www.yelp.com/user_details?userid={user_id}" resp = requests.get(user_url, headers=headers) soup = BeautifulSoup(resp.text, "lxml") # 注册日期 join_date_elem = soup.find("div", class_="user-profile-header__join-date") join_date = parse(join_date_elem.text.strip().replace("Joined ", "")) # 总评论数 total_reviews_elem = soup.find("span", class_="review-count") total_reviews = int(total_reviews_elem.text.strip().split()[0]) # 平均评分 avg_rating_elem = soup.find("div", class_="average-rating") avg_rating = float(avg_rating_elem.find("img")["alt"].split()[0]) # 提取所有评论的发布日期 review_date_list = [] review_blocks = soup.find_all("div", class_="review-content") for block in review_blocks: date_str = block.find("span", class_="rating-qualifier").text.strip() review_date = parse(date_str) review_date_list.append(review_date) return { "join_date": join_date, "total_reviews": total_reviews, "avg_rating": avg_rating, "review_dates": review_date_list } def calculate_nearby_reviews(target_date, review_dates): time_window = timedelta(days=1) start = target_date - time_window end = target_date + time_window count = sum(1 for dt in review_dates if start <= dt <= end) return count - 1 # 减去当前评论本身 # 示例调用:假设已从评论区拿到user_id和该评论的target_date # user_data = get_user_profile("xxx-xxx-xxx") # nearby_count = calculate_nearby_reviews(target_date, user_data["review_dates"])
3. 常见错误解决
- 请求被拦截:Yelp反爬严格,必须携带真实
User-Agent,避免短时间内高频请求,必要时加入代理IP池。 - 元素定位失败:Yelp页面类名会不定期更新,爬取前用浏览器开发者工具核对最新的CSS类名,不要硬编码旧选择器。
- 日期解析失败:用户评论日期格式不统一(如
5/12/2023或May 12, 2023),用dateutil.parser.parse自动识别比手动写正则更可靠。
三、非推荐评论区爬取适配
非推荐评论区URL格式为https://www.yelp.com/not_recommended_reviews/[商家标识],和常规评论区的差异点及适配方案:
- 评论加载方式:默认只显示少量评论,需要模拟滚动或点击"Load More"按钮加载全部内容,推荐用Selenium实现:
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 def scrape_not_recommended_reviews(biz_url): driver = webdriver.Chrome() driver.get(biz_url) wait = WebDriverWait(driver, 10) # 循环点击加载更多,直到按钮消失 while True: try: load_btn = wait.until(EC.element_to_be_clickable((By.XPATH, "//button[contains(text(), 'Load More')]"))) load_btn.click() time.sleep(2) except: break # 提取所有用户ID user_links = driver.find_elements(By.CSS_SELECTOR, ".user-display-name a") user_ids = [] for link in user_links: href = link.get_attribute("href") user_id = href.split("userid=")[1] user_ids.append(user_id) driver.quit() return user_ids # 调用示例 # biz_url = "https://www.yelp.com/not_recommended_reviews/gelati-celesti-virginia-beach-2" # user_ids = scrape_not_recommended_reviews(biz_url)
- 后续字段爬取:非推荐评论区的用户主页结构和常规评论区完全一致,直接复用上面的
get_user_profile函数即可。
四、Pandas虚假评论分析方向
将爬取的字段合并到评论CSV后,可通过以下特征识别可疑评论:
- 注册时间不足30天但总评论数超过20条的用户
- 平均评分等于5.0或1.0的极端用户
- 单条评论前后1天内发布评论数超过3条的用户
- 评论内容重复率高(可结合
sklearn的文本特征向量检测)
内容的提问来源于stack exchange,提问作者Y0hno
相关产品推荐
相关产品推荐

