Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >实战 | PyQt5制作雪球网股票数据爬虫工具

实战 | PyQt5制作雪球网股票数据爬虫工具

作者头像
龙哥
发布于 2020-09-24 09:42:50
发布于 2020-09-24 09:42:50
2.8K100
代码可运行
举报
文章被收录于专栏:Python绿色通道Python绿色通道
运行总次数:0
代码可运行

最近有盆友需要帮忙写个爬虫脚本,爬取雪球网一些上市公司的财务数据。盆友希望可以根据他自己的选择进行自由的抓取,所以简单给一份脚本交给盆友,盆友还需要自己搭建python环境,更需要去熟悉一些参数修改的操作,想来也是太麻烦了。

于是,结合之前做过的汇率计算器小工具,我这边决定使用PyQt5给朋友制作一个爬虫小工具,方便他的操作可视化。

一、效果演示

二、功能说明

  • 可以自由选择证券市场类型:A股、美股和港股
  • 可以自由选择上市公司:单选或全选
  • 可以自由选择财务数据类型:单选或全选(主要指标、利润表、资产负债表、现金流表)
  • 可以导出数据存储为excel表格文件
  • 支持同一家上市公司同类型财务数据追加

三、制作过程

首先引入需要的库

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow,QFileDialog

import os
import requests
from fake_useragent import UserAgent
import json
import  logging
import time
import pandas as pd
from openpyxl import load_workbook

雪球网页拆解

这一步的目的是获取需要爬取的数据的真正URL地址规律。

当我选中某只股票查看财务数据某类型数据报告时,点击下一页,网站地址没有变化,基本可以知道这是动态加载的数据,对于这类数据可以使用F12打开开发者模式。

在开发者模式下,选到Network—>XHR可以查看到真正的数据获取地址URL及请求方式(General里是请求URL和请求方式说明,Request Headers有请求头信息,如cookie,Query String Parameters就是可变参数项,一般来说数据源URL就是由基础URL和这里的可变参数组合而成)

我们分析这段URL,可以发现其基本结构如下:

基于上述结构,我们拆分最终的组合URL地址如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#基础网站
base_url = f'https://stock.xueqiu.com/v5/stock/finance/{ABtype}'

#组合url地址
url = f'{base_url}/{data_type}.json?symbol={ipo_code}&type=all&is_detail=true&count={count_num}&timestamp={start_time}'

操作界面设计

操作界面设计使用的是PyQt5,这里不做更详细的介绍,我们在后续中对PyQt5的使用再专题讲解。

使用QT designer对操作界面进行可视化设计,参考如下:

雪球网数据提取.ui中各个组件的相关设置,参考如下:

.ui文件可以使用pyuic5指令进行编译生成对应的.py文件,或者我们也可以在vscode里直接转译(这里也不做更详细的介绍,具体见后续专题讲解)。

本文没有将操作界面定义文件单独使用,而是将全部代码集中在同一个.py文件,因此其转译后的代码备用即可。

获取cookie及基础参数

获取cookie

为了便于小工具拿来即可使用,我们需要自动获取cookie地址并附加在请求头中,而不是人为打开网页在开发者模式下获取cookie后填入。

自动获取cookie,这里使用到的requests库的session会话对象。

requests库的session会话对象可以跨请求保持某些参数,简单来说,就是比如你使用session成功的登录了某个网站,则在再次使用该session对象请求该网站的其他网页都会默认使用该session之前使用的cookie等参数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import requests
from fake_useragent import UserAgent

url = 'https://xueqiu.com'

session = requests.Session()
headers = {"User-Agent": UserAgent(verify_ssl=False).random}
 
session.get(url, headers=headers)
   
#获取当前的Cookie
Cookie= dict(session.cookies)
基础参数

基础参数是用于财务数据请求时原始网址构成参数选择,我们在可视化操作工具中需要对财务数据类型进行选择,因此这里需要构建财务数据类型字典。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#原始网址
original_url = 'https://xueqiu.com'
#财务数据类型字典
dataType = {'全选':'all',
           '主要指标':'indicator',
           '利润表':'income',
           '资产负债表':'balance',
           '现金流量表':'cash_flow'}

获取获取各证券市场上市名录

因为我们在可视化操作工具上是选定股票代码后抓取相关数据并导出,对导出的文件名称希望是以股票代码+公司名称的形式(SH600000 浦发银行)存储,所以我们需要获取股票代码及名称对应关系的字典表。

这其实就是一个简单的网络爬虫及数据格式调整的过程,实现代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1import requests
 2import pandas as pd
 3import json
 4from fake_useragent import UserAgent 
 5#请求头设置
 6headers = {"User-Agent": UserAgent(verify_ssl=False).random}
 7#股票清单列表地址解析(通过设置参数size为9999可以只使用1个静态地址,全部股票数量不足5000)
 8url = 'https://xueqiu.com/service/v5/stock/screener/quote/list?page=1&size=9999&order=desc&orderby=percent&order_by=percent&market=CN&type=sh_sz'
 9#请求原始数据
10response = requests.get(url,headers = headers)
11#获取股票列表数据
12df = response.text
13#数据格式转化
14data = json.loads(df)
15#获取所需要的股票代码及股票名称数据
16data = data['data']['list']
17#将数据转化为dataframe格式,并进行相关调整
18data = pd.DataFrame(data)
19data = data[['symbol','name']]
20data['name'] = data['symbol']+' '+data['name']
21data.sort_values(by = ['symbol'],inplace=True)
22data = data.set_index(data['symbol'])['name']
23#将股票列表转化为字典,键为股票代码,值为股票代码和股票名称的组合
24ipoCodecn = data.to_dict()

A股股票代码及公司名称字典如下:

获取上市公司财务数据并导出

根据在可视化操作界面选择的 财务报告时间区间、财务报告数据类型、所选证券市场类型以及所输入的股票代码后,需要先根据这些参数组成我们需要进行数据请求的网址,然后进行数据请求。

由于请求后的数据是json格式,因此可以直接进行转化为dataframe类型,然后进行导出。在数据导出的时候,我们需要判断该数据文件是否存在,如果存在则追加,如果不存在则新建。

获取上市公司财务数据

通过选定的参数生成财务数据网址,然后根据是否全选决定后续数据请求的操作,因此可以拆分为获取数据网址和请求详情数据两部分。

获取数据网址

数据网址是根据证券市场类型、财务数据类型、股票代码、单页数量及起始时间戳决定,而这些参数都是通过可视化操作界面进行设置。

证券市场类型 控件 是radioButton,可以通过你 ischecked() 方法判断是否选中,然后用if-else进行参数设定;

财务数据类型 和 股票代码 因为支持 全选,需要先进行全选判定(全选条件下是需要循环获取数据网址,否则是单一获取即可),因此这部分需要再做拆分;

单页数量 考虑到每年有4份财务报告,因此这里默认为年份差*4

时间戳 是 根据起始时间中的 结束时间 计算得出,由于可视化界面输入的 是 整数年份,我们可以通过 mktime() 方法获取时间戳。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1def Get_url(self,name,ipo_code):
 2   #获取开始结束时间戳(开始和结束时间手动输入)
 3   inputstartTime = str(self.start_dateEdit.date().toPyDate().year)
 4   inputendTime = str(self.end_dateEdit.date().toPyDate().year)
 5   endTime = f'{inputendTime}-12-31 00:00:00'
 6   timeArray = time.strptime(endTime, "%Y-%m-%d %H:%M:%S")
 7
 8   #获取指定的数据类型及股票代码
 9   filename = ipo_code
10   data_type =dataType[name]
11   #计算需要采集的数据量(一年以四个算)
12   count_num = (int(inputendTime) - int(inputstartTime) +1) * 4
13   start_time =  f'{int(time.mktime(timeArray))}001'
14
15   #证券市场类型
16   if (self.radioButtonCN.isChecked()):
17       ABtype = 'cn'
18       num = 3
19   elif (self.radioButtonUS.isChecked()):
20       ABtype = 'us'
21       num = 6
22   elif (self.radioButtonHK.isChecked()):
23       ABtype = 'hk'
24       num = 6
25   else:
26       ABtype = 'cn'
27       num = 3
28
29   #基础网站
30   base_url = f'https://stock.xueqiu.com/v5/stock/finance/{ABtype}'
31
32   #组合url地址
33   url = f'{base_url}/{data_type}.json?symbol={ipo_code}&type=all&is_detail=true&count={count_num}&timestamp={start_time}'
34
35   return url,num
请求详情数据

需要根据用户输入决定数据采集方式,代码中主要是根据用户输入做判断然后再进行详情数据请求。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1#根据用户输入决定数据采集方式
 2def Get_data(self):
 3   #name为财务报告数据类型(全选或单个)
 4   name = self.Typelist_comboBox.currentText()
 5   #股票代码(全选或单个)
 6   ipo_code = self.lineEditCode.text()
 7   #判断证券市场类型
 8   if (self.radioButtonCN.isChecked()):
 9       ipoCodex=ipoCodecn
10   elif (self.radioButtonUS.isChecked()):
11       ipoCodex=ipoCodeus
12   elif (self.radioButtonHK.isChecked()):
13       ipoCodex=ipoCodehk
14   else:
15       ipoCodex=ipoCodecn
16#根据财务报告数据类型和股票代码类型决定数据采集的方式
17   if name == '全选' and ipo_code == '全选':
18       for ipo_code in list(ipoCodex.keys()):
19           for name in list(dataType.keys())[1:]:
20               self.re_data(name,ipo_code)
21   elif name == '全选' and ipo_code != '全选':
22           for name in list(dataType.keys())[1:]:
23               self.re_data(name,ipo_code)
24   elif ipo_code == '全选' and name != '全选':
25       for ipo_code in list(ipoCodex.keys()):
26           self.re_data(name,ipo_code)            
27   else:
28       self.re_data(name,ipo_code)
29
30#数据采集,需要调用数据网址(Get.url(name,ipo_code)    
31def re_data(self,name,ipo_code):
32   name = name
33   #获取url和num(url为详情数据网址,num是详情数据中根据不同证券市场类型决定的需要提取的数据起始位置)
34   url,num = self.Get_url(name,ipo_code)
35   #请求头
36   headers = {"User-Agent": UserAgent(verify_ssl=False).random}
37   #请求数据
38   df = requests.get(url,headers = headers,cookies = cookies)
39
40   df = df.text
41try:
42      data = json.loads(df)
43  pd_df = pd.DataFrame(data['data']['list'])
44  to_xlsx(num,pd_df)
45   except KeyError:
46       log = '<font color=\"#FF0000\">该股票此类型报告不存在,请重新选择股票代码或数据类型</font>'
47       self.rizhi_textBrowser.append(log)  
财务数据处理并导出

单纯的数据导出是比较简单的操作,直接to_excel() 即可。但是考虑到同一个上市公司的财务数据类型有四种,我们希望都保存在同一个文件下,且对于同类型的数据可能存在分批导出的情况希望能追加。因此,需要进行特殊的处理,用pd.ExcelWriter()方法操作。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1#数据处理并导出
 2def to_xlsx(self,num,data):
 3   pd_df = data
 4   #获取可视化操作界面输入的导出文件保存文件夹目录
 5   filepath = self.filepath_lineEdit.text()
 6   #获取文件名
 7   filename = ipoCode[ipo_code]  
 8   #组合成文件详情(地址+文件名+文件类型)
 9   path = f'{filepath}\{filename}.xlsx'
10   #获取原始数据列字段
11   cols = pd_df.columns.tolist()
12   #创建空dataframe类型用于存储
13   data = pd.DataFrame()    
14   #创建报告名称字段            
15   data['报告名称'] = pd_df['report_name']
16   #由于不同证券市场类型下各股票财务报告详情页数据从不同的列才是需要的数据,因此需要用num作为起点
17   for i in range(num,len(cols)):
18       col = cols[i]
19       try:
20           #每列数据中是列表形式,第一个是值,第二个是同比
21           data[col] = pd_df[col].apply(lambda x:x[0])
22       # data[f'{col}_同比'] = pd_df[col].apply(lambda x:x[1])
23       except TypeError:
24           pass
25   data = data.set_index('报告名称')      
26   log = f'{filename}的{name}数据已经爬取成功'
27   self.rizhi_textBrowser.append(log)
28   #由于存储的数据行索引为数据指标,所以需要对采集的数据进行转T处理
29   dataT = data.T
30   dataT.rename(index = eval(f'_{name}'),inplace=True)
31   #以下为判断数据报告文件是否存在,若存在则追加,不存在则重新创建
32   try:
33       if os.path.exists(path):
34           #读取文件全部页签
35           df_dic = pd.read_excel(path,None)
36           if name not in list(df_dic.keys()):
37               log = f'{filename}的{name}数据页签不存在,创建新页签'
38               self.rizhi_textBrowser.append(log)
39               #追加新的页签
40               with pd.ExcelWriter(path,mode='a') as writer:
41                   book = load_workbook(path)    
42                   writer.book = book    
43                   dataT.to_excel(writer,sheet_name=name)
44                   writer.save()
45           else:
46               log = f'{filename}的{name}数据页签已存在,合并中'
47               self.rizhi_textBrowser.append(log)
48               df = pd.read_excel(path,sheet_name = name,index_col=0)
49               d_ = list(set(list(dataT.columns)) - set(list(df.columns)))
50#使用merge()进行数据合并
51               dataT = pd.merge(df,dataT[d_],how='outer',left_index=True,right_index=True)
52               dataT.sort_index(axis=1,ascending=False,inplace=True)
53               #页签中追加数据不影响其他页签
54               with pd.ExcelWriter(path,engine='openpyxl') as writer:  
55                   book = load_workbook(path)    
56                   writer.book = book
57                   idx = writer.book.sheetnames.index(name)
58                   #删除同名的,然后重新创建一个同名的
59                   writer.book.remove(writer.book.worksheets[idx])
60                   writer.book.create_sheet(name, idx)
61                   writer.sheets = {ws.title:ws for ws in writer.book.worksheets}        
62
63                   dataT.to_excel(writer,sheet_name=name,startcol=0)
64                   writer.save()
65       else:
66           dataT.to_excel(path,sheet_name=name)
67
68       log = f'<font color=\"#00CD00\">{filename}的{name}数据已经保存成功</font>'
69       self.rizhi_textBrowser.append(log)
70
71   except FileNotFoundError:
72       log = '<font color=\"#FF0000\">未设置存储目录或存储目录不存在,请重新选择文件夹</font>'
73       self.rizhi_textBrowser.append(log)

上面就是制作过程讲解与关键代码,由于源代码内容较多,就不全量展示了,可在后台回复“XQ”可获取完整源代码文件!

-END-

代码语言:javascript
代码运行次数:0
运行
复制
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-09-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python绿色通道 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
10 条评论
热度
最新
XQ
XQ
回复回复1举报
有源码吗?发一下
有源码吗?发一下
回复回复点赞举报
xq
xq
回复回复点赞举报
XQ
XQ
回复回复点赞举报
XQ
XQ
回复回复点赞举报
源码呢
源码呢
回复回复点赞举报
XQ
XQ
回复回复点赞举报
XQ
XQ
回复回复点赞举报
XQ
XQ
回复回复点赞举报
XQ
XQ
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
股票交易数据采集+数据可视化(Python爬取某网站股票数据,附代全部代码)
前言 我国股票投资者数量为15975.24万户, 如此多的股民热衷于炒股,首先抛开炒股技术不说, 那么多股票数据是不是非常难找,找到之后是不是看着密密麻麻的数据是不是头都大了? 今天带大家爬取雪球平台
松鼠爱吃饼干
2021/12/04
4.4K1
股票交易数据采集+数据可视化(Python爬取某网站股票数据,附代全部代码)
AkShare-股票数据-股票列表
作者寄语 新增返回 A 股所有股票代码和股票简称的接口,可以一次返回相应板块的股票列表。 更新接口 "stock_info_sz_name_code" # 深证证券交易所股票代码和简称 "stock_info_sh_name_code" # 上海证券交易所股票代码和简称 "stock_info_a_code_name" # A 股股票代码和简称 股票列表-A股 接口: stock_info_a_code_name 目标地址: 沪深交易所 描述: 获取沪深 A 股股票代码和简称数据 限量: 单次获取所有
数据科学实战
2020/07/23
3.7K0
Python爬取股票信息,并实现可视化数据
前言 截止2019年年底我国股票投资者数量为15975.24万户, 如此多的股民热衷于炒股,首先抛开炒股技术不说, 那么多股票数据是不是非常难找, 找到之后是不是看着密密麻麻的数据是不是头都大了? 今
松鼠爱吃饼干
2020/10/09
1.5K0
Python爬取股票信息,并实现可视化数据
AkShare-股票数据-新股发行和股票增发
目标地址: https://vip.stock.finance.sina.com.cn/corp/go.php/vISSUE_NewStock/stockid/600004.phtml
数据科学实战
2020/05/20
6800
Python爬虫实战:股票分时数据抓取与存储 (1)
在金融数据分析中,股票分时数据是投资者和分析师的重要资源。它能够帮助我们了解股票在交易日内的价格波动情况,从而为交易决策提供依据。然而,获取这些数据往往需要借助专业的金融数据平台,其成本较高。幸运的是,通过Python爬虫技术,我们可以低成本地抓取股票分时数据,并将其存储以便后续分析。本文将详细介绍如何使用Python实现股票分时数据的抓取与存储,同时结合代理服务器确保爬虫的稳定性和安全性。
小白学大数据
2025/02/15
2080
Python爬虫实战:股票分时数据抓取与存储 (1)
AKShare-股票数据-北交所-股票列表
本次更新北京证券交易所的股票列表接口,同时在 stock_info_a_code_name 接口中增加京交所股票的支持。
数据科学实战
2022/01/12
1.1K0
AKShare-股票数据-北交所-股票列表
Python爬虫实战:股票分时数据抓取与存储
在金融数据分析中,股票分时数据是投资者和分析师的重要资源。它能够帮助我们了解股票在交易日内的价格波动情况,从而为交易决策提供依据。然而,获取这些数据往往需要借助专业的金融数据平台,其成本较高。幸运的是,通过Python爬虫技术,我们可以低成本地抓取股票分时数据,并将其存储以便后续分析。本文将详细介绍如何使用Python实现股票分时数据的抓取与存储,同时结合代理服务器确保爬虫的稳定性和安全性。
小白学大数据
2025/02/14
3070
Python3网络爬虫(十四):跟股神巴菲特学习炒股之财务报表入库(MySQL)
版权声明:本文为博主原创文章,未经博主允许不得转载。个人网站:http://cuijiahua.com。 https://blog.csdn.net/c406495762/article/details/77801899
Jack_Cui
2019/05/25
1.2K0
Python3网络爬虫(十四):跟股神巴菲特学习炒股之财务报表入库(MySQL)
python 获取股票数据 tushare使用
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
多凡
2019/11/01
2K0
AkShare-股票数据-机构推荐
目标地址: http://stock.finance.sina.com.cn/stock/go.php/vIR_RatingNewest/index.phtml
数据科学实战
2020/07/23
7680
Python量化学习-提取证券数据
不知道公众号有多少读者买基金或者炒股,分享一下如何用python获取证券信息 1、网易财经 import requests from lxml import etree headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36' } def parse_url(url):
用户9925864
2022/07/27
9740
Python量化学习-提取证券数据
AkShare-股票数据-股票更名
目标地址: http://vip.stock.finance.sina.com.cn/corp/go.php/vCI_CorpInfo/stockid/300378.phtml
数据科学实战
2020/07/23
1.3K0
Tkinter制作股票数据抓取小程序,有点秀!
在前面的文章中,我们一起学习了如何通过 Python 抓取东方财富网的实时股票数据,链接如下
周萝卜
2022/09/28
8230
获取A股行情数据方法[通俗易懂]
做股票量化分析,获取股票行情数据是第一步,结合网上的信息,和我用过的一些东西,做个总结。以后有新信息,逐步完善。
全栈程序员站长
2022/07/25
9.2K0
股票数据API整理
最近在做股票分析系统,数据获取源头成了一大问题,经过仔细的研究发现了很多获取办法,这里整理一下,方便后来者使用。 获取股票数据的源头主要有:数据超市、雅虎、新浪、Google、和讯、搜狐、ChinaStockWebService、东方财富客户端、证券之星、网易财经。 根据最近频繁出现的数据超市,可以无限制获取相关数据,而不再需要使用爬虫等方式获取,这样不仅节省了极大资源,也有利于遍历数据。 列出来相关网站清单,开发者可自行到这些网站查询调用方法。 聚合数据 https://www.juhe.cn/ 百度A
机器学习AI算法工程
2018/03/15
26.1K2
股票数据API整理
Python 数据可视化实战:使用 PyQt5 和 Echarts 打造股票数据看板
数据可视化大致可分为两类,一类是 excel、powerBI 这类不需要写代码的,另一类是需要写代码的;而对于 Python 来说,数据可视化框架,我个人觉得大致可以分为以下两类(推荐程度从高到底)
月小水长
2020/01/15
5.5K0
AkShare-股票数据-次新股
目标地址: http://vip.stock.finance.sina.com.cn/mkt/#new_stock
数据科学实战
2020/09/25
7540
AkShare-股票数据-次新股
用Python轻松制作一个股票K线图网站
在前面的文章中,我们学习了如何使用 Tkinter 构建股票数据抓取以及展示K线图功能,虽然大致的功能已经具备,但是在当今这个人手一个 Web 服务的年代,GUI 程序还是没有 Web 服务来的香啊。
周萝卜
2022/09/28
1.6K0
AkShare-股票数据-龙虎榜-机构席位成交明细
目标地址: http://vip.stock.finance.sina.com.cn/q/go.php/vLHBData/kind/jgzz/index.phtml
数据科学实战
2020/08/07
7170
AKShare-股票数据-个股资金流
本次更新股票数据-个股资金流接口。本接口获取指定市场(三大股票交易所)和股票的近 100 个交易日的资金流数据,本次主要新增对北京证券交易所的支持。
数据科学实战
2023/03/09
9570
AKShare-股票数据-个股资金流
推荐阅读
相关推荐
股票交易数据采集+数据可视化(Python爬取某网站股票数据,附代全部代码)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验