位老总,有时我们想钱想疯了(没办法,上有老,下有小),就去玩股票,虽然大多数当菲菜,让人割了,但还是乐此不疲。
上APP、上软件看各股资料太麻烦?不好找出各股的对比数据?那你可以把各股资料放入数据库,像平常我们玩数据库一样,想查哪个市值多少,哪个地方的,非常方便。
下面程序是我之前写的读取各股票信息,然后存到数据库里,供自己分析,大家可以参考,编写更详细的信息。
主要是读取东方财富网的数据
上证各股资料的URL都是:http://quote.eastmoney.com/sh+股票编号.html
深上证各股资料的URL都是:http://quote.eastmoney.com/sz+股票编号.html
代码如下(几年前的JAVA代码,能运行就得了)
package yjz.nms.cla;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GetStockInfo {
public void getData() throws IOException {
//股票名
String stockname=null ;
//板块
String bankuai=null;
//业务范围
String yewufanwei=null ;
//概念
String gainian=null ;
//发行价
float faxingjia;
//注册资本
float zhuceziben = 0 ;
//市值
float shizhi ;
//市盈率
float shiyinglv = 0 ;
//每股收益
float meigushouyi = 0 ;
//业务收入
float yingyeshouru = 0 ;
//收入同比
float shourutongbi ;
//利润
float liren = 0 ;
//利润同比
float lirentongbi ;
//市净率
float shijinglv ;
Connection con = null;
// 连接数据库
con = connDB(con);
String codeSqe=null;
codeSqe=getCodeSeq(con );
String fileNameN = "e:\allStockCode.ini";
File f = new File(fileNameN);
String data = null;
if (f.exists()) {
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(fileNameN), "UTF-8"));
while((data=br.readLine())!=null && ! data.equals("")){
data=data.substring(data.indexOf("(")+1,data.indexOf(")"));
String urls = null;
if (data.startsWith("60")) {
urls = "http://quote.eastmoney.com/sh"+data+".html";
} else {
urls = "http://quote.eastmoney.com/sz"+data+".html";
}
String htmlContent= getHtmlContent(urls,"gb2312");
stockname = getContent(htmlContent,"<h2 class=\"header-title-h2 fl\" id=\"name\">(.*?)</h2>");
shizhi = Float.parseFloat(getContent(htmlContent,"<span id=\"gt7_2\">(.*?)亿</span>"));
String tmp=getContent(htmlContent,"<span id=\"gt6_2\">(.*?)</span>");
if(tmp.indexOf("-")<0){
shiyinglv = Float.parseFloat(tmp);
}
tmp=getContent(htmlContent,"收益</a>.*(\d+\.\d+?)</td>");
if(tmp.indexOf("-")<0){
meigushouyi = Float.parseFloat(tmp);
}
String yingyeshourus = getContent(htmlContent,"<td>收入:(.*?)</td>");
if(yingyeshourus.indexOf("亿")>0){
yingyeshouru=Float.parseFloat(yingyeshourus.substring(0,yingyeshourus.indexOf("亿")))*10000;
}else{
yingyeshouru=Float.parseFloat(yingyeshourus.substring(0,yingyeshourus.indexOf("万")));
}
shourutongbi = Float.parseFloat(getContent(htmlContent,"同比</a>:(.*?)%</td>"));
String lirens = getContent(htmlContent,"<td>净利润:(.*?)</td>");
if(lirens.indexOf("亿")>0){
liren=Float.parseFloat(lirens.substring(0,lirens.indexOf("亿")))*10000;
}else{
tmp=lirens.substring(0,lirens.indexOf("万"));
liren=Float.parseFloat(tmp);
}
lirentongbi = Float.parseFloat(getContent(htmlContent,"<td>同比:(.*?)%</td>"));
shijinglv = Float.parseFloat(getContent(htmlContent,"<td>市净率:<span id=\"gt13_2\">(.*?)</span></td>"));
if (data.startsWith("60")) {
urls = "http://f10.eastmoney.com/f10_v2/CompanySurvey.aspx?code=sh"+data;
} else {
urls = "http://f10.eastmoney.com/f10_v2/CompanySurvey.aspx?code=sz"+data;
}
htmlContent= getHtmlContent(urls,"utf-8");
yewufanwei = getContent(htmlContent,"<th class=\"tips-fieldnameL\">经营范围</th><td colspan=\"3\" class=\"tips-dataL tips-lineheight\" width=\"782\">(.*?)</td>");
bankuai = getContent(htmlContent,"<th class=\"tips-fieldnameL\">所属行业</th><td class=\"tips-dataL\">(.*?)</td></tr>");
String zhucezibens = getContent(htmlContent,"注册资本\(元\)</th><td class=\"tips-dataL\">(.*?)</td>");
if(zhucezibens.indexOf("亿")>0){
zhuceziben=Float.parseFloat(zhucezibens.substring(0,zhucezibens.indexOf("亿")))*10000;
}else{
zhuceziben=Float.parseFloat(zhucezibens.substring(0,zhucezibens.indexOf("万")));
}
System.out.println(getContent(htmlContent,"每股发行价\(元\)</th><td class=\"tips-dataL\">(.*?)</td>"));
faxingjia= Float.parseFloat(getContent(htmlContent,"每股发行价\(元\)</th><td class=\"tips-dataL\">(.*?)</td>"));
if (data.startsWith("60")) {
urls = "http://f10.eastmoney.com/f10_v2/CoreConception.aspx?code=sh"+data;
} else {
urls = "http://f10.eastmoney.com/f10_v2/CoreConception.aspx?code=sz"+data;
}
htmlContent= getHtmlContent(urls,"utf-8");
gainian= getContent(htmlContent,"<p>要点一:<font>所属板块</font> (.*?)</p>");
/*System.out.println("data:"+data);
System.out.println("stockname:"+stockname);
System.out.println("bankuai:"+bankuai);
System.out.println("yewufanwei:"+yewufanwei);
System.out.println("gainian:"+gainian);;
System.out.println("faxingjia:"+faxingjia);
System.out.println("zhuceziben:"+zhuceziben);
System.out.println("shizhi:"+shizhi);
System.out.println("shiyinglv:"+shiyinglv );
System.out.println("meigushouyi:"+meigushouyi );
System.out.println("yingyeshouru:"+yingyeshouru);
System.out.println("shourutongbi:"+shourutongbi);
System.out.println("liren:"+liren );
System.out.println("lirentongbi:"+lirentongbi);
System.out.println("shijinglv:"+shijinglv);*/
if((codeSqe==null) || (!codeSqe.contains(data))){
try {
String insertsql = "insert into stockINFO(stockcode , stockname, bankuai, yewufanwei,gainian ,faxingjia ,zhuceziben ,shizhi,shiyinglv ,meigushouyi,yingyeshouru ,shourutongbi,liren,lirentongbi,shijinglv)" +
" values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
PreparedStatement pstmt = con.prepareStatement(insertsql);
pstmt.setString(1, data);
pstmt.setString(2, stockname);
pstmt.setString(3, bankuai);
pstmt.setString(4, yewufanwei);
pstmt.setString(5, gainian);
pstmt.setFloat(6, faxingjia);
pstmt.setFloat(7, zhuceziben);
pstmt.setFloat(8, shizhi);
pstmt.setFloat(9,shiyinglv);
pstmt.setFloat(10,meigushouyi );
pstmt.setFloat(11,yingyeshouru);
pstmt.setFloat(12,shourutongbi );
pstmt.setFloat(13,liren);
pstmt.setFloat(14,lirentongbi );
pstmt.setFloat(15,shijinglv );
int result = pstmt.executeUpdate();
if(result==1){
System.out.print("insert "+data+" into database ok");
}
pstmt.close();
} catch (SQLException e) {
System.out.println("SQL error"+data);
e.printStackTrace();
}catch (NumberFormatException e){
System.out.println("数安格式错"+data);
e.printStackTrace();
}
catch (StringIndexOutOfBoundsException e){
System.out.println("索引超出值"+data);
e.printStackTrace();
}
}else{
try {
String updatesql = "update stockINFO set stockname=?, bankuai=?, yewufanwei=?,gainian=? ,faxingjia=? ,zhuceziben=? ,shizhi=?,shiyinglv=? ,meigushouyi=?,yingyeshouru=? ,shourutongbi=?,liren=?,lirentongbi=?,shijinglv=? where stockcode=?" ;
PreparedStatement pstmt = con.prepareStatement(updatesql);
pstmt.setString(1, stockname);
pstmt.setString(2, bankuai);
pstmt.setString(3, yewufanwei);
pstmt.setString(4, gainian);
pstmt.setFloat(5, faxingjia);
pstmt.setFloat(6, zhuceziben);
pstmt.setFloat(7, shizhi);
pstmt.setFloat(8,shiyinglv);
pstmt.setFloat(9,meigushouyi );
pstmt.setFloat(10,yingyeshouru);
pstmt.setFloat(11,shourutongbi );
pstmt.setFloat(12,liren);
pstmt.setFloat(13,lirentongbi );
pstmt.setFloat(14,shijinglv );
pstmt.setString(15, data);
int result = pstmt.executeUpdate();
if(result==1){
System.out.print("update "+data+" into database ok");
}
pstmt.close();
} catch (SQLException e) {
System.out.println("SQL error"+data);
e.printStackTrace();
}catch (NumberFormatException e){
System.out.println("数安格式错"+data);
e.printStackTrace();
}
catch (StringIndexOutOfBoundsException e){
System.out.println("索引超出值"+data);
e.printStackTrace();
}
}
}
br.close();
br=null;
} else {
System.out.println("请在/slview/yjz,里面加上股票代码,用逗号分隔");
}
try {
con.close();
con=null;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private Connection connDB(Connection con) {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
} catch (Exception e) {
System.out.println("Can't load dbdriver!-->"
+ e.getMessage());
}
try {
con = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1639:dbnms",
"abc", "dddd");
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return con;
}
public String getCodeSeq(Connection con ){
PreparedStatement pstmt=null;
ResultSet rs=null;
StringBuffer bs=new StringBuffer();
String sql = "select distinct stockcode from stockINFO" ;
try {
pstmt = con.prepareStatement(sql);
rs=pstmt.executeQuery();
while(rs.next()){
bs.append(rs.getString(1)+",");
}
}catch (SQLException e) {
e.printStackTrace();
}
try {
rs.close();
rs=null;
pstmt.close();
pstmt=null;
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return bs.toString();
}
public String getHtmlContent(String htmlURL,String code) {
URL url = null;
String rowContent = "";
StringBuffer htmlContent = new StringBuffer();
try {
url = new URL(htmlURL);
BufferedReader in = new BufferedReader(new InputStreamReader(url
.openStream(), code));
while ((rowContent = in.readLine()) != null) {
htmlContent.append(rowContent);
}
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return htmlContent.toString();
}
public String getContent(String htmlContent,String regex){
StringBuffer mainContent = new StringBuffer();
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(htmlContent);
if(matcher.find()) {
mainContent.append(matcher.group(1));
}
return mainContent.toString();
}
public static void main(String args[]) throws IOException,
InterruptedException {
GetStockInfo gsi=new GetStockInfo();
gsi.getData();
}
}
这个是只给大家一个参考,建议家里没有矿,还是少玩点。
者:Roman Orac
鱼羊 编译整理
量子位 报道 | 公众号 QbitAI
数据分析,如何能错过 Pandas 。
现在,数据科学家 Roman Orac 分享了他在工作中相见恨晚的 Pandas 使用技巧。
了解了这些技巧,能让你在学习、使用 Pandas 的时候更加高效。
话不多说,一起学习一下~
用 Pandas 做数据分析,最大的亮点当属 DataFrame。不过,在展示成果的时候,常常需要把 DataFrame 转成另一种格式。
Pandas 在这一点上其实十分友好,只需添加一行代码。
DataFrame 转 HTML
如果你需要用 HTML 发送自动报告,那么 to_html 函数了解一下。
比如,我们先设定这样一个 DataFrame:
import numpy as np
import pandas as pd
import random
n = 10
df = pd.DataFrame(
{
"col1": np.random.random_sample(n),
"col2": np.random.random_sample(n),
"col3": [[random.randint(0, 10) for _ in range(random.randint(3, 5))] for _ in range(n)],
}
)
用上 to_html,就可以将表格转入 html 文件:
df_html = df.to_html()
with open(‘analysis.html’, ‘w’) as f: f.write(df_html)
与之配套的,是 read_html 函数,可以将 HTML 转回 DataFrame。
DataFrame 转 LaTeX
如果你还没用过 LaTeX 写论文,强烈建议尝试一下。
要把 DataFrame 值转成 LaTeX 表格,也是一个函数就搞定了:
df.to_latex()
DataFrame 转 Markdown
如果你想把代码放到 GitHub 上,需要写个 README。
这时候,你可能需要把 DataFrame 转成 Markdown 格式。
Pandas 同样为你考虑到了这一点:
print(df.to_markdown())
注:这里还需要 tabulate 库
DataFrame 转 Excel
说到这里,给同学们提一个小问题:导师/老板/客户要你提供 Excel 格式的数据,你该怎么做?
当然是——
df.to_excel(‘analysis.xlsx’)
需要注意的是,如果你没有安装过 xlwt 和 openpyxl 这两个工具包,需要先安装一下。
另外,跟 HTML 一样,这里也有一个配套函数:read_excel,用来将excel数据导入pandas DataFrame。
DataFrame 转字符串
转成字符串,当然也没问题:
df.to_string()
此前,Roman Orac 还曾分享过 5 个他觉得十分好用,但大家可能没有那么熟悉的 Pandas 技巧。
1、data_range
从外部 API 或数据库获取数据时,需要多次指定时间范围。
Pandas 的 data_range 覆盖了这一需求。
import pandas as pd
date_from = “2019-01-01”
date_to = “2019-01-12”
date_range = pd.date_range(date_from, date_to, freq=”D”)
print(date_range)
freq = “D”/“M”/“Y”,该函数就会分别返回按天、月、年递增的日期。
2、合并数据
当你有一个名为left的DataFrame:
和名为right的DataFrame:
想通过关键字“key”把它们整合到一起:
实现的代码是:
df_merge = left.merge(right, on = ‘key’, how = ‘left’, indicator = True)
3、最近合并(Nearest merge)
在处理股票或者加密货币这样的财务数据时,价格会随着实际交易变化。
针对这样的数据,Pandas提供了一个好用的功能,merge_asof。
该功能可以通过最近的key(比如时间戳)合并DataFrame。
举个例子,你有一个存储报价信息的DataFrame。
还有一个存储交易信息的DataFrame。
现在,你需要把两个DataFrame中对应的信息合并起来。
最新报价和交易之间可能有10毫秒的延迟,或者没有报价,在进行合并时,就可以用上 merge_asof。
pd.merge_asof(trades, quotes, on=”timestamp”, by=’ticker’, tolerance=pd.Timedelta(‘10ms’), direction=‘backward’)
4、创建Excel报告
在Pandas中,可以直接用DataFrame创建Excel报告。
import numpy as np
import pandas as pd
df = pd.DataFrame(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), columns=["a", "b", "c"])
report_name = 'example_report.xlsx'
sheet_name = 'Sheet1'
writer = pd.ExcelWriter(report_name, engine='xlsxwriter')
df.to_excel(writer, sheet_name=sheet_name, index=False)
不只是数据,还可以添加图表。
# define the workbook
workbook = writer.book
worksheet = writer.sheets[sheet_name]
# create a chart line object
chart = workbook.add_chart({'type': 'line'})
# configure the series of the chart from the spreadsheet
# using a list of values instead of category/value formulas:
# [sheetname, first_row, first_col, last_row, last_col]
chart.add_series({
'categories': [sheet_name, 1, 0, 3, 0],
'values': [sheet_name, 1, 1, 3, 1],
})
# configure the chart axes
chart.set_x_axis({'name': 'Index', 'position_axis': 'on_tick'})
chart.set_y_axis({'name': 'Value', 'major_gridlines': {'visible': False}})
# place the chart on the worksheet
worksheet.insert_chart('E2', chart)
# output the excel file
writer.save()
注:这里需要 XlsxWriter 库
5、节省磁盘空间
Pandas在保存数据集时,可以对其进行压缩,其后以压缩格式进行读取。
先搞一个 300MB 的 DataFrame,把它存成 csv。
df = pd.DataFrame(pd.np.random.randn(50000,300))
df.to_csv(‘random_data.csv’, index=False)
压缩一下试试:
df.to_csv(‘random_data.gz’, compression=’gzip’, index=False)
文件就变成了136MB。
gzip压缩文件可以直接读取:
df = pd.read_csv(‘random_data.gz’)
这一份Pandas技巧笔记,暂且说到这里。各位同学都做好笔记了吗?
Talk is cheap, show me the code。学会了,就用起来吧
— 完 —
量子位 QbitAI · 头条号签约
关注我们,第一时间获知前沿科技动态
文由ScriptEcho平台提供技术支持
项目地址:传送门
键盘精灵是一款用于股票分析的辅助工具,通过键盘输入股票代码或拼音缩写,快速搜索并展示相关股票信息。它可以帮助交易者快速获取目标股票的实时行情、历史K线数据,并进行便捷的切换。
1. 加载所需库和资源
let jsUrls = [
// 加载JS库和资源
];
let styleUrls = [
// 加载CSS样式
];
await Promise.all(styleUrls.map((styleUrl) => loadStyle(styleUrl)));
await Promise.all(jsUrls.map((jsUrl) => loadJavascript(jsUrl)));
2. 创建键盘精灵组件
function KeyboardChart(divDialog, divInput, div) {
// 初始化键盘精灵组件
}
3. 创建K线图组件
function KLineChart(divKLine) {
// 初始化K线图组件
}
4. 初始化组件并绑定事件
window.$(function () {
// 创建K线图组件
var klineControl = new KLineChart(document.getElementById('kline'));
klineControl.Create();
// 创建键盘精灵组件
var divReport = document.getElementById('div_search_list');
var divDialog = document.getElementById('div_keyboard');
var divInput = document.getElementById('div_input_symbol');
var reportCtrl = new KeyboardChart(divDialog, divInput, divReport);
reportCtrl.Create();
// 绑定键盘精灵组件的股票切换回调函数
reportCtrl.ChangeSymbolCallback = function (sybmol) {
klineControl.ChangeSymbol(sybmol);
klineControl.Chart.SetFocus();
};
});
5. 键盘精灵组件功能实现
this.DivInput.addEventListener('keydown', (event) => {
this.OnKeydown(event);
});
this.DivInput.addEventListener('keyup', (event) => {
this.OnKeyup(event);
});
this.Chart.AddEventCallback({
event: JSCHART_EVENT_ID.ON_KEYBOARD_SELECTED,
callback: (event, data, chart) => {
this.OnSelectedSymbol(event, data, chart);
},
});
this.SendKeyToTDX = function (symbol) {
// 发送股票代码到通达信
};
开发过程中的经验与收获:
未来该卡片功能的拓展与优化:
获取更多Echos
本文由ScriptEcho平台提供技术支持
项目地址:传送门
微信搜索ScriptEcho了解更多
*请认真填写需求信息,我们会在24小时内与您取得联系。