11.3.1-使用Pythton抓取股票基金数据

news2024/10/7 8:22:10

文章目录

  • 1. 哪些方式获取股票数据
    • 1.1. yifinance
    • 1.2. JoinQuant聚宽
    • 1.3. tushare
    • 1.4. 自己动手,丰衣足食
  • 2. 使用python抓取数据
    • 2.1. 查看请求报文
    • 2.2. 解析返回报文
    • 2.3. 数据存储
    • 2.4. 开始python代码编写
      • 2.4.1. 构造时间区间
      • 2.4.2. requests调用
      • 2.4.3. 数据存储
    • 2.5. 完整的代码:

“知识就是力量”这句格言实际上是错误的。正确的表述应该是:“知识运用起来才是力量。”

本文摘要:

  1. 都有哪些方法可以获得股票数据?

  2. 省钱、相对不省力、定向性强:python抓取数据

1. 哪些方式获取股票数据

1.1. yifinance

发现yfinance和DataReader有相同的问题,就是要挂上V*N才可以连接到服务器。----放弃。

1.2. JoinQuant聚宽

这个之前没有使用,看官网:JQData使用说明 - JoinQuant

有试用和正式账号的区别,试一下注册账号试用能不能满足要求。官网这么描述试用:

聚宽JQData一直致力于提供专业的数据服务,【目前基础数据试用全面开放,流量升级为每天100万条】

试用账号历史范围:前15个月~前3个月 ; 正式账号历史范围:不限制

历史数据范围:试用账号:距今15个月前 至 距今最近3个月 (即不包含最近3个月,且可调取的历史范围最长为1年);正式账号不限制。

看起来,试用账号可能不能获取到最近3个月的数据。试一下再说。

刚入坑就被劝退了啊兄弟们!python api登录不上。(有成功的,可以告知一下查询日线数据,近3个月是否能拿到。ps:在很多官网介绍上都看到了”试用账号历史范围:前15个月~前3个月 “,估计就是量凉了,如果不想花钱,还是换渠道吧。)

有点侥幸心理,看看聚宽的会员费用:(我错了,我是穷鬼!)

1.3. tushare

tushare官网:Tushare数据

概览:

优点:

  1. 针对性比较强,主要是股市、经济相关数据。

  2. 使用比较简单,有python相关demo、保存数据demo等简单上手的内容

  3. 有在线的api调试页面,可以直接调试接口,拿到返回数据。(前提是你的积分是够的。)

  4. 覆盖股票、股市、基金,以及宏观经济数据,比如CPI

缺点:

  1. 收费:比如想看的510300沪深300ETF,需要2000积分(平台上积分是1年有效期)
  2. 其他真没了,感觉很好用啊~~

1.4. 自己动手,丰衣足食

就是自己用代码撸,下面搞一个。经过测试,代码撸1个基金日线数据出来,只需要100行代码(包含注释)。

2. 使用python抓取数据

先定一个范围:

  1. 单次抓取某一只股票的历史数据。(截止到上个交易日)

  2. 输入:开始日期,股票代码。

  3. 输出:csv文件,包含:日期、成交量、开盘价、收盘价、最高价、最低价

2.1. 查看请求报文

从下面的图,可以分析得出下面的结论:

  1. 发起的是get请求,参数都是拼接在url上的。

  2. 携带了cookie(这个可能是浏览器的行为,不过为了保证成功率,我们也带cookie)

  3. 要分析请求的参数:

symbol: SH510300 ---- 名称
begin: 1693895713149 ---- 是时间戳,13位,百度找一个unix时间戳转换工具即可。比如 时间戳(Unix timestamp)转换工具 - 在线工具 (tool.lu)
period: day ---- 日线数据
type: before ---- 查询此日之前的数据
count: -284 ---- 会返回”begin“日期之前的284天的数据
indicator: kline,pe,pb,ps,pcf,market_capital,agt,ggt,balance ---- 返回这些列,解析主要还是根据返回的数据来做。

2.2. 解析返回报文

返回报文截图如下,简单分析可得如下结论:

第一行数据 1657209600000 —> 2022-07-08

第二行数据 1657468800000 —> 2022-07-11

最后一行数据 1693756800000 —> 2023-09-04(竟然包含了当天的数据,要注意取的时间,如果没收盘,是会变动的。)

然后其他蓝色的数据,我们主要关注收盘价、当日最高价、当日最低价,基本就能满足简单的分析需求了。

2.3. 数据存储

数据存储,我们可以先解析返回,将返回的数据按照固定格式放于内存变量中,最后全部获取到数据之后,通过pandas的df.to_csv函数,写入到csv文件中。

2.4. 开始python代码编写

针对请求,需要做如下的准备工作:

  1. 选定一个python get请求的库,python库很丰富,我选了requests

  2. 请求报文头 ”begin: 1693895713149 ---- 是时间戳“ 参数构造。

    这里引申出一个点:需要构造每个时间区间的点,比如我们以38天为一个时间段,那需要构造begin列表:[‘2012-05-28’, ‘2012-07-05’, ‘2012-08-12’, ‘2012-09-19’…‘2023-07-16’, ‘2023-08-23’]

    另外一个,要把 2012-05-28 这样的时间格式,转换成unix时间戳。

  3. 请求报文头 ”count: -284 ---- 会返回begin日期之前的284天的数据”,我们可以自己选定每次响应返回的时间区间数量。为了和上面begin例子配合,这里就传38。

  4. 请求报文头 “indicator”,是返回哪些指标,我们就默认即可。

分析完毕,开始动工。

一步一步分解:

2.4.1. 构造时间区间

这是一门讲究,这种库也很多,我选用了pandas的date_range函数:

pd.date_range(start=start, end=end, freq=freq)

pd.date_range(start=‘2012-05-08’, end=‘2023-09-01’, freq=‘38D’)

返回的是Timestamp类型列表,形如:[‘2012-05-28’, ‘2012-07-05’, ‘2012-08-12’, ‘2012-09-19’…‘2023-07-16’, ‘2023-08-23’]

而接口入参需要的unix时间戳字符串,进行转换即可:date_unix_time = str(int(time.mktime(item.timetuple()) * 1000))

def date_range(start, end, freq):
    """
    构造时间区间,使用pandas函数
    :param start: '2012-05-08'
    :param end: '2023-09-01'
    :param freq: '38D'
    :return: ['2012-05-28', '2012-07-05', '2012-08-12', '2012-09-19'....'2023-07-16', '2023-08-23']
    """
    # date_range = pd.date_range(start='2022-01-01', end='2022-06-17', freq='38D')
    date_range = pd.date_range(start=start, end=end, freq=freq)
    return date_range

2.4.2. requests调用

最重要的是使用requests的get方法:

requests.get(url=url, params=data, cookies=cookies_dir, headers=headers)

这里有一些讲究:

  1. 伪造user-agent

  2. 为了携带cookie方便,我们最好提供一个cookie字符串参数,由代码,将其转换成requests库需要的字典格式

上述实现的代码如下:

def do_request(self, begin_unix_time_str):
    data = {
        "symbol": self.symbol,
        "begin": begin_unix_time_str,
        "period": "day",
        "type": "before",
        "count": "38",
        "indicator": "kline,pe,pb,ps,pcf,market_capital,agt,ggt,balance"
    }
    # 头部,伪装自己为浏览器
    headers = {
        'user-agent': 'Mozill..................04.1',
      }
    # cookie字符串,可以省去自己拼接k-v形式
    cookies_str = 'device_id=4b698.....................95430'
    cookies_dir = {cookie.split('=')[0]:cookie.split('=')[-1] for cookie in cookies_str.split('; ')}
    # 调用请求
    index_result = requests.get('https://stock.xueqiu.com/v5/stock/chart/kline.json',
                                params=data,
                                cookies=cookies_dir,
                                headers=headers)
    # 打印结果
    print('获取到结果\n' + index_result.text)
    return index_result.text

2.4.3. 数据存储

这里涉及到2种存储,1是临时写到内存变量进行保存、2是各个时间数据都全部获取完毕后,将结果写入到csv文件中。

def result_save(self, result_text):
    # 请求结果字符串转换为json对象
    result_json = json.loads(result_text)
    last_record = {}
    for item in result_json['data']['item']:
        record = {}
        # 日期格式化
        date = time.strftime("%Y-%m-%d", time.localtime(item[0]/1000))
        # 自行构造一个uuid,是为了判断此日期的数据有没有存在,存在就不必再保存了,不存在的才保存下来
        record['uuid'] = result_json['data']['symbol'] + '|' + date
        record['date'] = date
        record['volume'] = item[1]
        record['open'] = item[2]
        record['high'] = item[3]
        record['low'] = item[4]
        record['close'] = item[5]
        record['chg'] = item[6]
        record['percent'] = item[7]
        record['turnoverrate'] = item[8]
        record['amount'] = item[9]
        print(record)
        if record['uuid'] in self.fetch_days:
            print('已有当日数据')
        else:
            # self.fetch_days是类实例变量
            self.fetch_days[record['uuid']] = record['uuid']
            self.data_of_days.append(record)
        last_record = record
    return last_record

将数据存储到csv

# 数据存储到csv
df = pd.DataFrame(this_class.data_of_days)
# 默认自然序号的index会保存到csv文件
df.to_csv("{}-{}-{}.csv".format(security, start_date, end_date))

2.5. 完整的代码:

为了防止被封,要自行替换一下某球的 user-agent 和 cookies

import json
import time
import requests as requests
import pandas as pd


def date_range(start, end, freq):
    """
    构造时间区间,使用pandas函数
    :param start: '2012-05-08'
    :param end: '2023-09-01'
    :param freq: '38D'
    :return: ['2012-05-28', '2012-07-05', '2012-08-12', '2012-09-19'....'2023-07-16', '2023-08-23']
    """
    # date_range = pd.date_range(start='2022-01-01', end='2022-06-17', freq='38D')
    date_range = pd.date_range(start=start, end=end, freq=freq)
    return date_range


class SecurityHistory:
    """
    cookies_str 是要注意可能会过期,如果过期了,就重新通过浏览器手机模拟器获取一下。
    """
    def __init__(self, symbol) -> None:
        super().__init__()
        self.symbol = symbol
        self.fetch_days = {}
        self.data_of_days = []

    def do_request(self, begin_unix_time_str):
        data = {
            "symbol": self.symbol,
            "begin": begin_unix_time_str,
            "period": "day",
            "type": "before",
            "count": "38",
            "indicator": "kline,pe,pb,ps,pcf,market_capital,agt,ggt,balance"
        }
        # 头部,伪装自己为浏览器
        headers = {
            'user-agent': 'Mozilla/5.0 (iP.........这里要自行替换................./604.1',
          }
        # cookie字符串,可以省去自己拼接k-v形式
        cookies_str = 'device_id=4b..........................6987895430'
        cookies_dir = {cookie.split('=')[0]:cookie.split('=')[-1] for cookie in cookies_str.split('; ')}
        # 调用请求
        index_result = requests.get('https://stock.xueqiu.com/v5/stock/chart/kline.json',
                                    params=data,
                                    cookies=cookies_dir,
                                    headers=headers)
        # 打印结果
        print('获取到结果\n' + index_result.text)
        return index_result.text

    def result_save(self, result_text):
        # 请求结果字符串转换为json对象
        result_json = json.loads(result_text)
        last_record = {}
        for item in result_json['data']['item']:
            record = {}
            # 日期格式化
            date = time.strftime("%Y-%m-%d", time.localtime(item[0]/1000))
            # 自行构造一个uuid,是为了判断此日期的数据有没有存在,存在就不必再保存了,不存在的才保存下来
            record['uuid'] = result_json['data']['symbol'] + '|' + date
            record['date'] = date
            record['volume'] = item[1]
            record['open'] = item[2]
            record['high'] = item[3]
            record['low'] = item[4]
            record['close'] = item[5]
            record['chg'] = item[6]
            record['percent'] = item[7]
            record['turnoverrate'] = item[8]
            record['amount'] = item[9]
            print(record)
            if record['uuid'] in self.fetch_days:
                print('已有当日数据')
            else:
                # self.fetch_days记录获取过数据的日期、data_of_days记录日线数据。
                self.fetch_days[record['uuid']] = record['uuid']
                self.data_of_days.append(record)
            last_record = record
        return last_record


if __name__ == '__main__':
    security = 'SH510300'
    start_date = '2012-05-28'
    end_date = time.strftime("%Y-%m-%d", time.localtime())
    # 构造请求时间区间
    datetime_range = date_range(start=start_date, end=end_date, freq='38D')
    this_class = SecurityHistory(security)
    for item in datetime_range:
        date_unix_time = str(int(time.mktime(item.timetuple()) * 1000))  # item是Timestamp类型 2012-05-28 00:00:00
        # 调用请求接口获取数据
        result_text = this_class.do_request(date_unix_time)  # date_unix_time='1338134400000'
        # 保存每日数据,这里存放在内存,并去重
        this_class.result_save(result_text)
        # 休眠,防止请求过于频繁被封
        time.sleep(3)
    # 数据存储到csv
    df = pd.DataFrame(this_class.data_of_days)
    # 默认自然序号的index会保存到csv文件
    df.to_csv("{}-{}-{}.csv".format(security, start_date, end_date))

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

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

相关文章

让API开发更高效——Apipost

作为一款专为API开发设计的工具,Apipost凭借其强大的功能和高效的特点,正逐渐受到越来越多开发者的欢迎。本文将向您详细介绍Apipost的独特优势以及如何让您的API开发更加高效。 Apipost适用于所有与API开发相关的从业者,包括但不限于前端工…

Nor flash 页写地址与数据大小的限制

厂商提供的flash手册如下 如果页写指令的地址不是256的整数倍,并且写入的数据量超过了当前地址所在页的边界,则超过的那些数据会重新写入当前页的首地址(即256的整数倍地址),所以,在进行页写的时候&#x…

Unity Shader着色器知识

学习3D开发技术的时候无可避免的要接触到Shader,那么Shader是个什么概念呢?其实对于开发同事来说还是比较难理解的,一般来说Shader是服务于图形渲染的一类技术,开发人员可以通过其shader语言来自定义显卡渲染页面的算法&#xff0…

Django学习

1、启动项目 python manage.py runserversettings.py

微信小程序新建页面文件

1、在app.json->pages中新增页面的存放路径 list文件夹之前是直接右键加上去,后面删掉了,利用上述操作新增,只出现了两个文件。暂时还不清楚需要怎样才能正式生成4个文件

【STM32】锁存器

问题背景 在学习FSMC控制外部NOR存储器时,看到在NOR复用接口模式下,AD信号[15:0]是复用的。也就是说,若不使用锁存器:当NADV为低时,ADx(x0…15)上出现地址信号Ax,当NADV变高时,ADx上出现数据信号Dx。若使用…

基于深度学习网络的火灾检测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ................................................................................ load F…

【广州华锐互动】智慧园区3D数据可视化系统有什么作用?

随着科技的不断发展,智慧园区3D数据可视化系统已经成为了现代园区管理的重要组成部分。它通过将大量的数据进行整合、分析和展示,为企业提供了一个直观、高效的数据管理平台,帮助企业实现精细化管理,提高运营效率,降低…

网页文字复制

方法一:页面源码方式 比如:ctypes使用指南 - 百度文库 1.按F12 2. 3.选中要复制的文字 4.在源码中复制即可 方法二:打印预览 1.按 CTRLP 方法三:禁用JS脚本 1.按F12 2. 3. 4.选中要复制的文本进行复制(选中方法:鼠标点…

嵌入式基础-电路

目录 1、电流 1.1电流方向 1.2交流电和直流电 2、电压 3、电阻 4、欧姆定律 1、电流 电流是指单位时间内通过导体的电荷量,用符号I表示,单位是安培(A)。电流是电磁学中的基本量纲之一,是七个基本量纲之一。电流的…

AlphaControls sDBRadioGroup 为数据库操作添加活力

日常我们对数据库表的设计,都是按用途进行设置,按需盆字段,常常会因为字段太多,引起读取数据操作,同时,有时也会超过表的字段限制。 一、数据库多项选择的烦劳 例如对评估师表的设计,通常一个项…

20.(地图工具篇)QGIS修改shape字符集UTF-8编码

1:加载shape数据 拉进QGIS编辑区即可。 2:修改字符集 2.1右击Layers中的ground图层,选择properties 2.1修改data source encoding为UTF-8 3:导出新shape文件 3.1 导出入口 3.2 导出文件配置

测试需求分析

什么是软件测试需求: 灰度测试:先发布部分功能,然后看用户的反馈,再去发布另外一部分的更新 A/B测试:先发布的功能先让A部分的用户进行更新,再根据用户的犯困再更新B用户的功能 需求测试: 功…

机器学习笔记 - 使用具有triplet loss的孪生网络进行图像相似度估计

一、简述 孪生网络是一种网络架构,包含两个或多个相同的子网络,用于为每个输入生成特征向量并进行比较。 孪生网络可以应用于不同的场景,例如检测重复项、发现异常和人脸识别。 此示例使用具有三个相同子网的孪生网络。我们将向模型提供三张图像,其中两张是相似的(锚点和正…

风土是如何影响葡萄酒的?

风土的概念已经伴随我们几个世纪了,它有助于我们理解葡萄酒的生长条件和影响它的质量的因素有哪些。虽然这个术语在葡萄酒中已经存在了1000多年,但在葡萄酒爱好者中仍然被误解,接下来让我们来解释一下有关风土的文化与知识吧。 来自云仓酒庄雷…

Win10远程桌面连接黑屏

使用远程桌面连接报下面这个错误时候 按键盘WinR打开运行,输入命令gpedit.msc打开本地组策略编辑器 设置远程会话环境 查找本地计算机 >> 计算机配置 >> 管理模版 >> Windows组件 >> 远程桌面服务 >> 远程桌面会话主机 >> 远…

Redis 7 第六讲 主从模式(replica)架构篇

🌹🌹🌹 此篇开始进入架构篇范围(❤艸`❤) 理论 即主从复制,master以写为主,Slave以读为主。当master数据变化的时候,自动将新的数据异步同步到其它slave数据库。 使用场景 读写分离 容灾备份数据备份水平扩容主从架构 演示案例 注:masterauth、replicaof主…

无涯教程-JavaScript - SECOND函数

描述 SECOND函数返回时间值的秒数。第二个数字以0(零)到59之间的整数形式给出。 语法 SECOND (serial_number)争论 Argument描述Required/OptionalSerial_number 您想找到包含秒数的时间。 时间可以输入为- 引号内的文本字符串(如" 6:45 PM") 十进制数(如0.7812…

DAY01_瑞吉外卖——软件开发整体介绍瑞吉外卖项目介绍开发环境搭建后台系统登录功能后台系统退出功能

目录 1. 软件开发整体介绍1.1 软件开发流程1.2 角色分工1.3 软件环境 2. 瑞吉外卖项目介绍2.1 项目介绍2.2 产品原型2.3 技术选型2.4 功能架构2.5 角色 3. 开发环境搭建3.1 数据库环境搭建3.1.1 创建数据库3.1.2 数据库表导入3.1.3 数据库表介绍 3.2 Maven项目搭建3.2.1 创建ma…

vue element ui postman模拟数据 登陆页面 (1)

效果展示 介绍一个大概 就是一个基础的登录页面 我自己模拟的数据 不会可以参考我下边的 教程 跨域问题Access to XMLHttpRequest at ‘https:/ost?nam‘ from originNo ‘Access-Control-Allow-Origin‘ header_阿金要当大魔王~~的博客-CSDN博客https://blog.csdn.net/…