【爬虫】爬取A股数据写入数据库(二)

在这里插入图片描述
前几天有写过一篇 【爬虫】爬取A股数据写入数据库(一),现在继续完善下,将已有数据通过ORM形式批量写入数据库。
2024/05,本文主要内容如下:

  1. 对东方财富官网进行分析,并作数据爬取,使用python,使用pip install requests 模拟http数据请求,获取数据。
  2. 将爬取的数据写入通过 sqlalchemy ORM 写入 sqlite数据库。
  3. 记录爬取股票的基本信息,如果库中已存在某个股票代码,则进行更新。
  4. 后续计划:会不断完善,最终目标是做出一个简单的股票查看客户端。
  5. 本系列所有源码均无偿分享,仅作交流无其他,供大家参考。
    python依赖环境如下:
conda create --name xuan_gu python=3.9 --channel https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda remove --name xuan_gu --all
conda activate xuan_gu#pip install PyQt5==5.15.10 -i https://pypi.tuna.tsinghua.edu.cn/simple
#pip install pyqtgraph==0.13.6 -i https://pypi.tuna.tsinghua.edu.cn/simple
#python -m pyqtgraph.examples 查看图形化的pyqtgraph示例pip install requests==2.31.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install pandas==2.2.2 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install jsonpath==0.8.2 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install sqlalchemy==2.0.30 -i https://pypi.tuna.tsinghua.edu.cn/simple

1. 对东方财富官网的分析

东方财富网页地址:https://data.eastmoney.com/gdhs/
通过分析网页,发现https://datacenter-web.eastmoney.com/api/data/v1/get?请求后面带着一些参数即可以获取到相应数据,我们不断调试,模拟这类请求即可。分析过程如下图所示,F12调出调试框,不断尝试:
| ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/dcd5a9558b7a49e29f834d9fa0cebad4.png
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 爬取数据代码逻辑

如下即爬取数据的可运行代码,复制后直接能跑:

import pandas as pd
from typing import List
import requestsclass CustomedSession(requests.Session):def request(self, *args, **kwargs):kwargs.setdefault('timeout', 60)return super(CustomedSession, self).request(*args, **kwargs)
session = CustomedSession()
adapter = requests.adapters.HTTPAdapter(pool_connections = 50, pool_maxsize = 50, max_retries = 5)
session.mount('http://', adapter)
session.mount('https://', adapter)# 请求地址
QEURY_URL = 'http://datacenter-web.eastmoney.com/api/data/v1/get'
# HTTP 请求头
EASTMONEY_REQUEST_HEADERS = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko','Accept': '*/*','Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',# 'Referer': 'http://quote.eastmoney.com/center/gridlist.html',
}# 请求返回值过滤
RESULT_FIELDS = {'SECURITY_CODE': '股票代码','SECURITY_NAME_ABBR': '股票名称','END_DATE': '本次股东户数统计截止日','PRE_END_DATE': '上次股东户数统计截止日','INTERVAL_CHRATE': '区间涨跌幅','AVG_MARKET_CAP': '户均持股市值','AVG_HOLD_NUM': '户均持股数量','TOTAL_MARKET_CAP': '总市值','TOTAL_A_SHARES': '总股本','HOLD_NOTICE_DATE': '公告日期','HOLDER_NUM': '本次股东户数','PRE_HOLDER_NUM': '上次股东户数','HOLDER_NUM_CHANGE': '股东户数增减','HOLDER_NUM_RATIO': '股东户数较上期变化百分比',  'f2': '最新价','f3': '涨跌幅百分比',
}"""
获取沪深A股市场最新公开的股东数目变化情况: 当作获取所有股票
"""
def get_latest_holder_number() -> pd.DataFrame:# 请求页码QEURY_PAGE = 1PAGE_COUNT = 100dfs: List[pd.DataFrame] = []while 1:if QEURY_PAGE > PAGE_COUNT:break# 请求参数QUERY_PARAM = [('sortColumns', 'HOLD_NOTICE_DATE,SECURITY_CODE'),('sortTypes', '-1,-1'),('pageSize', 500),('pageNumber', QEURY_PAGE),('columns', 'SECURITY_CODE,SECURITY_NAME_ABBR,END_DATE,INTERVAL_CHRATE,AVG_MARKET_CAP,AVG_HOLD_NUM,TOTAL_MARKET_CAP,TOTAL_A_SHARES,HOLD_NOTICE_DATE,HOLDER_NUM,PRE_HOLDER_NUM,HOLDER_NUM_CHANGE,HOLDER_NUM_RATIO,END_DATE,PRE_END_DATE',),('quoteColumns', 'f2,f3'),('source', 'WEB'),('client', 'WEB'),('reportName', 'RPT_HOLDERNUMLATEST'),]params = tuple(QUERY_PARAM)response = session.get(QEURY_URL, headers=EASTMONEY_REQUEST_HEADERS, params=params)resultJson = response.json()PAGE_COUNT = resultJson.get('result').get('pages')print('json len=', len(str(resultJson)), 'page count=', PAGE_COUNT, 'page number=', QEURY_PAGE)if PAGE_COUNT is None:breakdata = resultJson.get('result').get('data')if data is None:breakdf = pd.DataFrame(data)df = df.rename(columns=RESULT_FIELDS)[RESULT_FIELDS.values()]dfs.append(df)QEURY_PAGE += 1if len(dfs) == 0:df = pd.DataFrame(columns=RESULT_FIELDS.values())return dfdf = pd.concat(dfs, ignore_index=True)return dfif __name__ == "__main__":data = get_latest_holder_number()print(data)

调用如上函数即可:
在这里插入图片描述

3. 将爬取的数据通过ORM形式写入数据库

from sqlalchemy import create_engine, Column, Integer, String, DateTime, Float, Index
from sqlalchemy.orm import declarative_base, sessionmaker
from sqlalchemy.orm import scoped_session
from datetime import datetime# 声明一个基类,所有的ORM类都将继承自这个基类
Base = declarative_base()# 创建引擎
engine = create_engine('sqlite:///a.db',  echo=False)
# 绑定引擎
Session = sessionmaker(bind=engine)
# 创建数据库链接池,直接使用session即可为当前线程拿出一个链接对象conn
session = scoped_session(Session)# 股票基础信息表
class stock_base_info(Base):__tablename__ = 'stock_base_info'SECURITY_CODE = Column(String, primary_key=True, index=True, nullable=False, comment="股票代码")SECURITY_NAME_ABBR = Column(String, nullable=False, comment="股票名称")TOTAL_MARKET_CAP = Column(Float, comment="总市值")TOTAL_A_SHARES = Column(Float, comment="总股本")HOLD_NOTICE_DATE = Column(String, comment="公告日期")HOLDER_NUM = Column(Integer, comment="本次股东户数")HOLDER_NUM_RATIO = Column(String, comment="股东户数较上期变化百分比")PRE_HOLDER_NUM = Column(Integer, comment="上次股东户数")f2 = Column(String, comment="股票价格")last_updated = Column(DateTime, default=datetime.now, onupdate=datetime.now, comment="最后更新时间")__table_args__ = (Index('idx_SECURITY_CODE_index', SECURITY_CODE, unique=True),)# 创建表, 创建所有class xx(Base)
Base.metadata.create_all(engine)  def insert_or_update_stock_info(net_list):all_instances = session.query(stock_base_info).all()db_list = []for v in all_instances:db_list.append({'SECURITY_CODE': v.SECURITY_CODE,'SECURITY_NAME_ABBR': v.SECURITY_NAME_ABBR,'TOTAL_MARKET_CAP': v.TOTAL_MARKET_CAP,'TOTAL_A_SHARES': v.TOTAL_A_SHARES,'HOLD_NOTICE_DATE': v.HOLD_NOTICE_DATE,'HOLDER_NUM': v.HOLDER_NUM,'HOLDER_NUM_RATIO': v.HOLDER_NUM_RATIO,'PRE_HOLDER_NUM': v.PRE_HOLDER_NUM,'f2': v.f2,})# 查询出库中所有的数据 db_list; 从爬取的数据 net_list 中找到库中已有的数据进行更新 形成 db_map 并批量更新# 将 net_list 中不在 db_list 中的数据,形成 net_map 并批量插入db_map, not_exist_map = {}, {}for v in db_list:db_map[v['SECURITY_CODE']] = vfor item in net_list:code = item['SECURITY_CODE']if code in db_map:db_map[code].update(item)else:     not_exist_map[code] = itemupdate_result = list(db_map.values())insert_result = list(not_exist_map.values())if len(update_result) > 0:session.bulk_update_mappings(stock_base_info, update_result)if len(insert_result) > 0:session.bulk_insert_mappings(stock_base_info, insert_result)session.commit()if __name__ == "__main__":pass

4. 整体逻辑流程

步骤:

  1. 爬取数据得到返回结果
  2. 将返回结果组成数组,并写入数据库
  3. 对于库中已存在的信息根据 股票代码 进行批量更新,对于不存在的进行批量插入
import stock
import db_ormdef update_base_info_db():data_df = stock.get_latest_holder_number()print('获取的股票数量=', data_df.shape)net_list = []for index, row in data_df.iterrows():code = row['股票代码']name = row['股票名称']cap = row['总市值']shares = row['总股本']data = row['公告日期']num = row['本次股东户数']pre_num = row['上次股东户数']ratio = row['股东户数较上期变化百分比']f2 = row['最新价'] # float类型net_list.append({'SECURITY_CODE': code,'SECURITY_NAME_ABBR': name,'TOTAL_MARKET_CAP': cap,'TOTAL_A_SHARES': shares,'HOLD_NOTICE_DATE': data,'HOLDER_NUM': num,'HOLDER_NUM_RATIO': ratio,'PRE_HOLDER_NUM': pre_num,'f2': str(f2),})if len(net_list) > 0:db_orm.insert_or_update_stock_info(net_list=net_list)if __name__ == "__main__":update_base_info_db()

最终结果保存在 a.db中,例如:
在这里插入图片描述
更多内容可关注我,后续源码包均在上面回复下载:
【爬虫】爬取A股数据系列工具

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/8779.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【高阶数据结构(二)】初识图论

💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:高阶数据结构专栏⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习更多Go语言知识   🔝🔝 高阶数据结构 1. 前言2. 图的基…

LED显示屏控制器5个问题和解答

在LED电子显示屏的使用和维护过程中,用户经常会遇到各种技术问题。以下是五个关于LED电子显示屏控制器的常见问题及其解答,由专业LED显示屏生产厂家提供,旨在帮助用户更好地理解和使用LED显示屏。 1. 嵌入式实时脱机二合一控制器的工作原理 嵌…

SpringCloud Alibaba Sentinel 修改Dashboard用户名和密码

目录 一、下载Sentinel的Jar包 二、在启动时修改用户名和密码的命令 三、测试登录成功 在网上找到了一大堆文章,没一个有用的,最终还是通过不断测试找到了这个方法。 一、下载Sentinel的Jar包 Releases alibaba/Sentinel GitHub 二、在启动时修改…

并发问题系统学习(更新中)

进程、线程 进程:进程是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。可以理解为一个java应用。 线程:线程是进程的一个执行路径,一个进程中至少有一个线程,进程中的多个线程共享进程的资源。…

C++笔试强训day15

目录 1.平方数 2.分组 Check函数的具体实现&#xff1a; 3.拓扑排序 1.平方数 链接 数学找规律&#xff0c;找离 x 最近的完全平方数 y。 先开平方根再利用四舍五入进位即可。 详细代码&#xff1a; #include <cmath> #include <iostream> using namespac…

【吊打面试官系列】Java高并发篇 - 你对线程优先级的理解是什么?

大家好&#xff0c;我是锋哥。今天分享关于 【你对线程优先级的理解是什么&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 你对线程优先级的理解是什么&#xff1f; 每一个线程都是有优先级的&#xff0c;一般来说&#xff0c;高优先级的线程在运行时会具有优先…

基于C语言中的类型转换,C++标准创造出了更加可视化的类型转换

目录 前言 一、 C语言中的类型转换 二、为什么C需要四种类型转换 三、C中新增的四种强制类型转换操作符以及它们的应用场景 1.static_cast 2.reinterpret_cast 3.const_cast 4.dynamic_cast 前言 在C语言中&#xff0c;如果赋值运算符左右两侧的类型不同&#xff0c;或者…

新书速览|图神经网络基础、模型与应用实战

掌握PyTorch图神经网络基础与模型&#xff0c;实战自然语言处理、计算机视觉、推荐系统、社交网络应用开发 01 本书内容 图神经网络不仅能够解决传统机器学习方法无法解决的图数据问题&#xff0c;而且能够应用于许多实际场景&#xff0c;例如社交网络、药物发现、网络安全、…

Yii2 自动生成php代码

文档地址&#xff1a;入门&#xff08;Getting Started&#xff09;: 用 Gii 生成代码&#xff08;Generating Code with Gii&#xff09; - Yii 2.0 权威指南 - 文档 - Yii Framework 中文网 找到配置文件&#xff0c;以我的项目为例&#xff1a; 因为的是开启了路由美化所以访…

【前端热门框架【vue框架】】——对组件进行更加简洁合理的处理和解释(一)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;程序员-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

YOLOv5独家原创改进: 通用倒瓶颈(UIB)搜索块结合C3二次创新 | 轻量化之王MobileNetV4

💡💡💡创新点:轻量化之王MobileNetV4 开源 | Top-1 精度 87%,手机推理速度 3.8ms,原地起飞! 最主要创新:引入了通用倒瓶颈(UIB)搜索块,这是一个统一且灵活的结构,它融合了倒瓶颈(IB)、ConvNext、前馈网络(FFN)以及一种新颖的额外深度可分(ExtraDW)变体技…

Stable Diffusion WebUI 使用综述

前言 科技圈的风口年年都在变&#xff0c;前几年是区块链&#xff0c;后来是虚拟现实&#xff0c;元宇宙&#xff0c;web3&#xff0c;而现在是 AI&#xff0c;VR 曾经让我兴奋过&#xff0c;可惜它最终没能形成足够大的浪潮&#xff0c;离最终实现可能还很遥远。而 2022 年开…

flutter日期选择器仅选择年、月

引入包&#xff1a;flutter_datetime_picker: 1.5.0 封装 import package:flutter/cupertino.dart; import package:flutter/material.dart; import package:flutter_datetime_picker/flutter_datetime_picker.dart;class ATuiDateTimePicker {static Future<DateTime> …

TSINGSEE青犀视频边缘计算AI智能分析网关V4告警消息语音推送的配置流程

TSINGSEE青犀视频边缘计算硬件智能分析网关V4内置了近40种AI算法模型&#xff0c;支持对接入的视频图像进行人、车、物、行为等实时检测分析&#xff0c;上报识别结果&#xff0c;并能进行语音告警播放。今天我们来分享一下如何配置和使用AI智能分析网关V4的语音推送。 提前准备…

django中的cookie与session

获取cookie request.COOKIE.GET 使用cookie response.set-cookie views.py from django.http import HttpResponse from django.shortcuts import render# Create your views here. def cookie_test(request):r HttpResponse("hello world")r.set_cookie(lan, py…

c语言排序算法之八(桶排序)

前言 以下内容是被验证可以有效理解桶排序&#xff0c;代码也较容易理解。如果你发现还有很多需要增加的&#xff0c;欢迎留言。 为什么要单独写排序算法这一系列&#xff0c;看过一些贴子普遍篇幅较长。看完依旧难以直观理解原理及整个过程。代码永远是基于理解的基础上才能…

【刷题】前缀和进阶

送给大家一句话&#xff1a; 生活坏到一定程度就会好起来&#xff0c;因为它无法更坏。努力过后&#xff0c;才知道许多事情&#xff0c;坚持坚持&#xff0c;就过来了。 – 宫崎骏 《龙猫》 ┌(˘⌣˘)ʃ┌(˘⌣˘)ʃ┌(˘⌣˘)ʃ ┌(˘⌣˘)ʃ┌(˘⌣˘)ʃ┌(˘⌣˘)ʃ ┌(˘…

RS2105XN功能和参数介绍及PDF资料

RS2105XN 品牌: RUNIC(润石) 封装: MSOP-10 开关电路: 单刀双掷(SPDT) 通道数: 2 工作电压: 1.8V~5.5V 导通时间(Tonmax): 50ns RS2105XN是一款模拟开关芯片。以下是RS2105XN的功能和参数介绍&#xff1a; 功能&#xff1a; 2通道单刀双掷&#xff08;SPDT&#xff09;模拟开关…

基于springboot+mybatis+vue的项目实战之(后端+前后端联调)

步骤&#xff1a; 1、项目准备&#xff1a;创建数据库&#xff08;之前已经创建则忽略&#xff09;&#xff0c;以及数据库连接 2、建立项目结构文件夹 3、编写pojo文件 4、编写mapper文件&#xff0c;并测试sql语句是否正确 5、编写service文件 6、编写controller文件 …

【数据库原理及应用】期末复习汇总高校期末真题试卷09

试卷 一、填空题(每空1分&#xff0c;共10分) 数据的完整性是指数据的________、有效性和相容性。数据模型通常由________、数据操作以及数据约束条件等三要素组成。在关系的有关术语中&#xff0c;关系表中的每一行称作________&#xff0c;每一列称作属性。信息的三种世界是…