- 引言
12306作为中国铁路官方售票平台,不仅提供火车票预订服务,还涵盖了丰富的旅游产品,如跟团游、自由行、酒店套餐等。这些数据对旅游行业分析、价格监控、竞品研究等具有重要价值。然而,12306的数据接口通常有严格的访问限制和反爬机制,直接爬取网页可能效率低下且容易被封禁。
本文将通过API逆向分析的方式,使用Python模拟合法请求,高效抓取12306旅游产品数据,并提供完整的代码实现。 - 技术选型
2.1 Python爬虫工具
● Requests:发送HTTP请求,获取API数据。
● Selenium(可选):用于动态渲染页面的情况。
● BeautifulSoup / PyQuery:解析HTML(如果涉及网页抓取)。
● JSON / Pandas:处理和存储数据。
2.2 反爬应对策略
● User-Agent轮换:模拟浏览器访问。
● IP代理池:防止IP被封。
● 请求频率控制:避免触发反爬机制。
● Cookie/Session管理:维持登录状态(如需要)。 - 12306旅游产品API逆向分析
3.1 分析目标
我们需要获取12306旅游产品数据,包括:
● 旅游线路名称
● 出发地/目的地
● 价格
● 行程天数
● 产品详情页URL
3.2 寻找API接口 - 浏览器开发者工具(F12):
○ 打开12306旅游频道(如:https://kyfw.12306.cn/otn/)。
○ 进入Network(网络)选项卡,筛选XHR或Fetch请求。
○ 搜索关键词product、travel、list等,找到返回JSON数据的API。 - 示例API(需动态分析):
○ 假设找到一个类似https://kyfw.12306.cn/otn/travel/product/list?page=1的接口。
○ 观察请求头(Headers),特别是User-Agent、Referer、Cookie等。
3.3 模拟合法请求
12306的API通常需要:
● Referer(来源页面)
● Cookie(可能涉及登录态)
● 加密参数(如_json_att,需动态获取)
我们可以用Python的requests库构造合法请求:
```import requests
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"Referer": "https://kyfw.12306.cn/otn/leftTicket/init",
"Cookie": "JSESSIONID=...; RAIL_EXPIRATION=...; RAIL_DEVICEID=...", # 需替换为有效Cookie
}
url = "https://kyfw.12306.cn/otn/travel/product/list?page=1"
response = requests.get(url, headers=headers)
if response.status_code == 200:
data = response.json()
print(data)
else:
print("请求失败:", response.status_code)
4. 完整爬取流程与代码实现
4.1 获取Cookie(模拟登录)
12306可能需要登录才能访问API,我们可以用Selenium模拟登录并提取Cookie:
```from selenium import webdriver
import time
def get_12306_cookie():
driver = webdriver.Chrome()
driver.get("https://kyfw.12306.cn/otn/resources/login.html")
# 手动扫码登录(或自动填充账号密码)
time.sleep(20) # 留时间扫码
# 获取Cookie
cookies = driver.get_cookies()
cookie_str = "; ".join([f"{c['name']}={c['value']}" for c in cookies])
driver.quit()
return cookie_str
cookie = get_12306_cookie()
print("获取的Cookie:", cookie)
4.2 爬取旅游产品数据
结合API分析和Cookie管理,完整爬取代码:
```import requests
import pandas as pd
from fake_useragent import UserAgent
import time
import random
代理配置
proxyHost = "www.16yun.cn"
proxyPort = "5445"
proxyUser = "16QMSOML"
proxyPass = "280651"
构造代理字典
proxies = {
"http": f"http://{proxyUser}:{proxyPass}@{proxyHost}:{proxyPort}",
"https": f"http://{proxyUser}:{proxyPass}@{proxyHost}:{proxyPort}",
}
def get_random_headers():
"""生成随机请求头"""
ua = UserAgent()
return {
"User-Agent": ua.random,
"Referer": "https://kyfw.12306.cn/otn/leftTicket/init",
"Accept": "application/json, text/javascript, /; q=0.01",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "keep-alive",
"X-Requested-With": "XMLHttpRequest",
}
def fetch_12306_travel_products(page=1, max_pages=5):
"""爬取12306旅游产品数据(带代理IP)"""
all_products = []
base_url = "https://kyfw.12306.cn/otn/travel/product/list"
for page in range(1, max_pages + 1):
try:
# 每次请求使用随机请求头
headers = get_random_headers()
headers["Cookie"] = get_12306_cookie() # 替换为你的Cookie
params = {"page": page}
# 添加随机延迟(1-3秒)
time.sleep(random.uniform(1, 3))
# 发送带代理的请求
response = requests.get(
base_url,
headers=headers,
params=params,
proxies=proxies,
timeout=10
)
if response.status_code == 200:
data = response.json()
products = data.get("data", {}).get("list", [])
all_products.extend(products)
print(f"✅ 成功爬取第 {page} 页,共 {len(products)} 条数据")
else:
print(f"❌ 第 {page} 页请求失败,状态码: {response.status_code}")
except Exception as e:
print(f"⚠️ 第 {page} 页请求异常: {str(e)}")
continue
return all_products
示例:获取Cookie(需替换为实际实现)
def get_12306_cookie():
"""获取12306登录Cookie(示例函数,需替换为实际实现)"""
return "JSESSIONID=...; RAIL_EXPIRATION=...; RAIL_DEVICEID=..."
主程序
if name == "main":
print("🚀 开始爬取12306旅游产品数据...")
# 爬取数据(3页示例)
travel_data = fetch_12306_travel_products(max_pages=3)
# 数据处理
if travel_data:
df = pd.DataFrame(travel_data)
# 提取关键字段
df = df[[
"productName", # 产品名称
"fromStation", # 出发地
"toStation", # 目的地
"price", # 价格
"days", # 行程天数
"productUrl" # 详情链接
]]
# 保存数据
df.to_csv("12306_travel_products.csv", index=False, encoding='utf_8_sig')
print(f"🎉 数据已保存至 12306_travel_products.csv,共 {len(df)} 条记录")
else:
print("❌ 未获取到有效数据")
4.3 数据解析与存储
爬取的数据通常是JSON格式,可以用pandas整理成结构化数据:
```import pandas as pd
# 示例数据整理
df = pd.DataFrame(travel_data)
df = df[[
"productName", # 产品名称
"fromStation", # 出发地
"toStation", # 目的地
"price", # 价格
"days", # 行程天数
"productUrl" # 详情链接
]]
print(df.head())
- 结论
本文通过API逆向分析,使用Python高效抓取12306旅游产品数据,并提供了完整的代码实现。关键点包括:
API分析:通过浏览器开发者工具找到数据接口。
模拟请求:构造合法Headers和Cookie。
反爬策略:使用代理IP、随机UA、请求延迟等。
数据存储:用pandas整理并导出CSV。