第二章:北向资金数据获取——数据源介绍与实战爬取

各位同学,欢迎来到第二章。

上一章我们聊了北向资金为什么值得关注。今天,咱们直接动手——把数据拿到手。

做量化交易,数据就是你的弹药。没有数据,再好的策略也是空中楼阁。我个人习惯先把数据源摸清楚,再决定用什么工具去拿。今天我们就围绕两个主流数据源:东方财富和同花顺,讲讲怎么用Python把它们的数据“请”出来。

2.1 数据源对比:东方财富 vs 同花顺

先说说这两个平台。东方财富和同花顺,是国内散户和机构用得最多的两个金融数据平台。它们各有千秋,我分别讲一下。

对比维度 东方财富(Choice/EastMoney) 同花顺(iFinD)
数据覆盖 沪深港通、个股资金流、板块资金 沪深港通、Level-2、龙虎榜
接口稳定性 较稳定,反爬策略中等 较稳定,反爬策略较强
免费数据量 历史数据较全,实时数据有延迟 历史数据较全,实时数据需付费
Python支持 有非官方API,社区活跃 有非官方API,但文档较少
个人推荐 适合初学者和中小资金 适合进阶用户和机构

我个人更倾向于先用东方财富。为什么?因为它的网页端数据接口相对容易解析,而且社区里有很多现成的轮子可以用。同花顺的数据质量更高,但反爬策略也更严,新手容易碰壁。

小提示: 如果你刚开始学,建议先从东方财富入手。等把爬虫基础打牢了,再挑战同花顺。我当年就是先啃东方财富,后来再看同花顺的接口,感觉轻松不少。

2.2 Python爬虫基础——你只需要这三板斧

说到爬虫,很多同学觉得很难。其实说白了,就是模拟浏览器去访问网页,然后把数据拿回来。你只需要掌握三个库:requestsBeautifulSoupjson

我刚开始写爬虫时,也踩过不少坑。有一次爬东方财富的北向资金数据,怎么都拿不到,后来发现是忘了加请求头。嗯,这里要注意——很多网站会检查你是不是真人访问。

2.2.1 requests库——你的网络手

requests 是Python里最常用的HTTP库。用它发送一个GET请求,就像你打开浏览器输入网址一样简单。

import requests

# 最简单的请求
url = "https://data.eastmoney.com/hsgt/index.html"
response = requests.get(url)

# 看看返回的状态码
print(response.status_code)  # 200表示成功

# 打印网页内容的前500个字符
print(response.text[:500])

你看,就这么几行代码,就能拿到网页的HTML源码。但实际中,我们往往需要加一些参数,比如请求头(Headers),来伪装成浏览器。

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "Referer": "https://data.eastmoney.com/",
}

response = requests.get(url, headers=headers)
避坑指南: 我曾经因为没加Referer头,被东方财富封了IP整整一天。后来才知道,Referer告诉服务器你是从哪个页面跳转过来的,不加这个,服务器会认为你是爬虫。

2.2.2 BeautifulSoup——你的数据筛选器

拿到HTML之后,怎么提取我们需要的数据?用正则表达式?太累了。BeautifulSoup就是专门干这个的。

from bs4 import BeautifulSoup

soup = BeautifulSoup(response.text, 'html.parser')

# 找到所有表格
tables = soup.find_all('table')

# 找到id为"hsgt_table"的表格
target_table = soup.find('table', id='hsgt_table')

# 提取表格中的所有行
rows = target_table.find_all('tr')
for row in rows:
    cells = row.find_all('td')
    for cell in cells:
        print(cell.text.strip())

不过说实话,现在很多网站的数据都是通过JavaScript动态加载的,直接用BeautifulSoup拿不到。这时候就需要另一种方式——直接找API接口。

2.2.3 json库——解析结构化数据

很多金融网站的数据接口返回的是JSON格式。JSON说白了就是Python里的字典和列表的组合,用json库解析非常方便。

import json

# 假设我们拿到了一个JSON字符串
json_str = '{"code": 0, "data": {"total_buy": 100.5, "total_sell": 80.2}}'

# 解析成Python字典
data = json.loads(json_str)

# 提取数据
total_buy = data['data']['total_buy']
total_sell = data['data']['total_sell']
net_buy = total_buy - total_sell

print(f"北向资金净买入:{net_buy} 亿元")

2.3 实战:调用东方财富API获取北向资金数据

好了,理论知识讲完了。咱们直接上实战。我会带你一步步调用东方财富的API,拿到北向资金的实时数据。

你想想看,东方财富的网页上,北向资金数据是怎么显示的?其实它背后有一个隐藏的API接口。我们只需要找到这个接口的URL,然后模拟请求就行了。

2.3.1 找到API接口

打开浏览器,按F12进入开发者工具,切换到Network(网络)选项卡。然后刷新页面,你会看到很多请求。找到名字里带“hsgt”或者“northbound”的那个,点开看看。

我一般会先过滤一下,只保留XHR请求。因为API接口通常都是XHR(XMLHttpRequest)类型的。

# 东方财富北向资金API接口(示例)
api_url = "https://push2.eastmoney.com/api/qt/stock/fflow/daykline/get"

# 参数说明
params = {
    "secid": "1.000001",  # 股票代码,1表示上海,000001是上证指数
    "fields1": "f1,f2,f3,f4,f5,f6",
    "fields2": "f51,f52,f53,f54,f55",
    "klt": "101",  # 日线
    "lmt": "10",   # 最近10个交易日
}

response = requests.get(api_url, params=params, headers=headers)
data = response.json()

2.3.2 解析返回的数据

返回的数据长什么样?我们打印出来看看。

{
    "data": {
        "klines": [
            "2025-01-10,120.5,80.2,40.3",
            "2025-01-09,110.3,75.1,35.2",
            ...
        ]
    }
}

每个字符串里,用逗号分隔了日期、买入额、卖出额、净买入额。我们把它解析成结构化数据。

import pandas as pd

klines = data['data']['klines']
records = []

for line in klines:
    parts = line.split(',')
    record = {
        'date': parts[0],
        'buy': float(parts[1]),
        'sell': float(parts[2]),
        'net': float(parts[3]),
    }
    records.append(record)

df = pd.DataFrame(records)
print(df)
核心要点: 拿到数据后,一定要先检查数据质量。我遇到过好几次,API返回的数据里混入了空值或者异常值。比如某一天的净买入额突然变成几千亿,那明显是数据错误。所以,清洗数据是必不可少的一步。

2.3.3 封装成可复用的函数

写代码不能每次都复制粘贴。我习惯把常用的功能封装成函数,这样以后调用就方便了。

def get_northbound_flow(days=10):
    """
    获取北向资金流向数据
    :param days: 获取最近多少天的数据,默认10天
    :return: DataFrame,包含日期、买入、卖出、净买入
    """
    api_url = "https://push2.eastmoney.com/api/qt/stock/fflow/daykline/get"
    params = {
        "secid": "1.000001",
        "fields1": "f1,f2,f3,f4,f5,f6",
        "fields2": "f51,f52,f53,f54,f55",
        "klt": "101",
        "lmt": str(days),
    }
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        "Referer": "https://data.eastmoney.com/",
    }
    
    response = requests.get(api_url, params=params, headers=headers)
    if response.status_code != 200:
        print(f"请求失败,状态码:{response.status_code}")
        return None
    
    data = response.json()
    if 'data' not in data or 'klines' not in data['data']:
        print("数据格式异常,请检查API接口")
        return None
    
    klines = data['data']['klines']
    records = []
    for line in klines:
        parts = line.split(',')
        if len(parts) < 4:
            continue
        records.append({
            'date': parts[0],
            'buy': float(parts[1]),
            'sell': float(parts[2]),
            'net': float(parts[3]),
        })
    
    df = pd.DataFrame(records)
    df['date'] = pd.to_datetime(df['date'])
    return df

# 调用函数
df = get_northbound_flow(20)
print(df.head())

2.4 本章知识体系总览

为了让你更直观地理解本章的知识结构,我画了一张流程图。你可以看到,从数据源选择,到爬虫基础,再到API实战,是一条完整的链路。

北向资金数据获取知识体系 数据源选择 东方财富(推荐) 同花顺(进阶) Python爬虫三板斧 requests(网络请求) BeautifulSoup(解析HTML) json(解析结构化数据) API接口调用实战 → 获取北向资金数据

2.5 常见问题与避坑指南

  • 请求被拒绝: 检查是否加了User-Agent和Referer头。我遇到过最坑的一次,是忘了加Referer,结果被东方财富封了IP。
  • 数据格式变化: 金融网站的API接口偶尔会更新。建议每次运行前先打印原始数据看看,确认格式没变。
  • 频率限制: 不要频繁请求同一个接口。我一般设置每次请求间隔至少1秒,避免被服务器拉黑。
  • 数据缺失: 节假日没有交易数据,API可能返回空值。记得做空值处理。
我的习惯: 每次拿到数据后,我会先画个简单的折线图,看看数据趋势是否合理。如果某一天的数据突然跳变,那八成是数据有问题。先排查,再入库。

好了,这一章的内容就到这里。数据拿到了,下一章我们就可以开始分析北向资金与指数的关系了。记住,数据是基础,但更重要的是你怎么用它。


公众号:蓝海资料掘金营,微信deep3321