halo 的技术博客

返回

价格发现越来越发生在文本里。一条财报电话会的措辞变化、一则监管问询函、一个论坛里的持仓讨论,往往比正式披露更早反映预期。问题不是”文本重不重要”,而是你有没有能力把它变成能进回测循环的数值信号

这篇文章给你一条从网页到信号的完整流水线,并且每一步都附可运行的 Python。我们不只讲”怎么爬”,更讲”怎么让它可信”。

网页爬虫 + 文本挖掘:从原始网页到可回测信号的完整流水线

一、先讲红线:爬虫不是”能爬就爬”#

动手之前,有三件事比代码更重要:

  1. 读 robots.txt。 目标站根目录下的 robots.txt 写明了哪些路径允许抓取、抓取频率上限。这是行业共识级的礼貌与合规底线。
  2. 限速与标识。 给请求加 User-Agent,并在两次请求间 sleep(随机 1~3 秒)。高频轰炸既可能把对方服务器打挂,也会让你的 IP 很快进黑名单。
  3. 看清楚 ToS 与版权。 新闻、研报、论坛内容大多有版权与”禁止抓取”条款。研究用途vs商业用途、个人vs分发,法律边界完全不同。本文所有代码仅作方法演示,实盘务必以目标平台授权为准。

二、Python 实战 1:采集财经新闻标题#

最朴素的静态页面,用 requests + BeautifulSoup 就够。动态渲染(JS 加载)的页面要上 Selenium / Playwright,思路一致,只是多一层”等页面渲染完”。

要点:选择器(css_selector)和目标站 DOM 结构强绑定,对方改版你的爬虫就失效—这是文本采集最大的运维成本。生产上建议把”抓取”和”解析”解耦,解析规则可配置化。

三、Python 实战 2:中文分词与清洗#

英文按空格分词,中文要借助 jieba。清洗的核心是:去停用词、去标点、过滤单字噪声,否则 TF-IDF 会被”的/了/在”这类高频无意义词占据。

四、Python 实战 3:情感打分 → 日度情绪指数#

词典法是最稳的起点:维护一份”利好词/利空词”表,统计一篇文本里正负词的出现比例,归一化到 [-1, 1]。它可解释、不易过拟合,适合作为信号的”baseline”。

把这条指数画出来,你会看到它有明显的主题波动—某些天因为利空词集中而跌到负值区,某些天因利好扎堆而冲高。

文本挖掘得到的日度情绪指数:领先于价格拐点的软信息

五、Python 实战 4:TF-IDF 把文本压成特征,并做领先-滞后检验#

单一情感值太粗。TfidfVectorizer 能把每篇文档变成”词×文档”的数值矩阵,行归一后,每篇文档就是高维空间里的一个点,可以做聚类、相似度、甚至喂给下游模型。

from sklearn.feature_extraction.text import TfidfVectorizer

vec = TfidfVectorizer(tokenizer=tokenize, max_features=200)
X = vec.fit_transform(docs)
print("TF-IDF 矩阵形状 (文档数 × 词数):", X.shape)

# 领先-滞后检验:情绪是否真的领先于收益?
# 假设次日收益受「当日情绪」驱动:ret[t] = a * sent[t-1] + 噪声
ret = 0.5 * np.roll(daily, 1) + rng.normal(0, 0.4, len(daily))
lead_corr = np.corrcoef(daily[:-1], ret[1:])[0, 1]
print(f"情绪(t) 与 收益(t+1) 的相关系数: {lead_corr:.3f}")
python

文档-词项 TF-IDF 矩阵:文本被压成可量化、可聚类的数值特征

如果 lead_corr 显著为正,说明“今天文本情绪 → 明天价格”这条链路在样本里成立。但注意:这只说明样本里成立。 真正要下结论,必须跨时间段、跨标的重复检验,并用样本外数据验证。绝大多数“文本 alpha”死在这第二步。

五、把单篇打分落成日频面板#

上面的 daily 只是 30 个随机数。真实工程里,你要维护一张「日期 × 来源」的面板,而时间戳是防止前视偏差的生命线:

import pandas as pd
# 每条记录都带发布时间戳——它必须早于你用它下注的时刻
records = pd.DataFrame({
    "datetime": pd.date_range("2026-01-01", periods=200, freq="1h"),
    "source":   np.random.choice(["新闻", "研报", "论坛"], 200),
    "text":     np.random.choice(docs, 200),
})
records["sent"] = records["text"].map(sentiment)
daily_panel = (records.set_index("datetime")["sent"]
                    .resample("1D").mean()      # 日频聚合
                    .rolling(5).mean())        # 5 日平滑,抑制噪声
print(daily_panel.dropna().head())
python

三个关键工程点:(1) 时间戳必须早于你下注的时刻,否则就是前视;(2) 不同来源要分开存,方便做“新闻 vs 论坛”的截面对比与加权;(3) 对原始情绪做平滑(移动平均)通常能提升信噪比,但会引入滞后,必须在回测里显式建模这段延迟。

进阶:词典法之外#

词典法便宜、可解释,但抓不住反讽和上下文。进阶路线有两条:

  • FinBERT / 金融预训练模型:在金融语料上微调的 BERT,能给出句子级情感概率,对“业绩‘好’得离谱”这类反讽更鲁棒;代价是推理成本与训练数据偏差。
  • 词向量 / 主题模型:用 Word2Vec、LDA 把“营收超预期”和“利润大涨”在向量空间里拉近距离,做语义聚类,发现词典法漏掉的隐性主题。

无论哪条路线,最终都要回到第四步的领先-滞后检验——模型越复杂,越要证明它不是在拟合样本噪声

六、真实陷阱:别让你的信号是幻觉#

1. 前视偏差(最致命)。 用”当天收盘后发布的财报新闻”去解释”当天收益”,是典型的前视。文本时间戳必须严格早于你用它下注的时刻;新闻抓取时间、数据入库时间都要打点留痕。

2. 机器人放大与回音室。 社交媒体上大量内容由机器人生成,情绪指数会被水军和算法推荐放大。要做的不是直接吃原始情绪,而是做异常度检测(今天情绪相对过去 N 天 Z-score 偏离多少),过滤”日常噪声”。

3. 文本噪声 > 信号。 错别字、同义词、反讽(“这业绩真是’好’啊”)都会污染词典法。进阶用 FinBERT 这类金融预训练模型做上下文情感,但模型本身也可能过拟合到训练样本的特定表述。

4. 幸存者偏差。 你能抓到的论坛帖子,往往来自还活着的账号;退市、封号的那些声音消失了,你的语料天然偏乐观。

5. 合规与可得性。 抓取频率受限、源站改版、接口收费变动,都会让”信号”变成”时有时无的噪声”。生产系统必须监控数据源健康度,信号缺失时要能优雅降级。

小结#

网页爬虫与文本挖掘,本质是把非结构化的语言翻译成结构化的数值。它的门槛不在爬虫本身,而在:合规地、稳定地、时序正确地把文本变成可信信号,再用领先-滞后和样本外检验证明它不是幻觉。词典法打底、TF-IDF 做特征工程、FinBERT 做语义升级—这条流水线,是今天另类数据量化最值得投入的基本功之一。

至此,我们聊完了”行为组合理论”(怎么组织你的心理账户)和”文本挖掘”(怎么从语言里挖信号)。两者看似无关,其实都指向同一件事:量化不只是数学,更是理解信息与人的方式。

网页爬虫与文本挖掘:把非结构化网页变成可回测的量化信号
https://blog.halo26812.eu.org/blog/web-scraping-text-mining
Author halo
Published at 2026年7月10日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨