3、数据采集与清洗:社交媒体API调用(Twitter/微博),新闻爬虫基础,数据清洗与预处理(去噪、标准化)
做情绪数据与价格联动模型,第一步不是建模,而是搞数据。
我见过太多人一上来就调包跑LSTM,结果数据里全是垃圾,模型自然一塌糊涂。说白了,情绪数据这东西,比K线数据脏得多。K线好歹是交易所出来的标准化数据,情绪数据呢?推特上的表情包、微博里的阴阳怪气、新闻标题的夸张修辞……全是噪音。
这一章,我们就来解决这个问题。我会把我在实战中踩过的坑、总结的经验,一股脑倒出来。
3.1 社交媒体API调用:Twitter与微博
先聊Twitter。Twitter的API v2是目前的主流。我个人习惯用 tweepy 这个库,封装得比较舒服。
你需要先去Twitter Developer Portal申请一个Bearer Token。嗯,这里要注意,免费版有速率限制,每分钟只能拉450条。做量化研究其实够用了,但如果你要实盘高频扫描,得升级到Academic Research级别。
import tweepy
import pandas as pd
# 初始化客户端
client = tweepy.Client(bearer_token='你的Bearer Token')
# 搜索关键词
query = '比特币 OR BTC OR 加密货币 lang:en -is:retweet'
tweets = client.search_recent_tweets(
query=query,
max_results=100,
tweet_fields=['created_at', 'public_metrics']
)
# 提取数据
data = []
for tweet in tweets.data:
data.append({
'text': tweet.text,
'time': tweet.created_at,
'likes': tweet.public_metrics['like_count'],
'retweets': tweet.public_metrics['retweet_count']
})
df = pd.DataFrame(data)
print(df.head())
微博呢?说实话,微博的API比Twitter难搞。官方API对个人开发者限制很多,而且中文文本的处理比英文复杂——分词、表情符号、@用户、话题标签……全是坑。
我曾经试过用 weibo-scraper 这类第三方工具,但稳定性堪忧。后来我改用Selenium模拟浏览器抓取,虽然慢,但胜在可控。不过要注意,微博的反爬机制挺严的,频繁请求会被封IP。
3.2 新闻爬虫基础
新闻数据和社交媒体数据,性质完全不同。社交媒体是「情绪的快照」,新闻是「事件的记录」。做联动模型时,两者都要用。
新闻爬虫,我推荐 newspaper3k 这个库。它能把一篇新闻的标题、正文、发布时间、作者、摘要全扒下来,而且自带一些去噪功能。
from newspaper import Article
url = 'https://www.coindesk.com/...'
article = Article(url)
article.download()
article.parse()
news_data = {
'title': article.title,
'text': article.text,
'publish_date': article.publish_date,
'summary': article.summary
}
但这里有个坑:新闻网站的HTML结构经常变。你想想看,今天爬得好好的,明天网站改版了,你的解析逻辑就全废了。所以我一般会加一层异常处理,爬不到就跳过,别让一个坏链接卡死整个流程。
3.3 数据清洗与预处理:去噪、标准化
数据拿到手了,但离能用还差得远。社交媒体和新闻文本里,充斥着大量噪音。
3.3.1 去噪
去噪,说白了就是把没用的东西扔掉。我总结了一套标准流程:
- 去除HTML标签:新闻正文里偶尔会残留
<p>、<br>之类的标签。 - 去除URL和@提及:推特里的链接和@用户,对情绪分析没意义。
- 去除特殊符号和emoji:除非你要分析emoji情绪,否则建议去掉。但注意,有些emoji有明确情绪倾向(比如😡、😂),如果你要做细粒度分析,可以保留并映射成文字。
- 去除停用词:中文的「的、了、是」,英文的「the、a、is」——这些词不承载情绪。
- 去除重复内容:同一个新闻被多家媒体转载,内容几乎一样。我一般用SimHash去重。
import re
import emoji
def clean_text(text):
# 去HTML标签
text = re.sub(r'<[^>]+>', '', text)
# 去URL
text = re.sub(r'http\S+', '', text)
# 去@提及
text = re.sub(r'@\w+', '', text)
# 去emoji(可选)
text = emoji.replace_emoji(text, replace='')
# 去多余空格
text = re.sub(r'\s+', ' ', text).strip()
return text
3.3.2 标准化
标准化,就是把不同来源的数据拉到同一个尺度上。比如Twitter的互动量是几百,新闻的阅读量可能是几万,直接放一起建模会出问题。
我常用的标准化方法有两种:
| 方法 | 公式 | 适用场景 |
|---|---|---|
| Z-score标准化 | (x - μ) / σ | 数据近似正态分布时 |
| Min-Max标准化 | (x - min) / (max - min) | 数据有明确上下界时 |
我个人习惯用Z-score。为什么?因为情绪数据经常有极端值——比如一条推文突然爆火,互动量是平时的100倍。Min-Max会被这种极端值压扁,而Z-score还能保留相对关系。
3.4 知识体系总览
下面这张图,是我自己梳理的数据采集与清洗流程。你可以把它当作一个检查清单。
你看,从数据源到最终可用的标准化数据,中间要经过好几道工序。每一道工序都可能出问题——API限流、爬虫被封、去噪过度把情绪词也删了……
我刚开始做这个模型时,花在数据清洗上的时间,比建模多三倍。但后来发现,这时间花得值。数据干净了,模型自然就听话了。
好了,数据采集和清洗就聊到这儿。下一章我们会把这些清洗好的情绪数据,和价格数据对齐,然后开始做特征工程。嗯,那才是真正有意思的部分。
公众号:蓝海资料掘金营,微信deep3321