
1. 项目概述爬取东方财富网股票数据并存储到MySQL最近在做一个金融数据分析的小项目需要获取A股市场的实时行情数据。东方财富网作为国内领先的财经门户其股票数据页面结构清晰、更新及时非常适合作为数据源。本文将分享如何用Python爬虫抓取东方财富网的个股数据并通过PyMySQL库将清洗后的数据存入MySQL数据库的全过程。这个方案特别适合以下场景需要建立本地股票数据库进行量化分析想要定期采集特定股票的历史行情需要将不同来源的金融数据集中存储管理提示实际操作前请务必阅读东方财富网的robots.txt文件控制爬取频率建议设置2秒以上的请求间隔2. 环境准备与工具选型2.1 基础环境配置首先需要准备以下环境Python 3.7推荐3.9版本MySQL 5.7社区版即可开发工具VS Code或PyCharm关键Python库安装pip install requests beautifulsoup4 pymysql pandas2.2 技术栈选择考量选择RequestsBeautifulSoup组合而非Scrapy的原因东方财富网页面结构相对简单不需要复杂的爬虫框架项目数据量不大单次抓取约几十只股票更轻量级适合新手快速上手选择MySQL存储的三大优势结构化存储便于后续的SQL查询分析与Python生态集成良好PyMySQL库支持事务确保数据完整性3. 网页分析与数据抓取3.1 东方财富网页面结构解析以贵州茅台(600519)的个股页面为例http://quote.eastmoney.com/sh600519.html关键数据位置当前价classprice的div涨跌幅classchange的span成交量idvolume的span市盈率classpe的td3.2 Python爬虫实现代码import requests from bs4 import BeautifulSoup import time def get_stock_data(stock_code): url fhttp://quote.eastmoney.com/{sh if stock_code.startswith(6) else sz}{stock_code}.html headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 } try: response requests.get(url, headersheaders) soup BeautifulSoup(response.text, html.parser) data { code: stock_code, price: soup.find(div, class_price).get_text(), change: soup.find(span, class_change).get_text(), volume: soup.find(span, idvolume).get_text(), pe: soup.find(td, class_pe).get_text(), timestamp: int(time.time()) } return data except Exception as e: print(f获取{stock_code}数据失败{str(e)}) return None重要提醒务必设置合理的请求间隔建议使用time.sleep(2)控制爬取频率4. MySQL数据库设计与存储实现4.1 数据库表结构设计创建stock_data表CREATE TABLE stock_data ( id int(11) NOT NULL AUTO_INCREMENT, stock_code varchar(10) NOT NULL, price decimal(10,2) DEFAULT NULL, change_percent decimal(10,2) DEFAULT NULL, volume bigint(20) DEFAULT NULL, pe_ratio decimal(10,2) DEFAULT NULL, create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_code (stock_code), KEY idx_time (create_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;4.2 Python连接MySQL的完整示例import pymysql def save_to_mysql(data): connection pymysql.connect( hostlocalhost, useryour_username, passwordyour_password, databasestock_db, charsetutf8mb4 ) try: with connection.cursor() as cursor: sql INSERT INTO stock_data (stock_code, price, change_percent, volume, pe_ratio) VALUES (%s, %s, %s, %s, %s) cursor.execute(sql, ( data[code], float(data[price]), float(data[change].strip(%)), int(data[volume]), float(data[pe]) )) connection.commit() finally: connection.close()5. 完整工作流与优化方案5.1 主程序逻辑整合def main(): stock_list [600519, 000858, 601318] # 茅台、五粮液、平安 for code in stock_list: data get_stock_data(code) if data: save_to_mysql(data) time.sleep(3) # 严格遵守爬虫礼仪 if __name__ __main__: main()5.2 性能优化建议使用连接池管理数据库连接实现异常重试机制最多3次添加日志记录功能考虑使用多线程加速但要控制总请求频率6. 常见问题与解决方案6.1 数据抓取失败排查问题现象可能原因解决方案返回403错误IP被限制1. 检查User-Agent 2. 增加延迟 3. 使用代理IP数据为空页面改版1. 更新CSS选择器 2. 检查JavaScript渲染连接超时网络问题1. 增加超时时间 2. 添加重试逻辑6.2 MySQL存储异常处理数据库写入时的三个关键检查点字段类型匹配特别是字符串转数字唯一键冲突处理事务回滚机制改进后的存储函数示例def safe_save_to_mysql(data): try: # 转换数据类型 data[price] float(data[price]) data[change] float(data[change].strip(%)) data[volume] int(data[volume].replace(,, )) data[pe] float(data[pe]) if data[pe] ! - else None save_to_mysql(data) except ValueError as e: print(f数据格式错误{e}) except pymysql.err.IntegrityError: print(重复数据跳过) except Exception as e: print(f数据库错误{e})7. 项目扩展方向7.1 定时任务实现使用APScheduler实现定时采集from apscheduler.schedulers.blocking import BlockingScheduler scheduler BlockingScheduler() scheduler.scheduled_job(cron, hour9-15, minute*/5) def scheduled_job(): main() scheduler.start()7.2 数据可视化分析结合Pandas和Matplotlibimport matplotlib.pyplot as plt def analyze_data(): connection pymysql.connect(...) df pd.read_sql(SELECT * FROM stock_data WHERE create_time DATE_SUB(NOW(), INTERVAL 7 DAY), connection) plt.figure(figsize(12,6)) for code, group in df.groupby(stock_code): plt.plot(group[create_time], group[price], labelcode) plt.legend() plt.show()在实际项目中我通常会设置凌晨2-4点进行历史数据补全避免交易日的高峰时段。对于高频数据需求建议考虑使用东方财富的API服务如有这比爬虫更稳定可靠。另外MySQL表设计时预留了20%的额外字段方便后续添加技术指标等衍生数据。