基于 Selenium 的美团外卖动态数据爬虫实现方案

简介: 基于 Selenium 的美团外卖动态数据爬虫实现方案

美团外卖平台的商家列表、菜品详情、订单数据等核心内容均采用 JavaScript 动态渲染加载,传统 requests 库仅能获取未渲染的空壳 HTML 文档,无法直接提取有效数据。针对该类动态页面,主流解决方案分为AJAX 接口逆向与浏览器模拟渲染两类:接口逆向开发成本高、易受平台接口更新影响导致失效,因此本文采用 Selenium 自动化测试框架,通过模拟真实浏览器执行环境,等待 JavaScript 渲染完成后精准提取目标数据。
核心技术难点与应对策略
美团外卖平台具备完善的反爬机制,核心限制包括地理位置校验、人机验证拦截、登录态强制校验。针对性解决策略:

  1. 精准配置地理位置信息,匹配平台商家推荐规则;
  2. 接入代理 IP 池分散请求流量,规避单 IP 限流封禁;
  3. 模拟人类用户操作行为(页面滚动、随机请求延迟),降低反爬识别风险。
    一、开发环境配置
    通过 pip 安装项目核心依赖库,实现浏览器自动化、驱动管理与数据持久化:
    ● selenium:主流浏览器自动化操作框架,支持模拟用户交互与页面渲染;
    ● webdriver-manager:自动适配 Chrome 浏览器版本,管理 ChromeDriver 驱动,无需手动配置;
    ● pymysql:Python 连接 MySQL 数据库的驱动库,实现爬取数据的结构化存储。
    二、Selenium WebDriver 初始化
    配置 Chrome 浏览器启动参数,构建稳定的自动化运行环境,核心采用显式等待保证页面元素加载完成:
    python
    运行
    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
    from webdriver_manager.chrome import ChromeDriverManager
    import time
    import random

配置Chrome启动选项

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless') # 无头模式,生产环境推荐启用
chrome_options.add_argument('--disable-gpu') # 禁用GPU加速,适配服务器环境
chrome_options.add_argument('--no-sandbox') # 关闭沙盒模式,Linux环境必备
chrome_options.add_argument('--disable-dev-shm-usage') # 解决共享内存不足问题

配置真实User-Agent,伪装浏览器请求

chrome_options.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36')

初始化WebDriver,自动安装匹配的ChromeDriver

driver = webdriver.Chrome(ChromeDriverManager().install(), options=chrome_options)

显式等待:最长等待10秒,等待元素加载完成后执行操作

wait = WebDriverWait(driver, 10)
关键配置说明

  1. 无头模式:无界面运行浏览器,降低资源消耗,适合服务器部署;
  2. User-Agent 伪装:模拟真实浏览器请求头,减少被反爬识别的概率;
  3. 显式等待:替代固定休眠,高效等待页面元素加载,提升爬虫稳定性与效率。
    三、地理位置限制解决方案
    美团外卖基于用户地理位置实现商家精准推荐,未配置合法位置将无法获取有效数据,提供两种标准化实现方案:
    方案一:Cookie 持久化复用(推荐生产环境使用)
    首次手动登录美团外卖并设置位置,保存 Cookie 至本地文件,后续直接复用登录态与位置信息:
    python
    运行
    import json

1. 首次手动登录后,获取并保存Cookie到本地文件

cookies = driver.get_cookies()
with open('meituan_cookies.json', 'w', encoding='utf-8') as f:
json.dump(cookies, f, ensure_ascii=False)

2. 后续爬虫启动时,加载本地Cookie恢复登录状态与位置信息

driver.get('https://www.meituan.com/')
with open('meituan_cookies.json', 'r', encoding='utf-8') as f:
cookies = json.load(f)
for cookie in cookies:
driver.add_cookie(cookie)
方案二:前端 JS 注入经纬度信息
通过执行 JavaScript 代码,直接修改浏览器本地存储,强制设置目标地理位置:
python
运行

访问美团外卖首页

driver.get('https://www.meituan.com/')

注入经纬度与位置信息(以北京市朝阳区为例)

driver.execute_script('''
localStorage.setItem('geohash', 'wx4g0e0e0');
localStorage.setItem('location', '{"latitude":39.9042,"longitude":116.4074,"address":"北京市朝阳区"}');
''')

刷新页面生效配置

driver.refresh()
四、商家列表数据爬取
针对美团外卖无限滚动加载的商家列表,模拟用户滚动行为加载全量数据,结合随机延迟规避反爬:
python
运行
def scrape_merchants(keyword: str = '美食', limit: int = 20) -> list:
"""
爬取美团外卖商家列表
:param keyword: 搜索关键词
:param limit: 最大爬取商家数量
:return: 商家信息列表
"""

# 构造搜索URL
search_url = f'https://www.meituan.com/s/{keyword}/'
driver.get(search_url)
time.sleep(3)  # 基础页面加载延迟

merchant_list = []
last_page_height = driver.execute_script('return document.body.scrollHeight')

while len(merchant_list) < limit:
    # 模拟滚动至页面底部,加载更多商家数据
    driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')
    # 随机延迟1.5-3秒,模拟真实用户操作
    time.sleep(random.uniform(1.5, 3.0))

    # 定位商家元素节点
    merchant_elements = driver.find_elements(By.CSS_SELECTOR, '.poi-item')

    # 增量提取新增商家数据
    for elem in merchant_elements[len(merchant_list):]:
        try:
            merchant_info = {
                'name': elem.find_element(By.CSS_SELECTOR, '.poi-name').text,
                'rating': elem.find_element(By.CSS_SELECTOR, '.star-rating').get_attribute('title'),
                'address': elem.find_element(By.CSS_SELECTOR, '.address').text,
                'link': elem.find_element(By.CSS_SELECTOR, 'a').get_attribute('href')
            }
            merchant_list.append(merchant_info)
            print(f"成功爬取商家:{merchant_info['name']} | 评分:{merchant_info['rating']}")
        except Exception as e:
            print(f"商家信息提取异常:{str(e)}")
            continue

    # 判断是否到达页面底部,无新数据则终止循环
    new_page_height = driver.execute_script('return document.body.scrollHeight')
    if new_page_height == last_page_height:
        print('已滚动至页面底部,无更多商家数据')
        break
    last_page_height = new_page_height

return merchant_list[:limit]

核心实现要点

  1. 无限滚动处理:通过 JS 获取页面高度,循环滚动加载动态数据;
  2. 增量提取:仅处理新增渲染的商家元素,避免重复爬取;
  3. 异常捕获:单个商家提取异常不中断整体爬虫流程,提升鲁棒性。
    五、商家详情与菜品数据爬取
    进入商家详情页,加载全量菜品信息,提取商家基础信息与菜品数据:
    python
    运行
    def scrape_merchant_detail(merchant_url: str) -> dict | None:
    """
    爬取商家详情及菜品列表
    :param merchant_url: 商家详情页链接
    :return: 商家详情+菜品列表字典,提取失败返回None
    """
    driver.get(merchant_url)
    time.sleep(2)

    提取商家核心基础信息

    try:

     shop_name = driver.find_element(By.CSS_SELECTOR, '.shop-name').text
     business_hours = driver.find_element(By.CSS_SELECTOR, '.business-hours').text
     shop_phone = driver.find_element(By.CSS_SELECTOR, '.phone').text
    

    except Exception:

     print('商家基础信息提取失败')
     return None
    

    滚动加载全部菜品数据

    last_height = driver.execute_script('return document.body.scrollHeight')
    while True:

     driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')
     time.sleep(1)
     new_height = driver.execute_script('return document.body.scrollHeight')
     if new_height == last_height:
         break
     last_height = new_height
    

    提取菜品列表信息

    dish_list = []
    dish_elements = driver.find_elements(By.CSS_SELECTOR, '.dish-item')
    for elem in dish_elements:

     try:
         dish_info = {
             'name': elem.find_element(By.CSS_SELECTOR, '.dish-name').text,
             'price': elem.find_element(By.CSS_SELECTOR, '.dish-price').text,
             'sales': elem.find_element(By.CSS_SELECTOR, '.dish-sales').text
         }
         dish_list.append(dish_info)
     except Exception:
         continue
    

    return {

     'name': shop_name,
     'hours': business_hours,
     'phone': shop_phone,
     'dishes': dish_list
    

    }
    六、代理 IP 配置(反封禁核心)
    美团外卖对单 IP 请求频率严格限制,高频爬取会触发验证码或 IP 封禁,亿牛云爬虫代理接入方案如下:
    标准代理配置(Selenium 原生)
    python
    运行
    from selenium.webdriver.common.proxy import Proxy, ProxyType

亿牛云代理基础配置

PROXY_HOST = "t.16yun.cn"
PROXY_PORT = "31111"
PROXY_USER = "your_username"
PROXY_PASS = "your_password"

初始化代理对象

proxy = Proxy({
'proxyType': ProxyType.MANUAL,
'httpProxy': f'{PROXY_HOST}:{PROXY_PORT}',
'sslProxy': f'{PROXY_HOST}:{PROXY_PORT}',
'noProxy': 'localhost,127.0.0.1'
})

启动带代理的浏览器

driver = webdriver.Chrome(ChromeDriverManager().install(), options=chrome_options, proxy=proxy)
七、MySQL 数据持久化
将爬取的结构化数据存储至 MySQL 数据库,实现数据永久保存与后续分析:
python
运行
import pymysql
from pymysql.err import OperationalError

def save_to_mysql(merchant_data: list):
"""
将商家数据存储至MySQL数据库
:param merchant_data: 商家详情数据列表
"""
try:

    # 建立数据库连接
    conn = pymysql.connect(
        host='localhost',
        user='root',
        password='your_password',
        database='meituan_data',
        charset='utf8mb4'
    )
    cursor = conn.cursor()

    # 创建商家信息表(不存在则创建)
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS merchants (
            id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
            name VARCHAR(255) NOT NULL COMMENT '商家名称',
            rating VARCHAR(50) COMMENT '商家评分',
            address TEXT COMMENT '商家地址',
            link TEXT COMMENT '商家链接',
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '爬取时间'
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '美团外卖商家信息表';
    ''')

    # 批量插入数据
    for merchant in merchant_data:
        cursor.execute('''
            INSERT INTO merchants (name, rating, address, link)
            VALUES (%s, %s, %s, %s)
        ''', (merchant['name'], merchant['rating'], merchant['address'], merchant['link']))

    conn.commit()
    print(f"成功存储 {len(merchant_data)} 条商家数据至MySQL")
except OperationalError as e:
    print(f"数据库连接/操作失败:{str(e)}")
finally:
    # 确保资源释放
    if 'conn' in locals() and conn.open:
        cursor.close()
        conn.close()

八、爬虫完整执行流程
整合所有模块,实现初始化→登录态恢复→数据爬取→数据存储的全流程自动化:
python
运行
def main():

# 1. 初始化WebDriver
driver = webdriver.Chrome(ChromeDriverManager().install(), options=chrome_options)
wait = WebDriverWait(driver, 10)

# 2. 恢复登录Cookie
driver.get('https://www.meituan.com/')
try:
    with open('meituan_cookies.json', 'r', encoding='utf-8') as f:
        cookies = json.load(f)
        for cookie in cookies:
            driver.add_cookie(cookie)
    print("Cookie加载成功,登录态已恢复")
except FileNotFoundError:
    print("Cookie文件不存在,请首次手动登录获取")

# 3. 爬取商家列表
merchants = scrape_merchants(keyword='美食', limit=10)

# 4. 爬取商家详情数据
detailed_merchant_data = []
for merchant in merchants:
    detail = scrape_merchant_detail(merchant['link'])
    if detail:
        detailed_merchant_data.append(detail)
    # 商家间随机延迟,降低请求频率
    time.sleep(random.uniform(2, 5))

# 5. 数据存储至MySQL
save_to_mysql(detailed_merchant_data)

# 6. 关闭浏览器,释放资源
driver.quit()
print("爬虫任务执行完成,浏览器已关闭")

if name == 'main':
main()
九、常见问题排查与性能优化
表格
异常问题 根本原因 标准化解决方案
触发人机验证码 请求频率过高 / 单 IP 异常访问 接入代理 IP 池,增大随机延迟,优化用户行为模拟
Cookie 登录态失效 平台会话超时 / 异地登录检测 定时刷新 Cookie,新增自动重登录逻辑
页面元素定位失败 前端页面结构更新 实时维护 CSS 选择器 / XPath,兼容页面迭代
长时间运行内存泄漏 WebDriver 未正常释放 / 页面缓存堆积 定时重启浏览器实例,强制启用无头模式
爬取效率过低 重复启动浏览器 / 固定休眠过长 复用 WebDriver 实例,用显式等待替代固定休眠
十、技术方案边界与选型建议
Selenium 方案优缺点
● 优势:可直接获取渲染后的完整页面,调试成本低,无需逆向加密接口,适合短期、小规模爬虫项目;
● 劣势:浏览器资源占用高、爬取速度较慢,不适用超大规模分布式采集场景。
大规模采集替代方案

  1. AJAX 接口逆向:直接调用平台后端 API,爬取效率最高,但需攻克加密参数、签名算法,技术门槛高;
  2. requests + 代理池:轻量高效,仅适用于无强反爬、非动态渲染的简单页面;
  3. seleniumwire + 代理池:平衡开发成本与爬取稳定性,适合中规模数据采集。
相关文章
|
19天前
|
人工智能 数据可视化 安全
王炸组合!阿里云 OpenClaw X 飞书 CLI,开启 Agent 基建狂潮!(附带免费使用6个月服务器)
本文详解如何用阿里云Lighthouse一键部署OpenClaw,结合飞书CLI等工具,让AI真正“动手”——自动群发、生成科研日报、整理知识库。核心理念:未来软件应为AI而生,CLI即AI的“手脚”,实现高效、安全、可控的智能自动化。
34862 48
王炸组合!阿里云 OpenClaw X 飞书 CLI,开启 Agent 基建狂潮!(附带免费使用6个月服务器)
|
13天前
|
人工智能 自然语言处理 安全
Claude Code 全攻略:命令大全 + 实战工作流(建议收藏)
本文介绍了Claude Code终端AI助手的使用指南,主要内容包括:1)常用命令如版本查看、项目启动和更新;2)三种工作模式切换及界面说明;3)核心功能指令速查表,包含初始化、压缩对话、清除历史等操作;4)详细解析了/init、/help、/clear、/compact、/memory等关键命令的使用场景和语法。文章通过丰富的界面截图和场景示例,帮助开发者快速掌握如何通过命令行和交互界面高效使用Claude Code进行项目开发,特别强调了CLAUDE.md文件作为项目知识库的核心作用。
12574 37
Claude Code 全攻略:命令大全 + 实战工作流(建议收藏)
|
8天前
|
人工智能 JavaScript Ubuntu
低成本搭建AIP自动化写作系统:Hermes保姆级使用教程,长文和逐步实操贴图
我带着怀疑的态度,深度使用了几天,聚焦微信公众号AIP自动化写作场景,写出来的几篇文章,几乎没有什么修改,至少合乎我本人的意愿,而且排版风格,也越来越完善,同样是起码过得了我自己这一关。 这个其实OpenClaw早可以实现了,但是目前我觉得最大的区别是,Hermes会自主总结提炼,并更新你的写作技能。 相信就冲这一点,就值得一试。 这篇帖子主要就Hermes部署使用,作一个非常详细的介绍,几乎一步一贴图。 关于Hermes,无论你赞成哪种声音,我希望都是你自己动手行动过,发自内心的选择!
2609 27
|
30天前
|
人工智能 JSON 机器人
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
本文带你零成本玩转OpenClaw:学生认证白嫖6个月阿里云服务器,手把手配置飞书机器人、接入免费/高性价比AI模型(NVIDIA/通义),并打造微信公众号“全自动分身”——实时抓热榜、AI选题拆解、一键发布草稿,5分钟完成热点→文章全流程!
45768 157
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
|
6天前
|
人工智能 弹性计算 安全
Hermes Agent是什么?怎么部署?超详细实操教程
Hermes Agent 是 Nous Research 于2026年2月开源的自进化AI智能体,支持跨会话持久记忆、自动提炼可复用技能、多平台接入与200+模型切换,真正实现“越用越懂你”。MIT协议,部署灵活,隐私可控。
1876 3
|
4天前
|
弹性计算 人工智能 自然语言处理
阿里云Qwen3.6全新开源,三步完成专有版部署!
Qwen3.6是阿里云全新MoE架构大模型系列,稀疏激活显著降低推理成本,兼顾顶尖性能与高性价比;支持多规格、FP8量化、原生Agent及100+语言,开箱即用。
|
1天前
|
缓存 人工智能 自然语言处理
我对比了8个Claude API中转站,踩了不少坑,总结给你
本文是个人开发者耗时1周实测的8大Claude中转平台横向评测,聚焦Claude Code真实体验:以加权均价(¥/M token)、内部汇率、缓存支持、模型真实性及稳定性为核心指标。