第二章:北向资金数据获取——数据源介绍与实战爬取
各位同学,欢迎来到第二章。
上一章我们聊了北向资金为什么值得关注。今天,咱们直接动手——把数据拿到手。
做量化交易,数据就是你的弹药。没有数据,再好的策略也是空中楼阁。我个人习惯先把数据源摸清楚,再决定用什么工具去拿。今天我们就围绕两个主流数据源:东方财富和同花顺,讲讲怎么用Python把它们的数据“请”出来。
2.1 数据源对比:东方财富 vs 同花顺
先说说这两个平台。东方财富和同花顺,是国内散户和机构用得最多的两个金融数据平台。它们各有千秋,我分别讲一下。
| 对比维度 | 东方财富(Choice/EastMoney) | 同花顺(iFinD) |
|---|---|---|
| 数据覆盖 | 沪深港通、个股资金流、板块资金 | 沪深港通、Level-2、龙虎榜 |
| 接口稳定性 | 较稳定,反爬策略中等 | 较稳定,反爬策略较强 |
| 免费数据量 | 历史数据较全,实时数据有延迟 | 历史数据较全,实时数据需付费 |
| Python支持 | 有非官方API,社区活跃 | 有非官方API,但文档较少 |
| 个人推荐 | 适合初学者和中小资金 | 适合进阶用户和机构 |
我个人更倾向于先用东方财富。为什么?因为它的网页端数据接口相对容易解析,而且社区里有很多现成的轮子可以用。同花顺的数据质量更高,但反爬策略也更严,新手容易碰壁。
2.2 Python爬虫基础——你只需要这三板斧
说到爬虫,很多同学觉得很难。其实说白了,就是模拟浏览器去访问网页,然后把数据拿回来。你只需要掌握三个库:requests、BeautifulSoup、json。
我刚开始写爬虫时,也踩过不少坑。有一次爬东方财富的北向资金数据,怎么都拿不到,后来发现是忘了加请求头。嗯,这里要注意——很多网站会检查你是不是真人访问。
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)
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)
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实战,是一条完整的链路。
2.5 常见问题与避坑指南
- 请求被拒绝: 检查是否加了User-Agent和Referer头。我遇到过最坑的一次,是忘了加Referer,结果被东方财富封了IP。
- 数据格式变化: 金融网站的API接口偶尔会更新。建议每次运行前先打印原始数据看看,确认格式没变。
- 频率限制: 不要频繁请求同一个接口。我一般设置每次请求间隔至少1秒,避免被服务器拉黑。
- 数据缺失: 节假日没有交易数据,API可能返回空值。记得做空值处理。
好了,这一章的内容就到这里。数据拿到了,下一章我们就可以开始分析北向资金与指数的关系了。记住,数据是基础,但更重要的是你怎么用它。
公众号:蓝海资料掘金营,微信deep3321