欢迎光临
我们一直在努力

Python股票数据爬虫实战:Requests+BeautifulSoup+SQLite方案

1. 项目概述:为什么一个真实交易者会亲手写爬虫抓股票数据

我做量化策略开发快八年了,从最早在券商柜台手抄行情,到后来用Excel VBA调接口,再到如今自己搭数据管道——爬虫不是炫技的玩具,而是每天开盘前必须跑通的“数据心跳”。很多人一提Web Scraping就想到“绕过API”“违规风险”,但现实是:A股很多关键数据(比如龙虎榜详细席位、个股研报摘要、北向资金逐笔明细、甚至某些小众行业ETF的持仓变动)压根没有稳定公开API,或者API要付费且延迟严重。去年我盯一只次新股,发现其龙虎榜上某家游资席位连续三天净买入超5000万,但官方数据要T+1才更新,而爬取交易所公告页面,我能提前2小时拿到原始HTML里的实时披露文本。这不是钻空子,是补全信息差的必要动作。

核心关键词 Data Science 在这里不是宽泛概念,它特指“用可复现、可验证、可回溯的方式,把非结构化网页数据变成结构化时间序列”。你不需要成为HTML专家,但得懂DOM树怎么嵌套、CSS选择器怎么定位、HTTP请求头里User-Agent和Referer为什么不能乱填。这篇文章讲的,就是我日常用Python写的那个“股票数据采集脚手架”——它不追求一次性抓全市场,而是专注解决三个最痛的场景:实时行情快照、公告文本解析、以及财务数据表格提取。它跑在我自己的树莓派上,每天凌晨3点自动拉取最新财报PDF里的关键页,OCR识别后存进本地SQLite,整个过程不用碰任何商业数据库或云服务。如果你也常被“数据等不及”“格式太混乱”“源站反爬太烦”这些问题卡住,这篇就是为你写的。

2. 整体设计思路与方案选型逻辑

2.1 为什么放弃Selenium,坚持Requests+BeautifulSoup组合

新手常问:“为啥不用Selenium?它能渲染JS啊!”——这话对了一半。我试过用Selenium抓雪球网的个股讨论区,确实能拿到动态加载的评论,但代价是什么?启动一个Chrome实例要消耗400MB内存,单次请求耗时平均2.8秒,而同样的页面用Requests发GET请求只要0.3秒。更致命的是稳定性:Selenium在无头模式下遇到证书错误、DNS超时、页面重定向链断裂,经常直接抛出WebDriverException,而Requests的异常类型清晰(ConnectionError、Timeout、HTTPError),配合retry机制能99%自动恢复。

但Requests真能搞定所有场景吗?当然不能。比如东方财富网的F10页面,关键财务数据是JS异步加载的,直接GET返回的HTML里只有占位符。这时候我的方案是分层处理:先用Requests获取初始HTML,解析出JS里埋的data-id参数,再拼接出真正的AJAX接口URL(形如 https://emweb.securities.eastmoney.com/PC_HSF10/NewFinanceAnalysis/zycwzbAjax?code=sh600519 ),最后用Requests调这个纯JSON接口。你看,没动Selenium一根毫毛,却拿到了最干净的数据源。这背后是“能静态不动态,能接口不渲染”的铁律——每多一层JS渲染,就多一分不可控。

提示:判断一个页面是否需要Selenium,只看三件事:1)打开浏览器开发者工具,禁用JS后刷新页面,核心数据是否还在;2)Network标签页里,关键数据是否来自XHR/Fetch请求;3)该XHR请求的URL是否含动态参数(如时间戳、随机token)。三者满足其二,就别碰Selenium。

2.2 为什么用SQLite而不是MySQL或PostgreSQL

有人看到“股票数据”就本能想上分布式数据库。但想想你的实际需求:日线数据每天新增1万条,月线数据每月1千条,公告文本每年几百篇。这些数据总量十年不到10GB,而SQLite单文件支持最大140TB。更重要的是原子性——我写入一条行情记录的同时,要更新对应股票的最新PE值,这两个操作必须在一个事务里完成。MySQL也能做,但你要配主从、设连接池、防连接泄漏;而SQLite一句 conn.execute(\”BEGIN TRANSACTION\”) 就搞定,崩溃时自动回滚,连事务日志都不用管。

实测对比:同样插入10万条日线数据(含索引),SQLite耗时1.2秒,MySQL(本地部署)耗时3.7秒,差距主要在TCP握手和查询解析开销。而且SQLite零配置,代码里 sqlite3.connect(\”stocks.db\”) 就行,部署时直接拷贝.db文件,哪像MySQL还得折腾docker-compose.yml和my.cnf。当然,如果要做实时流计算或百人并发查询,那另当别论——但对个人策略回测和监控,SQLite是被严重低估的利器。

2.3 反爬策略的本质不是对抗,而是模拟“合理访问”

很多人把反爬当成黑客攻防,拼命研究加密参数、逆向JS。其实90%的网站反爬,只是想拦住不懂规矩的脚本。我总结出三条“人类行为准则”:

  • 节奏合理 :模拟真实用户间隔,用 time.sleep(random.uniform(1.5, 3.2)) ,而不是固定2秒。交易所网站尤其敏感,我观察过人工刷新龙虎榜页面,平均间隔是2.7秒。
  • 身份真实 :User-Agent不能用默认的 python-requests/2.28.1 ,得换主流浏览器标识,比如 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 ;Referer必须填来源页面URL,否则某些站点直接返回403。
  • 能力克制 :禁用cookies(除非登录必需)、禁用压缩( headers={\”Accept-Encoding\”: \”identity\”} ),因为普通用户浏览器不会主动发gzip请求头。这点常被忽略——很多反爬系统就靠检测异常请求头来标记机器人。

去年我抓同花顺的研报摘要,按常规流程写了脚本,结果连续三天被封IP。抓包对比才发现:人工访问时,浏览器会先GET首页,再GET研报列表页,最后GET单篇详情页,三次请求的Cookie是连贯的;而我的脚本直奔详情页URL,缺少前置请求的Cookie链,被判定为“异常跳转”。补上两步前置请求后,问题消失。你看,反爬不是技术难题,是行为学问题。

3. 核心细节解析与实操要点

3.1 HTML结构解析:从“看源码”到“读DOM树”

新手常犯的错是:对着浏览器右键“查看网页源代码”,看到一堆div就懵了。但真实开发中,你根本不用肉眼找元素——用开发者工具的“Elements”面板,鼠标悬停就能高亮对应区域。重点看三点:

  • 层级路径是否唯一 :比如想抓“贵州茅台”当前股价,找到显示数字的 <span> 标签,右键Copy → Copy selector,得到 #stockname > div:nth-child(1) > span 。但这个选择器依赖父级div的序号,一旦页面改版, nth-child(1) 可能变成 nth-child(2) 。更好的方式是找带语义的class,比如 <span class=\”price-now\”>1823.50</span> ,用 soup.select(\”span.price-now\”) 。

  • 数据是否藏在属性里 :很多网站把真实数值存在 data-* 属性中。比如雪球网的涨跌幅,HTML是 <span data-current=\”1823.50\” data-change=\”24.80\”>+1.38%</span> ,这时 span.text 只能拿到百分比,而 span.get(\”data-current\”) 才能拿到精确价格。我专门写了个函数遍历所有 data-* 属性,优先取

  • 赞(0)
    未经允许不得转载:171主机测评 » Python股票数据爬虫实战:Requests+BeautifulSoup+SQLite方案
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址