如何利用网页日期筛选器爬取FT网站基金全量历史数据(突破30天限制)
解决FT基金历史数据批量爬取(按年份筛选)的问题
我之前也碰到过FT这个限制,确实只能通过筛选器逐年来拉取历史数据。要搞定这个问题,核心是模拟页面上筛选器的请求行为,而不是只爬取初始加载的30天数据。下面是具体的解决方案:
第一步:分析筛选器的请求逻辑
打开浏览器开发者工具(按F12),切换到「Network」标签,然后手动操作页面上的年份筛选器:
- 选一个年份(比如2022),观察浏览器发送的请求
- 你会发现FT会发送一个POST请求到
https://markets.ft.com/data/funds/tearsheet/historical/results,携带的关键参数包括:s:目标基金的代码(比如LU0526609390:EUR)startDate:该年份的第一天(格式YYYY-MM-DD)endDate:该年份的最后一天(格式YYYY-MM-DD)
- 同时,请求头里必须带上
User-Agent和Referer来模拟正常浏览器访问,不然很容易被反爬拦截。
第二步:编写批量爬取代码
基于你现有的代码,我们可以修改为循环遍历目标年份,逐个请求对应时段的数据,最后合并所有结果。这里是完整的可运行代码:
import pandas as pd import requests import datetime from datetime import date import time # 定义要爬取的基金列表 fund_codes = ['LU0526609390:EUR', 'IE00BHBX0Z19:EUR', 'LU1076093779:EUR', 'LU1116896363:EUR'] # 日期格式处理函数(和你原代码保持一致) def format_date(date_str): date_str = date_str.split(',')[-2][1:] + date_str.split(',')[-1] return pd.Series({'Date': date_str}) # 模拟浏览器的请求头,避免被反爬 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', 'Referer': 'https://markets.ft.com/data/funds/tearsheet/historical' } # 存储所有基金的历史数据 all_fund_data = [] # 遍历每个基金 for fund_code in fund_codes: print(f"开始爬取基金 {fund_code} 的数据...") fund_year_data = [] # 定义爬取的年份范围(可根据基金成立时间调整起始年) start_year = 2010 current_year = datetime.datetime.now().year # 逐个年份请求数据 for year in range(start_year, current_year + 1): # 构造当年的起止日期 start_date = date(year, 1, 1).strftime('%Y-%m-%d') end_date = date(year, 12, 31).strftime('%Y-%m-%d') # 构造请求参数 payload = { 's': fund_code, 'startDate': start_date, 'endDate': end_date } try: # 发送POST请求,添加小间隔避免触发反爬 time.sleep(1) response = requests.post( 'https://markets.ft.com/data/funds/tearsheet/historical/results', headers=headers, data=payload ) response.raise_for_status() # 检查请求是否成功 # 解析返回的HTML表格 df_list = pd.read_html(response.content) if df_list: df = df_list[-1] df['Date'] = df['Date'].apply(format_date) df['Fund_Code'] = fund_code # 添加基金标识,方便后续区分 fund_year_data.append(df) print(f"✅ 成功获取 {fund_code} {year} 年的数据") else: print(f"ℹ️ {fund_code} {year} 年无可用数据") except Exception as e: print(f"❌ 爬取 {fund_code} {year} 年数据失败: {str(e)}") continue # 合并当前基金的所有年份数据 if fund_year_data: merged_fund_df = pd.concat(fund_year_data, ignore_index=True) all_fund_data.append(merged_fund_df) # 合并所有基金数据并保存到CSV if all_fund_data: final_df = pd.concat(all_fund_data, ignore_index=True) final_df.to_csv('ft_fund_historical_data.csv', index=False, encoding='utf-8-sig') print("🎉 所有数据已保存到 ft_fund_historical_data.csv") else: print("⚠️ 未获取到任何有效数据")
关键注意事项
- 反爬应对:如果还是被拦截,可以从浏览器复制当前会话的
Cookie添加到请求头里,或者延长请求间隔时间(比如time.sleep(2))。 - 年份范围优化:可以先查一下基金的成立时间,调整
start_year,避免请求不存在的时段浪费资源。 - 数据校验:爬取完成后可以抽查几个年份的数据,确认日期和价格的连续性,避免遗漏。
内容的提问来源于stack exchange,提问作者Tcs106




