您好,登录后才能下订单哦!
# Python如何爬取美团美食数据
## 一、爬取美团数据的背景与挑战
美团作为中国领先的生活服务电子商务平台,积累了海量的餐饮商户数据,包括店铺评分、用户评价、人均消费等关键信息。这些数据对于市场分析、竞品调研和商业决策具有重要价值。然而,美团数据的爬取面临三大技术难点:
1. **反爬机制严格**:美团采用动态渲染、请求加密、IP限制等多重防护
2. **数据结构复杂**:页面元素嵌套层级深,数据分散在多个异步接口中
3. **动态参数生成**:关键请求需要携带随时间变化的token和签名
## 二、技术方案设计
### 2.1 整体架构
```mermaid
graph TD
A[启动爬虫] --> B[模拟登录/获取Cookies]
B --> C[构造请求参数]
C --> D[发送HTTP请求]
D --> E{响应成功?}
E -->|是| F[解析数据]
E -->|否| G[异常处理]
F --> H[数据存储]
G --> C
组件类型 | 推荐方案 | 替代方案 |
---|---|---|
请求库 | requests + selenium | aiohttp |
解析库 | BeautifulSoup + parsel | pyquery |
动态渲染 | Playwright | Puppeteer |
代理服务 | 芝麻代理/快代理 | 自建IP池 |
数据存储 | MongoDB | MySQL/CSV |
# 安装依赖库
pip install requests playwright beautifulsoup4 pymongo
# 初始化Playwright
playwright install
接口逆向工程:
poi
、shop
等关键词的接口
https://www.meituan.com/meishi/api/poi/getPoiList?cityId=1&page=1
参数加密分析:
_genToken()
:function _genToken() {
return Math.random().toString(36).substr(2) +
Date.now().toString(36);
}
import requests
from bs4 import BeautifulSoup
from urllib.parse import urlencode
import time
import hashlib
class MeituanSpider:
def __init__(self):
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...',
'Referer': 'https://www.meituan.com/meishi/'
}
self.proxy = {'http': 'http://127.0.0.1:1080'}
def get_city_id(self, city_name):
"""获取城市ID映射"""
city_map = {
'北京': 1,
'上海': 2,
# 其他城市映射...
}
return city_map.get(city_name, 0)
def generate_signature(self, params):
"""生成接口签名"""
secret = 'd1d1b1c1a1a1b1c1' # 需动态获取
param_str = '&'.join([f'{k}={v}' for k,v in sorted(params.items())])
return hashlib.md5((param_str + secret).encode()).hexdigest()
def parse_poi_list(self, html):
"""解析店铺列表数据"""
soup = BeautifulSoup(html, 'lxml')
shops = []
for item in soup.select('.poi-list li'):
shop = {
'name': item.select_one('.title').text.strip(),
'score': float(item.select_one('.score').text),
'reviews': int(item.select_one('.review').text[:-3]),
'address': item.select_one('.address').text.strip()
}
shops.append(shop)
return shops
def crawl(self, city, max_page=10):
city_id = self.get_city_id(city)
result = []
for page in range(1, max_page+1):
params = {
'cityId': city_id,
'page': page,
'timestamp': int(time.time()*1000)
}
params['sign'] = self.generate_signature(params)
try:
url = f"https://www.meituan.com/meishi/api/poi/getPoiList?{urlencode(params)}"
resp = requests.get(url, headers=self.headers, proxies=self.proxy)
data = resp.json()
if data['code'] == 200:
result.extend(self.parse_poi_list(data['html']))
else:
print(f"第{page}页抓取失败: {data['msg']}")
time.sleep(1.5) # 遵守爬虫礼仪
except Exception as e:
print(f"请求异常: {str(e)}")
continue
return result
# 使用示例
if __name__ == '__main__':
spider = MeituanSpider()
data = spider.crawl('北京', max_page=5)
print(f"共获取{len(data)}条店铺数据")
def check_proxy(proxy):
try:
resp = requests.get('http://httpbin.org/ip',
proxies={'http': proxy},
timeout=5)
return resp.status_code == 200
except:
return False
headers = {
'Accept-Language': 'zh-CN,zh;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'Sec-Fetch-Dest': 'document',
'Upgrade-Insecure-Requests': '1'
}
cookies = {
'_lxsdk_cuid': '17a...',
'ci': '1',
# 其他必要cookies
}
from playwright.sync_api import sync_playwright
def browser_crawl(url):
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto(url)
# 模拟人类操作
page.mouse.move(100, 100)
page.wait_for_timeout(500)
html = page.content()
browser.close()
return html
from pymongo import MongoClient
client = MongoClient('mongodb://localhost:27017/')
db = client['meituan']
collection = db['restaurants']
def save_to_mongo(data):
try:
result = collection.insert_many(data)
print(f"插入成功,ID列表: {result.inserted_ids}")
except Exception as e:
print(f"存储失败: {str(e)}")
def remove_duplicates():
pipeline = [
{"$group": {
"_id": "$name",
"dups": {"$push": "$_id"},
"count": {"$sum": 1}
}},
{"$match": {"count": {"$gt": 1}}}
]
for doc in collection.aggregate(pipeline):
del doc['dups'][0]
collection.delete_many({"_id": {"$in": doc['dups']}})
遵守Robots协议:
https://www.meituan.com/robots.txt
控制请求频率:
数据使用限制:
async def async_crawl(url): async with aiohttp.ClientSession() as session: async with session.get(url) as response: return await response.text()
2. **分布式架构**:
- 使用Scrapy-Redis搭建分布式爬虫
- 消息队列采用RabbitMQ/Kafka
3. **断点续爬**:
```python
def save_progress(page):
with open('progress.txt', 'w') as f:
f.write(str(page))
def load_progress():
try:
with open('progress.txt') as f:
return int(f.read())
except:
return 1
本文详细介绍了爬取美团美食数据的技术方案和实现细节。在实际应用中,建议根据具体需求调整爬取策略,并持续关注美团的反爬机制更新。合规、节制的数据采集才能保证项目的可持续发展。
注意:本文示例代码仅供技术学习参考,请勿用于大规模商业爬取。数据抓取行为应当遵守相关法律法规和网站的使用条款。 “`
这篇文章包含了约3500字的内容,采用Markdown格式编写,包含以下关键要素: 1. 技术背景与挑战分析 2. 完整的技术实现方案 3. 代码示例和参数说明 4. 反爬应对策略 5. 数据存储方案 6. 法律合规建议 7. 性能优化方向
可根据实际需要调整代码细节或补充更多城市的数据映射关系。建议在正式使用前进行小规模测试,确保爬虫的稳定性和合规性。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。