新浪股票 API 数据实时展示

将新浪股票接口的数据直接实时展示在浏览器的标签与页面上。

目前为 2019-03-28 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name 新浪股票 API 数据实时展示
  3. // @namespace https://github.com/yujinpan/tampermonkey-extension
  4. // @version 1.0
  5. // @license MIT
  6. // @description 将新浪股票接口的数据直接实时展示在浏览器的标签与页面上。
  7. // @author yujinpan
  8. // @include http*://hq.sinajs.cn/*
  9. // ==/UserScript==
  10.  
  11. class App {
  12. intervalId = 0;
  13. intervalTime = 3000;
  14. data = {};
  15. tableWrap = null;
  16.  
  17. constructor(code) {
  18. this.code = code;
  19. }
  20.  
  21. // 获取数据
  22. getData() {
  23. return fetch(`/list=${this.code}`)
  24. .then((res) => res.blob())
  25. .then((blob) => {
  26. return new Promise((resolve) => {
  27. const reader = new FileReader();
  28. reader.onload = function() {
  29. resolve(reader.result);
  30. };
  31. reader.readAsText(blob, 'GBK');
  32. });
  33. });
  34. }
  35. // 格式化数据
  36. formatData(resultData) {
  37. try {
  38. const arr = resultData
  39. .match(/".*"/)[0]
  40. .replace(/"/g, '')
  41. .split(',');
  42. const reduce = arr[3] - arr[2];
  43. const percent = ((reduce / arr[2]) * 100).toFixed(2);
  44. this.data = {
  45. reduce,
  46. percent,
  47. date: arr[30],
  48. time: arr[31],
  49. name: arr[0],
  50. start: arr[1],
  51. end: arr[2],
  52. current: arr[3],
  53. max: arr[4],
  54. min: arr[5]
  55. };
  56. } catch (e) {
  57. console.log(e);
  58. }
  59. }
  60. // 设置title
  61. setTitle() {
  62. document.title = `${this.data.name} ${this.data.current} ${
  63. this.data.percent
  64. }%`;
  65. }
  66. // 渲染table
  67. renderTable() {
  68. const params = this.data;
  69. const sign = Math.sign(params.percent);
  70. const color = sign < 0 ? 'green' : sign === 0 ? 'gray' : 'red';
  71.  
  72. // 如果没有容器就创建一个
  73. if (!this.tableWrap) {
  74. this.tableWrap = document.createElement('section');
  75. this.tableWrap.style = `
  76. padding: 0 20px;
  77. margin-right: 20px;
  78. border-right: 1px solid #ddd;
  79. `;
  80. document.body.appendChild(this.tableWrap);
  81. }
  82.  
  83. this.tableWrap.innerHTML = `
  84. <h4>${params.date} ${params.time}</h4>
  85. <h4>${params.name}
  86. <font color="${color}">
  87. ${params.current} ${params.percent}% ${params.reduce.toFixed(3)}
  88. </font>
  89. </h4>
  90. <table border="1">
  91. <thead>
  92. <tr>
  93. <td>今日开盘</td>
  94. <td>昨日收盘</td>
  95. <td>今日最高</td>
  96. <td>今日最低</td>
  97. </tr>
  98. </thead>
  99. </tbody>
  100. <tr>
  101. <td>${params.start}</td>
  102. <td>${params.end}</td>
  103. <td>${params.max}</td>
  104. <td>${params.min}</td>
  105. </tr>
  106. </tbody>
  107. </table>
  108. `;
  109. }
  110. // 创建搜索
  111. renderSearch() {
  112. const searchHistoryElem = this.getSearchHistory()
  113. .map((item) => {
  114. return `<li><a href="/list=${item.code}">${item.name}(${
  115. item.code
  116. })</a></li>`;
  117. })
  118. .join('');
  119. const elem = `
  120. <h5>搜索股票</h5>
  121. <input id="search" autocomplete="false" style="width: 180px;" placeholder="输入股票代码,例如 sh000001" />
  122. <button>搜索</button>
  123. <h5>搜索历史</h5>
  124. <ul>
  125. ${searchHistoryElem}
  126. </ul>
  127. <h5>指数</h5>
  128. <ul>
  129. <li><a href="/list=sh000001">上证指数</a></li>
  130. </ul>
  131. `;
  132. const searchWrap = document.createElement('section');
  133. searchWrap.innerHTML = elem;
  134. const inputElem = searchWrap.querySelector('input');
  135.  
  136. // 点击与回车事件
  137. searchWrap.addEventListener('click', (e) => {
  138. if (e.target.tagName === 'BUTTON' && inputElem.value) {
  139. this.targetTo(inputElem.value);
  140. }
  141. });
  142. searchWrap.addEventListener('keyup', (e) => {
  143. if (e.keyCode === 13 && e.target.tagName === 'INPUT' && inputElem.value) {
  144. this.targetTo(inputElem.value);
  145. }
  146. });
  147. document.body.appendChild(searchWrap);
  148. }
  149. // 跳转
  150. targetTo(code) {
  151. location.href = `/list=${code}`;
  152. }
  153. // 获取搜索历史
  154. getSearchHistory() {
  155. const history = localStorage.getItem('history');
  156. if (history) {
  157. return JSON.parse(history);
  158. } else {
  159. return [];
  160. }
  161. }
  162. // 存储搜索历史
  163. setSearchHistory(code, name) {
  164. const history = this.getSearchHistory();
  165. const index = history.findIndex((item) => item.code === code);
  166. if (index !== -1) {
  167. history.splice(index, 1);
  168. }
  169. history.unshift({ code, name });
  170. localStorage.setItem('history', JSON.stringify(history));
  171. }
  172.  
  173. // 开始
  174. start() {
  175. const handle = () => {
  176. return this.getData().then((res) => {
  177. this.formatData(res);
  178. if (this.data.current) {
  179. this.setTitle();
  180. this.renderTable();
  181. return Promise.resolve(true);
  182. } else {
  183. alert('代码错误!');
  184. return Promise.resolve(false);
  185. }
  186. });
  187. };
  188. this.intervalId = setInterval(() => handle(), this.intervalTime);
  189.  
  190. document.body.innerHTML = '';
  191. document.body.style = `
  192. display: flex;
  193. `;
  194. handle().then((res) => {
  195. this.renderSearch();
  196. debugger;
  197. if (res) {
  198. this.setSearchHistory(
  199. location.pathname.replace('/list=', ''),
  200. this.data.name
  201. );
  202. }
  203. });
  204. }
  205. // 停止
  206. stop() {
  207. clearInterval(this.intervalId);
  208. }
  209. }
  210.  
  211. // 初始化
  212. (function() {
  213. const code = location.pathname.replace('/list=', '');
  214. const app = new App(code || sh000001);
  215. app.start();
  216. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址