Skip to content

Commit

Permalink
fix: 雪球搜索股票bug
Browse files Browse the repository at this point in the history
close #454
  • Loading branch information
giscafer committed Sep 15, 2024
1 parent df5efd2 commit fc32583
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 76 deletions.
16 changes: 16 additions & 0 deletions demo/xueqiu.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const Axios = require('axios');
Axios.get(`http://xueqiu.com/`, {headers: {
'User-Agent':
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/3.0 Safari/536.11',
}},).then((response) => {
const cookiesHeader = response.headers['set-cookie'];
console.log("🚀 ~ Axios.get ~ response:", response)
this.cookies +=
cookiesHeader
.map((h) => {
let content = h.split(';')[0];
return content.endsWith('=') ? '' : content;
})
.filter((h) => h !== '')
.join(';') + ';';
});
36 changes: 6 additions & 30 deletions src/explorer/newsService.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,10 @@
import Axios from 'axios';
import { TreeItem, Uri } from 'vscode';
import { randHeader } from '../shared/utils';
import { defaultXueQiuHeaders, getXueQiuToken } from '../shared/xueqiu-helper';

const defaultHeaders = {
Accept:
'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'en-US,en;q=0.9',
'Cache-Control': 'max-age=0',
Connection: 'keep-alive',
Host: 'xueqiu.com', // 股票的话这里写 stock.xueqiu.com
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'none',
'Sec-Fetch-User': '?1',
'Upgrade-Insecure-Requests': 1,
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36};',
};

export class NewsTreeItem extends TreeItem {}
export class NewsTreeItem extends TreeItem { }

export class NewsService {
private cookies = `device_id=${Math.random().toString(36).substring(2, 15)}`;
Expand All @@ -29,24 +14,15 @@ export class NewsService {

get headers() {
return {
...defaultHeaders,
...defaultXueQiuHeaders,
...randHeader(),
Cookie: this.cookies,
};
}

init() {
Axios.get(`https://xueqiu.com/`).then((response) => {
const cookiesHeader = response.headers['set-cookie'];
this.cookies +=
cookiesHeader
.map((h: string) => {
let content = h.split(';')[0];
return content.endsWith('=') ? '' : content;
})
.filter((h: string) => h !== '')
.join(';') + ';';
});
async init() {
const c = await getXueQiuToken();
this.cookies = c;
}

async getNewsUserList(userIds: string[]): Promise<NewsTreeItem[]> {
Expand Down
6 changes: 3 additions & 3 deletions src/explorer/stockProvider.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Event, EventEmitter, TreeDataProvider, TreeItem, TreeItemCollapsibleState } from 'vscode';
import { compact, flattenDeep, uniq } from 'lodash';
// import { compact, flattenDeep, uniq } from 'lodash';
import globalState from '../globalState';
import { LeekTreeItem } from '../shared/leekTreeItem';
import { defaultFundInfo, SortType, StockCategory } from '../shared/typed';
Expand Down Expand Up @@ -37,8 +37,8 @@ export class StockProvider implements TreeDataProvider<LeekTreeItem> {
if (!element) {
// Root view
const stockCodes = LeekFundConfig.getConfig('leek-fund.stocks') || [];
const stockList: string[] = uniq(compact(flattenDeep(stockCodes)));
return this.service.getData(stockList, this.order).then(() => {
// const stockList: string[] = uniq(compact(flattenDeep(stockCodes)));
return this.service.getData(stockCodes, this.order).then(() => {
return this.getRootNodes();
});
} else {
Expand Down
36 changes: 17 additions & 19 deletions src/explorer/stockService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { decode } from 'iconv-lite';
import { ExtensionContext, QuickPickItem, window } from 'vscode';
import globalState from '../globalState';
import { LeekTreeItem } from '../shared/leekTreeItem';
import { HeldData } from '../shared/typed';
import { executeStocksRemind } from '../shared/remindNotification';
import { HeldData } from '../shared/typed';
import { calcFixedPriceNumber, events, formatNumber, randHeader, sortData } from '../shared/utils';
import { getXueQiuToken } from '../shared/xueqiu-helper';
import { LeekService } from './leekService';
import moment = require('moment');
import Log from '../shared/log';

export default class StockService extends LeekService {
public stockList: Array<LeekTreeItem> = [];
Expand All @@ -28,21 +30,16 @@ export default class StockService extends LeekService {
const maps = s.split(',');
return this.stockList.filter((item) => !maps.includes(item.info.code));
}

async getToken(): Promise<string> {
if (this.token !== '') return this.token;

const res = await Axios.get('https://xueqiu.com/');
const cookies: string[] = res.headers['set-cookie'];

const param: string = cookies.filter((key) => key.includes('xq_a_token'))[0] || '';
this.token = param.split(';')[0] || '';
console.log("🚀 ~ StockService ~ getToken ~ this.token:", this.token);

const res = await getXueQiuToken();
this.token = res;
return this.token;
}

async getData(codes: Array<string>, order: number): Promise<Array<LeekTreeItem>> {
// console.log('fetching stock data…');
// Log.info('fetching stock data…');
if ((codes && codes.length === 0) || !codes) {
return [];
}
Expand Down Expand Up @@ -421,9 +418,7 @@ export default class StockService extends LeekService {
headers: {
...randHeader(),
Referer: 'https://stock.xueqiu.com/',
// 雪球token规则变化,临时解决
// Cookie: await this.getToken(),
"cookie": "acw_tc=2760826017254576052523235e0b5e24ba6432d19252e786e33ed3e0ee2db8; acw_sc__v2=66d864c5c68f742d150271b6da3a371072df5bc6; xq_a_token=49c5e355d2fc1b871fde601c659cf9ae1457a889; xqat=49c5e355d2fc1b871fde601c659cf9ae1457a889; xq_r_token=250d5a132310b89c6cf1193e084989736506a297; xq_id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOi0xLCJpc3MiOiJ1YyIsImV4cCI6MTcyNzkxNjc3OCwiY3RtIjoxNzI1NDU3NTg4MjU3LCJjaWQiOiJkOWQwbjRBWnVwIn0.ggqWWe7vvq1GcgRDS6e6abMOSiu6EqfW84QXQjeYQrLuja8zFA-KGrQBlcH6vV74bL6_NR1qROWqKp5fF7acOYagqLEUIXH4xG9M_Pf_EvscNzcp9IitW-0a5CEivezAIoms_ajKpEOp-toXQq7aOG4KfNw6Paktzr4nlrBXtmuXb9V0eaIFXnQAhjVK2_2-X351YGYfUesT0io22BYJUus037if8O_H3GmSF9xWTFcBWZ3seQl2wG_w1fwVhzP1SzcjiIzEEIU8QXttFMMUmUkG8SWsFV18JFKYEu618ZTItxE6-ijxL5Dk0oKt8MV58uz9chQ4o4vlukd_-UguTA; cookiesu=411725457605875; u=411725457605875; Hm_lvt_1db88642e346389874251b5a1eded6e3=1725457610; HMACCOUNT=2546BEF12550F4D4; device_id=a0814ba472ea428d8488ca48833b7db8; smidV2=2024090421465125ea22186efc27f3de9c33bd7df8002b00f1792dfda7b5c90; is_overseas=0; Hm_lpvt_1db88642e346389874251b5a1eded6e3=1725457619; .thumbcache_f24b8bbe5a5934237bbc0eda20c1b6e7=gyo2b8VGfAxa5SfTipuQx8ezwddhs93f7FW74dnOzyirEbx849B+Ff3Z7VnhDgFgOEPO8rw+tAuePz+dXrbBXQ%3D%3D; ssxmod_itna=eqRxyDciDQG=Dtmx0dGQDHFySC7fYDnG7nD8eK9cx0yDReGzDAxn40iDt=a5/j7OxAPYi0424Dun2Dh3UKWOhLINTInBw5jDbxiTD4q07Db4GkDAqiOD7kRwoD435GwD0eG+DD4DWtXI=D7rXgUkNXWq=07TNDmb=uDGQcDiU3xi5Z/L=/8eGWnqGfDDoDYbNSAeQDGkKDbTQDITXKb8hxqcj7Ha=2CPDuCa6YcqDLfQFHxB=ulmPSWFODtw=cnnQ2UAX=OuTd4hp3WxA3GuAxb8GY4rEKWhZxf6AifG+3fB3ST3e4Gw+UI04DDWDEd4D===; ssxmod_itna2=eqRxyDciDQG=Dtmx0dGQDHFySC7fYDnG7nD8eK9xn9S4DsLDwxqjKG7d4D==",
Cookie: await this.getToken()
},
});
const { data, error_code, error_description } = resp.data;
Expand Down Expand Up @@ -523,7 +518,7 @@ export default class StockService extends LeekService {
searchText
)}`;
try {
console.log('getFutureSuggestList: getting...');
Log.info('getFutureSuggestList: getting...');
const futureResponse = await Axios.get(futureUrl, {
responseType: 'arraybuffer',
transformResponse: [
Expand All @@ -539,7 +534,7 @@ export default class StockService extends LeekService {
return result;
}
const tempArr = text.split(';');
console.log(tempArr);
Log.info(tempArr);

tempArr.forEach((item: string) => {
const arr = item.split(',');
Expand Down Expand Up @@ -576,7 +571,7 @@ export default class StockService extends LeekService {
});
return result;
} catch (err) {
console.log(futureUrl);
Log.info(futureUrl);
console.error(err);
return [{ label: '期货查询失败,请重试' }];
}
Expand All @@ -586,7 +581,7 @@ export default class StockService extends LeekService {
searchText
)}`;
try {
console.log('getStockSuggestList: getting...');
Log.info('getStockSuggestList: getting...');
const stockResponse = await Axios.get(stockUrl, {
responseType: 'text',
transformResponse: [
Expand All @@ -600,8 +595,11 @@ export default class StockService extends LeekService {
Referer: 'https://stock.xueqiu.com/',
Cookie: await this.getToken(),
},
}).catch(() => {
this.token = '';
return { data: {} };
});
const stocks = stockResponse.data.stocks || [];
const stocks = stockResponse.data?.stocks || [];
stocks.forEach((item: any) => {
const { code, name } = item;
if (code.startsWith('SH') || code.startsWith('SZ') || code.startsWith('BJ')) {
Expand All @@ -627,7 +625,7 @@ export default class StockService extends LeekService {
});
return result;
} catch (err) {
console.log(stockUrl);
Log.info(stockUrl);
console.error(err);
return [{ label: '股票查询失败,请重试' }];
}
Expand Down
27 changes: 16 additions & 11 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
* Github: https://github.com/giscafer
*-------------------------------------------------------------*/

import { compare } from 'compare-versions';
import { compact, flattenDeep, uniq } from 'lodash';
import { ConfigurationChangeEvent, ExtensionContext, extensions, TreeView, window, workspace } from 'vscode';
import { ConfigurationChangeEvent, ExtensionContext, TreeView, window, workspace } from 'vscode';
import { BinanceProvider } from './explorer/binanceProvider';
import BinanceService from './explorer/binanceService';
import { ForexProvider } from './explorer/forexProvider';
Expand All @@ -22,6 +20,7 @@ import FlashNewsOutputServer from './output/flash-news/FlashNewsOutputServer';
import { registerCommandPaletteEvent, registerViewEvent } from './registerCommand';
import { HolidayHelper } from './shared/holidayHelper';
import { LeekFundConfig } from './shared/leekConfig';
import Log from './shared/log';
import { Telemetry } from './shared/telemetry';
import { SortType } from './shared/typed';
import { events, formatDate, isStockTime } from './shared/utils';
Expand Down Expand Up @@ -134,7 +133,7 @@ export function activate(context: ExtensionContext) {
manualRequest();
}
} else {
console.log('StockMarket Closed! Polling closed!');
Log.info('StockMarket Closed! Polling closed!');
// 闭市时增加轮询间隔时长
if (intervalTime === intervalTimeConfig) {
intervalTime = intervalTimeConfig * 100;
Expand Down Expand Up @@ -184,8 +183,9 @@ export function activate(context: ExtensionContext) {

setIntervalTime();

// eslint-disable-next-line @typescript-eslint/no-unused-vars
workspace.onDidChangeConfiguration((e: ConfigurationChangeEvent) => {
console.log('🐥>>>Configuration changed', e);
Log.info('Configuration changed');
intervalTimeConfig = LeekFundConfig.getConfig('leek-fund.interval');
setIntervalTime();
setGlobalVariable();
Expand Down Expand Up @@ -256,18 +256,23 @@ function setGlobalVariable() {
globalState.fundLists = fundLists;
}
// 临时解决3.10.1~3.10.3 pr产生的分组bug
const leekFundExt = extensions.getExtension('giscafer.leek-fund');
const currentVersion = leekFundExt?.packageJSON?.version;
// const leekFundExt = extensions.getExtension('giscafer.leek-fund');
// const currentVersion = leekFundExt?.packageJSON?.version;
// if (compare(currentVersion, '3.9.2', '>=')) {
const arr = LeekFundConfig.getConfig('leek-fund.stocks') || [];
const stockList = uniq(compact(flattenDeep(arr)));
LeekFundConfig.setConfig('leek-fund.stocks', stockList);
// const arr = LeekFundConfig.getConfig('leek-fund.stocks') || [];
// const flag = arr.some((a: any) => Array.isArray(a));
// if (flag) {
// const stockList = uniq(compact(flattenDeep(arr)));
// Log.info(" ~ setGlobalVariable ~ stockList:", stockList);
// LeekFundConfig.setConfig('leek-fund.stocks', stockList);
// }

// }
}

// this method is called when your extension is deactivated
export function deactivate() {
console.log('🐥deactivate');
Log.info('deactivate');
FlashNewsDaemon.KillAllServer();
profitBar?.destroy();
if (loopTimer) {
Expand Down
21 changes: 17 additions & 4 deletions src/shared/holidayHelper.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import axios from 'axios';
import { formatDate } from './utils';
import { formatDate, randHeader } from './utils';
import Log from './log';

export class HolidayHelper {
/**
Expand All @@ -11,7 +12,12 @@ export class HolidayHelper {
// https://timor.tech/api/holiday/year/2020
const url = `https://timor.tech/api/holiday/info/${year}`;
try {
const response = await axios.get(url);
const response = await axios.get(url, {
headers: {
...randHeader(),
Referer: 'https://timor.tech/',
}
});
const data = response.data;
// 返回的结构体如下:
// 解释:
Expand Down Expand Up @@ -53,8 +59,14 @@ export class HolidayHelper {
// https://timor.tech/api/holiday/info/2020-09-18
const url = `https://timor.tech/api/holiday/info/${formatDate(date)}`;
try {
const response = await axios.get(url);
const response = await axios.get(url, {
headers: {
...randHeader(),
Referer: 'https://timor.tech/',
}
});
const data = response.data;

// 返回的结构体如下:
// 实例: {"code":0,"type":{"type":0,"name":"周五","week":5},"holiday":null}
// 解释:
Expand Down Expand Up @@ -91,7 +103,8 @@ export class HolidayHelper {
let dataObj = await HolidayHelper.getHolidayDataByDate(date);

if (dataObj) {
tof = dataObj.type.type === 2;
tof = dataObj.type?.type === 2;
Log.info("HolidayHelper ~ 节假日= ~ :", dataObj?.type?.name);
}

return tof;
Expand Down
24 changes: 15 additions & 9 deletions src/shared/leekConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { window, workspace } from 'vscode';
import globalState from '../globalState';
import { clean, uniq, events } from './utils';
import { flattenDeep } from 'lodash';
import { compact, flattenDeep } from 'lodash';

export class BaseConfig {
static getConfig(key: string, defaultValue?: any): any {
Expand All @@ -22,12 +22,13 @@ export class BaseConfig {
return config.update(cfgKey, cfgValue, true);
}

static updateConfig(cfgKey: string, codes: Array<any>) {
static async updateConfig(cfgKey: string, codes: Array<string>) {
const config = workspace.getConfiguration();
const updatedCfg = [...config.get(cfgKey, []), ...codes];
let newCodes = clean(updatedCfg);
newCodes = uniq(newCodes);
return config.update(cfgKey, newCodes, true);
const origin: string[] = config.get(cfgKey, []);
let newCodes = uniq(compact(origin.concat(codes)));
console.log(`🚀 ~ BaseConfig ~ updateConfig ~ ${cfgKey}:`, newCodes);
await config.update(cfgKey, newCodes, true);
return newCodes;
}

static removeConfig(cfgKey: string, code: string) {
Expand Down Expand Up @@ -147,11 +148,16 @@ export class LeekFundConfig extends BaseConfig {
// Fund End

// Stock Begin
static updateStockCfg(codes: string, cb?: Function) {
this.updateConfig('leek-fund.stocks', codes.split(',')).then(() => {
static updateStockCfg(list: string, cb?: Function) {
const cfgKey = 'leek-fund.stocks';
const config = workspace.getConfiguration();
const origin: string[] = config.get(cfgKey, []);
let codes = typeof list === 'string' ? list.split(',') : list;
let newCodes = uniq(compact(flattenDeep(origin).concat(codes)));
config.update(cfgKey, newCodes, true).then(() => {
window.showInformationMessage(`Stock Successfully add.`);
if (cb && typeof cb === 'function') {
cb(codes);
cb(codes, newCodes);
}
});
}
Expand Down
21 changes: 21 additions & 0 deletions src/shared/log.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
let verbose = false;


function log(level = 'info', ...msg: any[]) {
const date = new Date();
console.log(
` 🚀 「LeekFund」${date.toLocaleDateString()} ${date.toLocaleTimeString()} [${level || "info"
}] `, ...msg
);
}


const Log = {
info: (...rest: any[]) => log("info", ...rest),
warn: (msg: string) => log("warn", msg),
error: (msg: string) => log("error", msg),
debug: (msg: string) => verbose && log("debug", msg),
log,
};

export default Log
Loading

0 comments on commit fc32583

Please sign in to comment.