首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >实战:爬取美团外卖商家评分与销量——从零开始的完整指南

实战:爬取美团外卖商家评分与销量——从零开始的完整指南

原创
作者头像
富贵软件
发布2025-11-21 16:30:36
发布2025-11-21 16:30:36
120
举报
文章被收录于专栏:编程教程编程教程

一、为什么需要爬取美团外卖数据?

在餐饮外卖行业,商家评分和销量是消费者决策的核心依据。对于商家运营者,分析竞品数据可优化定价策略;对于市场调研者,掌握区域销量分布能洞察消费趋势。美团外卖作为国内最大外卖平台,其数据具有极高的商业价值。但手动收集效率低下,本文将通过Python爬虫技术,实现自动化数据采集。

二、技术选型:工具与原理

1. 核心工具包

  • Requests:发送HTTP请求获取网页内容
  • BeautifulSoup:解析静态HTML结构
  • Selenium:模拟浏览器行为处理动态加载
  • Pandas:数据清洗与存储
  • 代理IP池:突破反爬机制

2. 美团外卖数据特点

美团采用AJAX动态加载技术,商家列表和详情页数据通过接口分批获取。例如:

  • 商家列表接口:https://meishi.meituan.com/api/v1/poi/list
  • 返回格式:JSON结构包含商家ID、名称、评分、月销量等字段

三、实战步骤:从环境搭建到数据落地

1. 环境准备

代码语言:javascript
复制
pip install requests beautifulsoup4 selenium pandas fake_useragent

安装ChromeDriver(需与浏览器版本匹配),配置环境变量。

2. 基础爬虫实现(静态页面解析)

代码语言:javascript
复制
import requests
from bs4 import BeautifulSoup
import pandas as pd

def get_static_data(url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
    }
    response = requests.get(url, headers=headers)
    soup = BeautifulSoup(response.text, 'html.parser')
    
    shops = []
    for item in soup.find_all('div', class_='shop-item'):
        name = item.find('h3').text.strip()
        rating = item.find('span', class_='rating').text
        sales = item.find('span', class_='sales').text.split('月售')[1].strip()
        shops.append({'name': name, 'rating': rating, 'sales': sales})
    
    return pd.DataFrame(shops)

# 示例调用
df = get_static_data('https://www.meituan.com/meishi/')
df.to_csv('meituan_static.csv', index=False)

问题:此方法仅能获取首屏数据,后续内容需滚动加载。

3. 动态数据采集(Selenium方案)

代码语言:javascript
复制
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 get_dynamic_data(url):
    options = webdriver.ChromeOptions()
    options.add_argument('--headless')  # 无头模式
    driver = webdriver.Chrome(options=options)
    driver.get(url)
    
    # 模拟滚动加载
    for _ in range(5):
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        time.sleep(2)
    
    # 解析动态加载的元素
    shops = []
    items = driver.find_elements(By.CSS_SELECTOR, '.shop-item')
    for item in items:
        name = item.find_element(By.CSS_SELECTOR, 'h3').text
        rating = item.find_element(By.CSS_SELECTOR, '.rating').text
        sales = item.find_element(By.CSS_SELECTOR, '.sales').text.split('月售')[1]
        shops.append({'name': name, 'rating': rating, 'sales': sales})
    
    driver.quit()
    return pd.DataFrame(shops)

# 示例调用
df = get_dynamic_data('https://www.meituan.com/meishi/')
df.to_csv('meituan_dynamic.csv', index=False)

优化点

  • 添加time.sleep()模拟人类操作节奏
  • 使用CSS选择器替代XPath提升解析效率

4. 终极方案:直接调用API接口

通过Chrome开发者工具(F12)的Network面板,捕获商家列表请求:

代码语言:javascript
复制
import requests
import json

def get_api_data(city_id, offset=0):
    url = f"https://meishi.meituan.com/api/v1/poi/list?cityId={city_id}&offset={offset}&limit=20"
    headers = {
        'Referer': 'https://www.meituan.com/meishi/',
        'User-Agent': 'Mozilla/5.0...'
    }
    response = requests.get(url, headers=headers)
    data = json.loads(response.text)
    
    shops = []
    for poi in data.get('data', []):
        shops.append({
            'name': poi['title'],
            'rating': poi['avgScore'],
            'sales': poi['recentSalesNum'],
            'address': poi['address']
        })
    
    return shops

# 示例:获取北京前40家商家数据
all_shops = []
for i in range(2):  # 每页20条,获取2页
    all_shops.extend(get_api_data(city_id=1, offset=i*20))

pd.DataFrame(all_shops).to_csv('meituan_api.csv', index=False)

优势

  • 直接获取结构化JSON数据
  • 无需处理HTML解析
  • 效率比页面渲染高10倍以上

四、反爬策略与应对方案

1. 常见反爬机制

  • IP限制:单IP请求频率过高触发封禁
  • User-Agent检测:识别非浏览器请求
  • 验证码:图形/滑动验证码拦截
  • 行为分析:检测鼠标轨迹、点击间隔等

2. 应对策略

(1)IP代理池
代码语言:javascript
复制
import random
from fake_useragent import UserAgent

proxies = [
    {'http': 'http://123.123.123.123:8080'},
    {'http': 'http://124.124.124.124:8081'}
]

def get_with_proxy(url):
    proxy = random.choice(proxies)
    headers = {'User-Agent': UserAgent().random}
    try:
        return requests.get(url, headers=headers, proxies=proxy, timeout=5)
    except:
        return get_with_proxy(url)  # 失败自动重试
(2)请求头伪装
代码语言:javascript
复制
headers = {
    'Accept': 'application/json',
    'Referer': 'https://www.meituan.com/',
    'X-Requested-With': 'XMLHttpRequest',
    'Cookie': 'your_cookie_here'  # 必要时携带合法Cookie
}
(3)请求频率控制
代码语言:javascript
复制
import time
import random

def request_with_delay(url):
    delay = random.uniform(1, 3)  # 1-3秒随机延迟
    time.sleep(delay)
    return get_with_proxy(url)

五、数据存储与可视化

1. 存储方案

代码语言:javascript
复制
# 存储为CSV
df.to_csv('meituan_data.csv', index=False, encoding='utf_8_sig')

# 存储到MySQL
import pymysql
from sqlalchemy import create_engine

engine = create_engine('mysql+pymysql://user:password@localhost/meituan')
df.to_sql('shops', engine, if_exists='replace', index=False)

2. 数据可视化

代码语言:javascript
复制
import matplotlib.pyplot as plt

# 评分分布饼图
ratings = df['rating'].value_counts()
plt.pie(ratings, labels=ratings.index, autopct='%1.1f%%')
plt.title('商家评分分布')
plt.show()

# 销量TOP10柱状图
top10 = df.nlargest(10, 'sales')
plt.barh(top10['name'], top10['sales'])
plt.xlabel('月销量')
plt.title('销量TOP10商家')
plt.show()

六、常见问题Q&A

Q1:被网站封IP怎么办? A:立即启用备用代理池,建议使用住宅代理(如站大爷IP代理),配合每请求更换IP策略。若使用Selenium,可结合selenium-wire库自动轮换代理。

Q2:如何获取特定区域的商家数据? A:通过API接口的cityId参数指定城市,或解析页面URL中的区域标识(如/meishi/bj/代表北京)。

Q3:数据缺失或格式错误如何处理? A:在解析阶段添加异常处理:

代码语言:javascript
复制
try:
    rating = float(item['avgScore'])
except (KeyError, ValueError):
    rating = 0.0

Q4:如何避免被法律风险? A:严格遵守《网络安全法》,仅爬取公开数据,避免高频请求(建议延迟≥3秒),不存储敏感信息。商业用途前建议咨询法律顾问。

Q5:Selenium爬取时出现元素未加载怎么办? A:使用显式等待替代固定延迟:

代码语言:javascript
复制
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

element = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.CSS_SELECTOR, '.shop-item'))
)

七、总结与延伸

本文通过三种技术方案(静态解析、Selenium模拟、API直连)实现了美团外卖数据采集,核心要点包括:

  1. 优先尝试API接口获取结构化数据
  2. 动态页面需结合代理池与请求延迟
  3. 数据存储建议采用CSV+MySQL双方案
  4. 可视化阶段重点关注评分分布与销量排名

进阶方向:

  • 使用Scrapy框架构建分布式爬虫
  • 结合NLP分析用户评论情感倾向
  • 搭建实时数据监控看板(如Grafana)

数据采集的本质是信息获取效率的竞赛,但始终需牢记:技术应服务于正当需求,合规性比技术实现更重要。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、为什么需要爬取美团外卖数据?
  • 二、技术选型:工具与原理
    • 1. 核心工具包
    • 2. 美团外卖数据特点
  • 三、实战步骤:从环境搭建到数据落地
    • 1. 环境准备
    • 2. 基础爬虫实现(静态页面解析)
    • 3. 动态数据采集(Selenium方案)
    • 4. 终极方案:直接调用API接口
  • 四、反爬策略与应对方案
    • 1. 常见反爬机制
    • 2. 应对策略
      • (1)IP代理池
      • (2)请求头伪装
      • (3)请求频率控制
  • 五、数据存储与可视化
    • 1. 存储方案
    • 2. 数据可视化
  • 六、常见问题Q&A
  • 七、总结与延伸
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档