ds_sina.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. package tick
  2. import "net/http"
  3. import "io/ioutil"
  4. import "regexp"
  5. import "strings"
  6. import "bytes"
  7. import "errors"
  8. import "fmt"
  9. import "strconv"
  10. import "time"
  11. import "log"
  12. import "golang.org/x/text/encoding/simplifiedchinese"
  13. var symbolurl = "http://quote.eastmoney.com/stock_list.html"
  14. var lastMarket map[string]string
  15. func GetInstrument() ([]string, []string, error) {
  16. return getInstrument()
  17. }
  18. func getInstrument() ([]string, []string, error) {
  19. resp, err := http.Get(symbolurl)
  20. if err != nil {
  21. return nil, nil, err
  22. }
  23. defer resp.Body.Close()
  24. data, err := ioutil.ReadAll(resp.Body)
  25. if err != nil {
  26. return nil, nil, err
  27. }
  28. symbolcontent := bytes.SplitN(data, []byte(`<div id="quotesearch">`), 2)
  29. if len(symbolcontent) != 2 {
  30. return nil, nil, errors.New("no symbolcontent-0")
  31. }
  32. symbolcontent = bytes.SplitN(symbolcontent[1], []byte("</ul>"), 3)
  33. if len(symbolcontent) != 3 {
  34. return nil, nil, errors.New("no symbolcontent-1")
  35. }
  36. //sh symbol list
  37. shlist, err := getli(symbolcontent[0])
  38. if err != nil {
  39. return nil, nil, err
  40. }
  41. //sz
  42. szlist, err := getli(symbolcontent[1])
  43. if err != nil {
  44. return nil, nil, err
  45. }
  46. var sh []string
  47. for i := 0; i < len(shlist); i++ {
  48. sym , _ := getsymbol(string(shlist[i]))
  49. sh = append(sh, sym)
  50. }
  51. var sz []string
  52. for i := 0; i < len(szlist); i++ {
  53. sym, _ := getsymbol(string(szlist[i]))
  54. sz = append(sz, sym)
  55. }
  56. return sh, sz, nil
  57. }
  58. func GetInstrument2() ([]string, []string, []string, []string, error) {
  59. resp, err := http.Get(symbolurl)
  60. if err != nil {
  61. return nil, nil,nil, nil, err
  62. }
  63. defer resp.Body.Close()
  64. data, err := ioutil.ReadAll(resp.Body)
  65. if err != nil {
  66. return nil, nil, nil, nil, err
  67. }
  68. symbolcontent := bytes.SplitN(data, []byte(`<div id="quotesearch">`), 2)
  69. if len(symbolcontent) != 2 {
  70. return nil, nil, nil, nil, errors.New("no symbolcontent-0")
  71. }
  72. symbolcontent = bytes.SplitN(symbolcontent[1], []byte("</ul>"), 3)
  73. if len(symbolcontent) != 3 {
  74. return nil, nil, nil, nil, errors.New("no symbolcontent-1")
  75. }
  76. //sh symbol list
  77. shlist, err := getli(symbolcontent[0])
  78. if err != nil {
  79. return nil, nil, nil, nil, err
  80. }
  81. //sz
  82. szlist, err := getli(symbolcontent[1])
  83. if err != nil {
  84. return nil, nil, nil ,nil, err
  85. }
  86. var sh []string
  87. var shname []string
  88. trans := simplifiedchinese.GBK.NewDecoder()
  89. dst := make([]byte, 1024)
  90. for i := 0; i < len(shlist); i++ {
  91. symbol, name := getsymbol(string(shlist[i]))
  92. sh = append(sh, symbol)
  93. nDst, _, err := trans.Transform(dst, []byte(name), true)
  94. if err == nil {
  95. name = string(dst[0:nDst])
  96. }
  97. shname = append(shname, name)
  98. }
  99. var sz []string
  100. var szname []string
  101. for i := 0; i < len(szlist); i++ {
  102. symbol, name := getsymbol(string(szlist[i]))
  103. sz = append(sz, symbol)
  104. nDst, _, err := trans.Transform(dst, []byte(name), true)
  105. if err == nil {
  106. name = string(dst[0:nDst])
  107. }
  108. szname = append(szname, name)
  109. }
  110. return sh, sz, shname, szname, nil
  111. }
  112. func getli(data []byte) ([][]byte, error) {
  113. return matchTag(data, "li")
  114. }
  115. func getsymbol(data string) (string, string) {
  116. data = stripTags(data)
  117. o, _, err := strRange(data, "(", ")", 0)
  118. if err != nil {
  119. return "", ""
  120. }
  121. name := strings.Replace(data, "("+o+")", "", -1)
  122. return o, name
  123. }
  124. func strRange(html string, start string, end string, offset int) (string, int, error) {
  125. istart := strings.SplitN(html, start, 2)
  126. if len(istart) != 2 {
  127. return "", 0, errors.New("start string not found")
  128. }
  129. if offset > 0 {
  130. istart[1] = istart[1][offset:]
  131. }
  132. iend := strings.SplitN(istart[1], end, 2)
  133. if len(iend) != 2 {
  134. return "", 0, errors.New("end string not found")
  135. }
  136. return iend[0], len(istart[0]) + len(iend[0]), nil
  137. }
  138. func matchTag(html []byte, tagname string) ([][]byte, error) {
  139. exp, err := regexp.Compile("(?i)<" + tagname + "[^>]*>(.*?)</" + tagname + ">")
  140. if err != nil {
  141. return nil, err
  142. }
  143. matched := exp.FindAllSubmatch(html, -1)
  144. if len(matched) == 0 {
  145. return nil, fmt.Errorf("tagname=%s not matched", tagname)
  146. }
  147. ret := make([][]byte, len(matched))
  148. for i := 0; i < len(ret); i++ {
  149. ret[i] = matched[i][1]
  150. }
  151. return ret, nil
  152. }
  153. var tagsRegexp = regexp.MustCompile("<[^>]+>")
  154. func stripTags(html string) string {
  155. return tagsRegexp.ReplaceAllString(html, "")
  156. }
  157. type SinaDS struct {
  158. *DSBase
  159. }
  160. func init() {
  161. drivers[Sina] = newSinaDS
  162. }
  163. func newSinaDS(conf *DsConf) (DataSource, error) {
  164. return &SinaDS{
  165. DSBase: NewDsBase(conf), // lmax 自己下载历史数据, 所以参数db==nil
  166. }, nil
  167. }
  168. func (lds *SinaDS) Name() string {
  169. return Sina
  170. }
  171. func (lds *SinaDS) Run() {
  172. if !lds.conf.Run {
  173. log.Println("SinaDS.run config NOT run")
  174. return
  175. }
  176. log.Println("SinaDS.run")
  177. fn := func() {
  178. var urls []string
  179. for {
  180. sh, sz, err := getInstrument()
  181. if err != nil {
  182. time.Sleep(time.Second)
  183. continue
  184. }
  185. urls = getfetchurls(sh, sz)
  186. break
  187. }
  188. lastMarket = make(map[string]string)
  189. datach := make(chan []string, 20)
  190. // 登录产生新的Session
  191. for i := 0; i < len(urls); i++ {
  192. go func(n int) {
  193. for {
  194. fetchurl(IntSina, urls[n], datach)
  195. time.Sleep(time.Millisecond * 200)
  196. }
  197. }(i)
  198. }
  199. for {
  200. item := <-datach
  201. newdata := getnewdata(IntSina, item)
  202. for i := 0; i < len(newdata); i++ {
  203. lds.Save(newdata[i])
  204. }
  205. }
  206. }
  207. fn()
  208. }
  209. func getfetchurls(sh []string, sz []string) []string {
  210. baseurl := "http://hq.sinajs.cn/list="
  211. for i := 0; i < len(sh); i++ {
  212. sh[i] = "sh" + sh[i]
  213. }
  214. for i := 0; i < len(sz); i++ {
  215. sz[i] = "sz" + sz[i]
  216. }
  217. sh = append(sh, sz...)
  218. var ret []string
  219. for i := 0; i < len(sh); i = i + 200 {
  220. end := 200
  221. if i+200 > len(sh) {
  222. end = len(sh) - i
  223. }
  224. data := sh[i : i+end]
  225. query := strings.Join(data, ",")
  226. ret = append(ret, baseurl+query)
  227. }
  228. return ret
  229. }
  230. func fetchurl(typ int, url string, ch chan []string) {
  231. if typ == IntSinaFuture {
  232. //log.Println("sinafuture fetchurl begin")
  233. }
  234. resp, err := http.Get(url)
  235. if err != nil {
  236. ch <- nil
  237. log.Println("fetchurl get", err)
  238. return
  239. }
  240. defer resp.Body.Close()
  241. data, err := ioutil.ReadAll(resp.Body)
  242. if err != nil {
  243. ch <- nil
  244. log.Println("fetchurl readall", err)
  245. return
  246. }
  247. tickdatas := parsetick(string(data))
  248. ch <- tickdatas
  249. if typ == IntSinaFuture {
  250. //log.Println("sinafuture fetchurl end")
  251. }
  252. }
  253. func parsetick(data string) []string {
  254. return strings.Split(data, "\n")
  255. }
  256. func getnewdata(typ int, datas []string) []*Market {
  257. var ret []*Market
  258. for i := 0; i < len(datas); i++ {
  259. datas[i] = strings.Replace(datas[i], "var hq_str_", "", -1)
  260. marketdata := strings.SplitN(datas[i], "=", 2)
  261. if len(marketdata) != 2 {
  262. continue
  263. }
  264. if lastdata, ok := lastMarket[marketdata[0]]; ok {
  265. if lastdata == marketdata[1] {
  266. if typ == IntSinaFuture {
  267. //log.Println("sinafuture same")
  268. }
  269. continue
  270. }
  271. }
  272. lastMarket[marketdata[0]] = marketdata[1]
  273. var market *Market
  274. var err error
  275. if typ == IntSina {
  276. market, err = parsemarket(marketdata[0], marketdata[1])
  277. } else {
  278. market, err = parsemarketfuture(marketdata[0], marketdata[1])
  279. }
  280. if err != nil {
  281. log.Println(datas[i], err)
  282. continue
  283. }
  284. ret = append(ret, market)
  285. }
  286. return ret
  287. }
  288. func parsemarket(name string, data string) (*Market, error) {
  289. data = strings.Trim(data, "\";\r\n")
  290. datas := strings.Split(data, ",")
  291. if len(datas) < 32 {
  292. return nil, errors.New("makret data error")
  293. }
  294. var market Market
  295. var err error
  296. market.Open, err = strconv.ParseFloat(datas[1], 64)
  297. if err != nil {
  298. return nil, err
  299. }
  300. market.LastPrice, err = strconv.ParseFloat(datas[2], 64)
  301. if err != nil {
  302. return nil, err
  303. }
  304. market.Close, err = strconv.ParseFloat(datas[3], 64)
  305. if err != nil {
  306. return nil, err
  307. }
  308. market.High, err = strconv.ParseFloat(datas[4], 64)
  309. if err != nil {
  310. return nil, err
  311. }
  312. market.Low, err = strconv.ParseFloat(datas[5], 64)
  313. if err != nil {
  314. return nil, err
  315. }
  316. market.AllVolume, err = strconv.ParseFloat(datas[8], 64)
  317. if err != nil {
  318. return nil, err
  319. }
  320. market.AllAmount, err = strconv.ParseFloat(datas[9], 64)
  321. if err != nil {
  322. return nil, err
  323. }
  324. bids := make([]PP, 5)
  325. bids[0][1], err = strconv.ParseFloat(datas[10], 64)
  326. if err != nil {
  327. return nil, err
  328. }
  329. bids[0][0], err = strconv.ParseFloat(datas[11], 64)
  330. if err != nil {
  331. return nil, err
  332. }
  333. bids[1][1], err = strconv.ParseFloat(datas[12], 64)
  334. if err != nil {
  335. return nil, err
  336. }
  337. bids[1][0], err = strconv.ParseFloat(datas[13], 64)
  338. if err != nil {
  339. return nil, err
  340. }
  341. bids[2][1], err = strconv.ParseFloat(datas[14], 64)
  342. if err != nil {
  343. return nil, err
  344. }
  345. bids[2][0], err = strconv.ParseFloat(datas[15], 64)
  346. if err != nil {
  347. return nil, err
  348. }
  349. bids[3][1], err = strconv.ParseFloat(datas[16], 64)
  350. if err != nil {
  351. return nil, err
  352. }
  353. bids[3][0], err = strconv.ParseFloat(datas[17], 64)
  354. if err != nil {
  355. return nil, err
  356. }
  357. bids[4][1], err = strconv.ParseFloat(datas[18], 64)
  358. if err != nil {
  359. return nil, err
  360. }
  361. bids[4][0], err = strconv.ParseFloat(datas[19], 64)
  362. if err != nil {
  363. return nil, err
  364. }
  365. market.Bids = bids
  366. asks := make([]PP, 5)
  367. asks[0][1], err = strconv.ParseFloat(datas[20], 64)
  368. if err != nil {
  369. return nil, err
  370. }
  371. asks[0][0], err = strconv.ParseFloat(datas[21], 64)
  372. if err != nil {
  373. return nil, err
  374. }
  375. asks[1][1], err = strconv.ParseFloat(datas[22], 64)
  376. if err != nil {
  377. return nil, err
  378. }
  379. asks[1][0], err = strconv.ParseFloat(datas[23], 64)
  380. if err != nil {
  381. return nil, err
  382. }
  383. asks[2][1], err = strconv.ParseFloat(datas[24], 64)
  384. if err != nil {
  385. return nil, err
  386. }
  387. asks[2][0], err = strconv.ParseFloat(datas[25], 64)
  388. if err != nil {
  389. return nil, err
  390. }
  391. asks[3][1], err = strconv.ParseFloat(datas[26], 64)
  392. if err != nil {
  393. return nil, err
  394. }
  395. asks[3][0], err = strconv.ParseFloat(datas[27], 64)
  396. if err != nil {
  397. return nil, err
  398. }
  399. asks[4][1], err = strconv.ParseFloat(datas[28], 64)
  400. if err != nil {
  401. return nil, err
  402. }
  403. asks[4][0], err = strconv.ParseFloat(datas[29], 64)
  404. if err != nil {
  405. return nil, err
  406. }
  407. market.Asks = asks
  408. t, err := time.Parse(time.RFC3339, datas[30]+"T"+datas[31]+"+08:00")
  409. if err != nil {
  410. return nil, err
  411. }
  412. market.Timestamp = t.Unix() * 1000
  413. name = name[2:]
  414. market.InsId, err = strconv.ParseInt(name, 10, 64)
  415. if err != nil {
  416. return nil, err
  417. }
  418. market.Type = IntSina
  419. return &market, nil
  420. }