You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何利用网页日期筛选器爬取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-AgentReferer来模拟正常浏览器访问,不然很容易被反爬拦截。

第二步:编写批量爬取代码

基于你现有的代码,我们可以修改为循环遍历目标年份,逐个请求对应时段的数据,最后合并所有结果。这里是完整的可运行代码:

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

火山引擎 最新活动