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

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

一、为什么需要爬取美团外卖数据?在餐饮外卖行业,商家评分和销量是消费者决策的核心依据。对于商家运营者,分析竞品数据可优化定价策略;对于市场调研者,掌握区域销量分布能洞察消费趋势。美团外卖作为国内最大外卖平台,其数据具有极高的商业价值。但手动收集效率低下,本文将通过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&AQ1:被网站封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.0Q4:如何避免被法律风险?

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直连)实现了美团外卖数据采集,核心要点包括:

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

使用Scrapy框架构建分布式爬虫结合NLP分析用户评论情感倾向搭建实时数据监控看板(如Grafana)数据采集的本质是信息获取效率的竞赛,但始终需牢记:技术应服务于正当需求,合规性比技术实现更重要。

相关推荐

征召模式有段位要求吗
365彩票最新版app下载

征召模式有段位要求吗

📅 07-16 👁️ 1003
Microsoft SQL Server 打开数据库时提示“数据库正在恢复中”,如何处理?
AE剪辑软件:好用还是不好用的探讨
365彩票最新版app下载

AE剪辑软件:好用还是不好用的探讨

📅 11-13 👁️ 5840