第3章:数据采集基础:Python爬虫入门(requests + BeautifulSoup)
做量化分析,数据就是命根子。
我见过太多人,策略模型写得天花乱坠,结果一跑起来,数据源断了,或者拿到的数据全是错的。说白了,没有靠谱的数据采集,后面的一切都是空中楼阁。
这一章,我们就来搞定最基础、也是最核心的一环——用Python爬虫抓取财经新闻标题和评论数据。别怕,没那么玄乎,跟着我一步步来。
3.1 为什么非得自己爬数据?
你可能会问:现在不是有很多现成的数据API吗?
嗯,确实有。但现实是:
- 收费贵:专业金融数据接口,一年几万到几十万不等,个人玩家根本扛不住。
- 有延迟:免费API往往有15分钟甚至更长的延迟,做短线分析基本废了。
- 数据不全:很多平台只提供结构化数据,但新闻标题、评论这种非结构化数据,它们不给你。
所以,自己动手爬,是最灵活、最省钱的方式。我在做舆情因子研究时,就靠这个抓了上百万条新闻标题,效果出奇的好。
3.2 准备工作:装好你的工具箱
我们需要两个核心库:
- requests:用来发HTTP请求,说白了就是模拟浏览器去访问网页。
- BeautifulSoup:用来解析HTML,从一堆标签里把我们需要的数据提取出来。
安装很简单,一行命令搞定:
pip install requests beautifulsoup4
小提示: 我个人习惯在虚拟环境里装,避免跟其他项目冲突。你如果刚入门,直接装全局也行,问题不大。
3.3 第一个实战:抓取财经新闻标题
我们拿东方财富网的新闻板块来练手。为什么选它?因为结构相对规整,适合新手。
先看代码:
import requests
from bs4 import BeautifulSoup
# 目标网址
url = 'https://finance.eastmoney.com/a/czqyw.html'
# 伪装成浏览器,别让服务器认出你是爬虫
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
# 发请求
response = requests.get(url, headers=headers)
response.encoding = 'utf-8'
# 解析HTML
soup = BeautifulSoup(response.text, 'html.parser')
# 找到新闻标题所在的标签
# 我观察过,东方财富的新闻标题都在 <a> 标签里,class 为 'title'
news_items = soup.find_all('a', class_='title')
for item in news_items[:10]: # 先打印前10条
title = item.get_text(strip=True)
link = item.get('href')
print(f'标题:{title}')
print(f'链接:{link}')
print('---')
跑一下,你就能看到类似这样的输出:
标题:A股三大指数震荡整理 半导体板块走强
链接:https://finance.eastmoney.com/a/202503213456789.html
---
标题:央行最新表态:货币政策仍有空间
链接:https://finance.eastmoney.com/a/202503213456790.html
---
核心要点:
- User-Agent一定要加,不加的话很多网站直接拒绝你。我曾经因为忘了加这个,排查了半天,结果就是被反爬了。
- 编码设置:response.encoding = 'utf-8',不然中文会乱码。
- find_all的用法:第一个参数是标签名,第二个参数是筛选条件。class_后面有个下划线,因为class是Python关键字。
3.4 进阶:抓取评论数据
新闻标题好抓,评论就麻烦一点。很多网站的评论是动态加载的,直接抓HTML拿不到。
怎么办?
我常用的方法是:打开浏览器的开发者工具(F12),看Network面板,找到真正的数据接口。
以某财经网站为例,评论数据通常是通过AJAX请求加载的,返回的是JSON格式。我们直接模拟这个请求就行:
import requests
import json
# 评论数据的真实接口(从浏览器里找到的)
comment_url = 'https://comment.eastmoney.com/api/comment/list'
params = {
'article_id': '123456789', # 新闻的ID
'page': 1,
'page_size': 20
}
headers = {
'User-Agent': 'Mozilla/5.0',
'Referer': 'https://finance.eastmoney.com/' # 有些网站会检查来源
}
resp = requests.get(comment_url, params=params, headers=headers)
data = resp.json()
# 提取评论内容
for comment in data['data']['list']:
content = comment['content']
print(f'评论:{content}')
避坑指南:
- 频率控制:别一秒发几十个请求,会被封IP。我一般加个time.sleep(1)。
- Referer检查:有些网站会验证请求来源,不加Referer直接返回空数据。我曾经在这上面栽过跟头。
- 数据格式:返回的JSON结构每个网站都不一样,需要耐心解析。建议先用print(data)看看整体结构。
3.5 本章知识体系
下面这张图,帮你把整个流程串起来:
3.6 避坑总结
最后,分享几个我踩过的坑:
- 别用默认的User-Agent:很多网站直接屏蔽Python的默认请求头。我一般从浏览器里复制一个真实的User-Agent过来。
- 注意请求频率:我曾经为了赶项目,写了个循环每秒发10个请求,结果IP被封了三天。后来学乖了,每次请求之间至少等1秒。
- 数据清洗不能省:爬下来的数据经常带空格、换行、HTML标签。记得用strip()和正则表达式清理一下。
- 保存原始数据:我习惯把爬到的原始HTML或JSON先存一份,万一解析逻辑写错了,还能重新来过。
嗯,这一章的内容就到这。代码不多,但都是实战经验。你照着敲一遍,基本就能上手了。