大麦网是国内领先的演出票务平台,涵盖演唱会、话剧、体育赛事等票务服务。由于大麦网未正式开放公共 API,以下分析基于其移动端 / 网页端的非官方接口(通过抓包分析),并提供 Python 调用方案。需注意:非官方 API 可能存在稳定性问题,且使用需遵守平台规则。
### 一、大麦网接口核心特性分析
#### 1. 接口体系与功能域
通过抓包分析,大麦网核心接口可分为以下几类:
- **首页推荐**:获取热门演出、分类推荐;
- **演出列表**:按城市、品类、时间筛选演出;
- **演出详情**:获取演出时间、场馆、票价、座位图;
- **购票相关**:库存查询、下单、支付;
- **用户中心**:订单查询、收货地址。
#### 2. 认证与请求规范
- **匿名接口**:首页推荐、演出列表等公开信息接口无需登录,仅需标准请求头;
- **登录态接口**:购票、订单查询等需携带登录 Cookie(关键 Cookie 为`damai.cn`的`SESSION`和`userId`);
- **请求头**:必需`User-Agent`(模拟移动端 / PC 端)、`Referer`(防盗链);
- **参数加密**:部分接口参数经过简单加密(如时间戳 + 固定密钥 MD5),但公开信息接口参数多为明文。
#### 3. 典型接口参数与响应
以**演出列表接口**为例:
- **请求 URL**:
- **方法**:GET
- **核心参数**:
- `city`:城市 ID(如北京`101010100`);
- `ctl`:品类(演唱会`1`、话剧`2`、体育`5`等);
- `page`:页码;
- `ts`:时间戳(毫秒级)。
- **响应格式**:JSON,包含`totalCount`(总数)、`pageData`(演出列表,含 ID、名称、价格等)。
### 二、Python 脚本实现:大麦网接口调用框架
以下实现大麦网公开接口的调用,包括演出列表查询、演出详情获取,并处理基本的请求头和参数构造。
import requests
import json
import time
import logging
from typing import Dict, List, Optional
from requests.exceptions import RequestException
# 配置日志
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)
class DamaiAPI:
def __init__(self, city_id: str = "101010100"):
"""
初始化大麦网API客户端
:param city_id: 城市ID(默认北京:101010100,其他城市需查询对应ID)
"""
self.city_id = city_id
self.headers = {
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Damai/7.2.0",
"Referer": "https://m.damai.cn/",
"Origin": "https://m.damai.cn",
"Accept": "application/json, text/plain, */*"
}
# 会话保持(处理Cookie)
self.session = requests.Session()
self.session.headers.update(self.headers)
def _get_timestamp(self) -> int:
"""生成毫秒级时间戳"""
return int(time.time() * 1000)
def search_performances(self, keyword: str = "", category: int = 0, page: int = 1) -> Optional[List[Dict]]:
"""
搜索演出列表
:param keyword: 搜索关键词(如"周杰伦")
:param category: 品类(1:演唱会,2:话剧,5:体育,0:全部)
:param page: 页码
:return: 演出列表(含ID、名称、价格等)
"""
url = "https://search.damai.cn/searchajax.html"
params = {
"city": self.city_id,
"keyword": keyword,
"ctl": category,
"page": page,
"ts": self._get_timestamp(),
"stype": 0,
"order": 1 # 1:热门排序,2:时间排序
}
try:
response = self.session.get(url, params=params, timeout=10)
response.raise_for_status()
result = response.json()
# 解析演出列表
if result.get("status") == 1:
performances = result.get("pageData", {}).get("resultData", [])
logging.info(f"搜索到{len(performances)}个演出,关键词:{keyword},页码:{page}")
return [
{
"id": item.get("id"),
"name": item.get("name"),
"category": item.get("categoryName"),
"time": item.get("showTime"),
"venue": item.get("venueName"),
"price": item.get("priceStr"),
"status": item.get("statusName") # 售票状态:预售/在售/售罄
} for item in performances
]
else:
logging.error(f"搜索失败:{result.get('msg')}")
return None
except RequestException as e:
logging.error(f"搜索请求异常:{str(e)}")
return None
def get_performance_detail(self, performance_id: str) -> Optional[Dict]:
"""
获取演出详情(时间、场馆、票价等)
:param performance_id: 演出ID(从搜索接口获取)
:return: 演出详情字典
"""
url = f"https://detail.damai.cn/item.htm?id={performance_id}"
# 详情页接口实际通过HTML渲染,需解析页面中的JSON数据
try:
response = self.session.get(url, timeout=10)
response.raise_for_status()
html = response.text
# 提取页面中的JSON数据(大麦网详情页数据嵌在window.__INITIAL_STATE__中)
start = html.find("window.__INITIAL_STATE__ = ") + len("window.__INITIAL_STATE__ = ")
end = html.find(";</script>", start)
if start == -1 or end == -1:
logging.error("无法提取演出详情数据")
return None
detail_json = json.loads(html[start:end])
item_info = detail_json.get("itemDetail", {}).get("item", {})
sku_list = detail_json.get("skuList", {}).get("skuList", []) # 票价信息
# 解析核心信息
return {
"id": performance_id,
"name": item_info.get("name"),
"poster": item_info.get("verticalPic"), # 海报图
"time": item_info.get("showTime"),
"venue": item_info.get("venueName"),
"address": item_info.get("venueAddress"),
"price_list": [
{
"price": sku.get("price"),
"desc": sku.get("skuName"), # 票价描述(如"内场VIP")
"stock": sku.get("stockStatusName") # 库存状态
} for sku in sku_list
],
"description": item_info.get("detailDesc") # 演出简介
}
except RequestException as e:
logging.error(f"详情请求异常:{str(e)}")
return None
except json.JSONDecodeError:
logging.error("解析演出详情JSON失败")
return None
def get_city_list(self) -> Optional[List[Dict]]:
"""获取大麦网支持的城市列表(含城市ID)"""
url = "https://city.damai.cn/js/cityjson.js"
try:
response = self.session.get(url, timeout=10)
response.raise_for_status()
# 解析城市数据(格式为var cityList = {...};)
start = response.text.find("=") + 1
end = response.text.rfind(";")
city_data = json.loads(response.text[start:end])
# 提取城市ID和名称
return [
{"id": city.get("id"), "name": city.get("name")}
for city in city_data.get("cityList", [])
]
except Exception as e:
logging.error(f"获取城市列表失败:{str(e)}")
return None
# 示例调用
if __name__ == "__main__":
# 初始化客户端(默认北京,可通过get_city_list()获取其他城市ID)
damai = DamaiAPI(city_id="101010100") # 北京
# 1. 搜索演出(示例:搜索"演唱会")
performances = damai.search_performances(keyword="演唱会", category=1, page=1)
if performances:
print("演出列表:")
for perf in performances[:3]: # 打印前3个
print(f"[{perf['id']}] {perf['name']} | {perf['time']} | {perf['venue']} | {perf['price']} | {perf['status']}")
# 2. 获取演出详情(使用搜索结果中的第一个演出ID)
if performances:
first_perf_id = performances[0]["id"]
detail = damai.get_performance_detail(first_perf_id)
if detail:
print(f"\n演出详情:{detail['name']}")
print(f"时间:{detail['time']}")
print(f"场馆:{detail['venue']}({detail['address']})")
print("票价信息:")
for price in detail["price_list"]:
print(f"- {price['desc']}:{price['price']}元({price['stock']})")
三、关键技术点解析
#### 1. 接口特点与反爬应对
- **动态参数**:部分接口需携带时间戳(`ts`),需实时生成;
- **HTML 内嵌数据**:演出详情数据嵌在页面的`window.__INITIAL_STATE__`中,需从 HTML 中提取 JSON;
- **请求头模拟**:需设置真实的`User-Agent`(推荐移动端 UA)和`Referer`,否则可能返回 403;
- **IP 限制**:频繁请求可能触发 IP 封禁,建议添加随机间隔(如`time.sleep(1-3秒)`)。
#### 2. 登录态处理(可选)
如需调用购票、订单等需登录的接口,需:
1. 手动登录大麦网,从浏览器 Cookie 中提取`SESSION`和`userId`;
1. 将 Cookie 添加到会话中:
```
self.session.cookies.set("SESSION", "your_session_value")
self.session.cookies.set("userId", "your_user_id")
```
1. 注意 Cookie 有效期(通常为 24 小时),需定期更新。
#### 3. 城市 ID 映射
大麦网城市 ID 为固定编码(如北京`101010100`、上海`101020100`),可通过`get_city_list()`方法获取完整列表,或手动查询对应城市 ID。
### 四、风险与注意事项
1. **合规性**:非官方 API 可能违反大麦网用户协议,用于商业用途需谨慎;
1. **稳定性**:接口地址、参数或响应格式可能随时变更,需定期维护;
1. **反爬限制**:高频请求可能导致 IP 封禁,建议控制频率并使用代理池;
1. **法律风险**:未经授权的大规模爬取可能涉及法律责任,建议仅用于个人学习。
通过上述框架,可实现大麦网公开演出信息的查询,适用于个人兴趣的演出监控、信息聚合等场景。实际使用中需根据接口变化及时调整参数和解析逻辑。