Python爬蟲之——爬取基金數(shù)據(jù)

要點:

?1筒狠、數(shù)據(jù)的分析與爬取

2舔庶、pyecharts繪圖

數(shù) 據(jù) 源

數(shù)據(jù)來源我們選擇新浪財經(jīng)基金板塊:https://finance.sina.com.cn/fund/

我們隨便選一個基金抛蚁,就選第一個吧:660001,農(nóng)銀行業(yè)成長混合A

老辦法惕橙,監(jiān)控Network

分析新浪財經(jīng)基金板塊Network

通過分析瞧甩,我們發(fā)現(xiàn)了三個request:

今日的實時數(shù)據(jù)從下面的連接返回

https://app.xincai.com/fund/api/jsonp.json/var%20t1fu_660001=/XinCaiFundService.getFundYuCeNav?symbol=660001&___qn=3

返回信息格式如下

var t1fu_660001=({"yes":"2.6775","detail":"09:30,2.6822,09:31,...,15:03,2.7189"});

歷史數(shù)據(jù)從下面的連接返回

https://finance.sina.com.cn/fund/api/xh5Fund/nav/660001.js

返回信息格式如下

xh5Fund({"data":"20200220,2.6775,3.2775,4.15436,82.38,81.8,56.24#

20200219,2.6223,3.2223,4.06871,84.26,81.19,55.47#...#20080804,1,1,1,,,","symbol":"660001","fhday":"20091123,20100426","fhvalue":"0.4,0.2","fhchaifen":"0,0"})

數(shù)據(jù)順序為:日期、單位凈值弥鹦、累積凈值肚逸、歷史回報、排位百分比彬坏、排位百分比朦促、排位百分比

查詢時間下的基金綜合數(shù)據(jù)

https://hq.sinajs.cn/list=fu_660001

返回信息
var hq_str_fu_660001="農(nóng)銀行業(yè)成長混合A

,15:04:00,2.6722,2.6223,3.2223,0.0262,1.9029,2020-02-20";

爬取并解析數(shù)據(jù)

了解了以上信息,我們就可以用requests獲得返回的數(shù)據(jù)栓始。

我們可以先定義header务冕,假裝是瀏覽器訪問網(wǎng)站

header = {
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3704.400 SLBrowser/10.0.3929.400",
}

實時數(shù)據(jù)的解析

解析返回的實時數(shù)據(jù)字符串,按照 左括號 ( 與右括號 ) 拆分幻赚,將提取出的大括號{}中的數(shù)據(jù)利用ast.literal_eval轉(zhuǎn)換為字典禀忆。yes對應(yīng)的字符串直接轉(zhuǎn)換為float,detail對應(yīng)的字符串按照 逗號 坯屿, 拆分油湖,每兩個數(shù)據(jù)一組,第一個為“時間”保持字符串即可领跛,第二個為“實時數(shù)據(jù)”轉(zhuǎn)換為float乏德。將解析好的數(shù)據(jù)再次打包為字典即可備用。

歷史數(shù)據(jù)的解析

歷史數(shù)據(jù)的解析吠昭,與實時數(shù)據(jù)基本相似喊括,也是先通過對左右括號的拆分,提取出需要的字典字符串?dāng)?shù)據(jù)矢棚,而后利用ast.literal_eval將字符串轉(zhuǎn)為字典郑什。字典的data中是每日數(shù)據(jù),這里用 # 號拆分歷史每日數(shù)據(jù)字符串蒲肋,再將每一天的數(shù)據(jù)字符串用 逗號, 拆分蘑拯,依照數(shù)據(jù)順序轉(zhuǎn)換為float打包為最終字典即可钝满。

定義抓取數(shù)據(jù)函數(shù)代碼,返回 實時數(shù)據(jù)字典 與 每日數(shù)據(jù)字典

# -*- coding:utf-8 -*-
import requests
import re
import ast
header = {
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3704.400 SLBrowser/10.0.3929.400",
}
today_url_format = "https://app.xincai.com/fund/api/jsonp.json/var%20t1fu_{}=/XinCaiFundService.getFundYuCeNav?symbol={}&___qn=3"
both_url_format = "https://finance.sina.com.cn/fund/api/xh5Fund/nav/{}.js"
name_url_format = "https://hq.sinajs.cn/list=fu_{}"
def catchData(code):
    today_url = today_url_format.format(code,code)
    both_url = both_url_format.format(code)
    name_url = name_url_format.format(code)
    #獲得當(dāng)天數(shù)據(jù),步長為分鐘
    today_response = requests.get(today_url,headers=header)
    today_str = re.split("[()]",today_response.text)[1]#通過()拆分字符串
    today_dict_one = ast.literal_eval(today_str)#初步生成字典
    minute_list_strs = today_dict_one['detail'].split(',')#拆分字典中detail的字符串
    minute_dict = {}
    for i in range(0,len(minute_list_strs),2):
        minute_dict[minute_list_strs[i]] = float(minute_list_strs[i+1])
    today_dict = {"yes":float(today_dict_one["yes"]),"detail":minute_dict}
    #獲得全部數(shù)據(jù)申窘,步長為天
    both_response = requests.get(both_url,headers=header)
    both_str = re.split("[()]",both_response.text)[1]
    both_dict_one = ast.literal_eval(both_str)
    day_list_strs = both_dict_one['data'].split('#')
    day_list = {}
    for i in range(len(day_list_strs)):
        str = day_list_strs[i];
        str_list = str.split(',')
        day_list[str_list[0]] = {"dwjz":str2float(str_list[1]),"jljz":str2float(str_list[2]),
                                 "lshb":str2float(str_list[3]),"mper":str2float(str_list[4]),
                                 "qper":str2float(str_list[5]),"yper":str2float(str_list[6])}
    both_dict = {"symbol":both_dict_one["symbol"],"fhday":both_dict_one["fhday"],
                 "fhvalue":both_dict_one["fhvalue"],"fhchaifen":both_dict_one["fhchaifen"],
                "data":day_list}
    #獲取基金名稱
    name_response = requests.get(name_url,headers=header)
    name_str = name_response.text.split('="')[1].split(',')[0]
    today_dict["name"] = name_str
    both_dict["name"] = name_str
    return today_dict,both_dict
def str2float(str):
    return 0 if ''==str else float(str)

調(diào)用函數(shù)

我們只需要給出基金代碼弯蚜,既可以獲得數(shù)據(jù)字典

code = "660001"    
today_dict,both_dict = catchData(code) 

繪制數(shù)據(jù)曲線

pyecharts是非常強大的繪圖工具,非常好用剃法。分為 v0.5.X 和 v1 兩個大版本碎捺,v0.5.X 和 v1 間不兼容,v1 是一個全新的版本贷洲。目前官方已經(jīng)不再維護v0.5.X版本收厨,因此本文建議讀者使用v1版本。

:v1版本僅支持 Python3.6+

特別注意:本文使用的環(huán)境是一款神器jupyter lab优构,在該環(huán)境下可以使用

render_notebook()直接繪制pyecharts圖形诵叁。但是因為其無法得知用戶的具體開發(fā)環(huán)境,因此需要指定開發(fā)環(huán)境:

CurrentConfig.NOTEBOOK_TYPE = NotebookType.JUPYTER_LAB

如果在調(diào)用render_notebook()時繪制的依然為空白俩块,說明環(huán)境沒有正確加載echarts.js等文件黎休,只需要在繪制前調(diào)用:load_javascript()即可。

在jupyter lab環(huán)境中玉凯,調(diào)用load_javascript()與render_notebook()需要和設(shè)置圖形的代碼段分開势腮。

具體詳見官方文檔:

https://pyecharts.org/#/zh-cn/notebook?id=jupyter-lab

繪制實時數(shù)據(jù)折線圖

下面介紹一下繪制實時數(shù)據(jù)折線圖的關(guān)鍵點:

1)通過is_smooth=True可以平滑折線圖

2)通過extend_axis函數(shù)定義第二個y軸,并設(shè)置其格式:formatter="{value} %"

3)字典的keys方法可以將字典的所有索引提取為數(shù)組

4)字典的values方法可以將字典的所有值提取為數(shù)組

from pyecharts.globals import CurrentConfig, NotebookType
CurrentConfig.NOTEBOOK_TYPE = NotebookType.JUPYTER_LAB
import pyecharts.options as opts
from pyecharts.faker import  Faker
from pyecharts.charts import Line
import numpy as np
yes = today_dict["yes"]
xaxis = list(today_dict["detail"].keys())#獲得x軸數(shù)據(jù)
yaxis = list(today_dict["detail"].values())#獲得y軸數(shù)據(jù)
yaxis_plus_yes = [yes-x for x in yaxis]
dy_max_abs = np.max(np.abs(yaxis_plus_yes))#用來計算百分比和坐標軸范圍
def today_line_smooth() -> Line:
    c = (
        Line()
        .add_xaxis(xaxis)
        .add_yaxis("凈值預(yù)測", yaxis , is_smooth=True,is_hover_animation=True,yaxis_index=0)
        .extend_axis(
            yaxis=opts.AxisOpts(
                axislabel_opts=opts.LabelOpts(formatter="{value} %"),
                min_=round(-dy_max_abs/yes*100,2),
                max_=round(dy_max_abs/yes*100,2)
            )
        )
        .set_global_opts(title_opts=opts.TitleOpts(title="Line-smooth"),
                         yaxis_opts=opts.AxisOpts(min_=round(yes-dy_max_abs,4),max_=round(yes+dy_max_abs,4)))
    )
    return c
line = today_line_smooth()
line.load_javascript()
line.render_notebook()

實時數(shù)據(jù)折線圖

繪制歷史單位凈值及積累凈值曲線

主要需要注意如下幾點:

  1. 配置AxisOpts漫仆,min_=min,max_=max捎拯,使曲線上只提示最大值和最小值

2)配置TooltipOpts,使鼠標移動顯示十字交叉線盲厌,并提示關(guān)鍵信息:

 trigger="axis",trigger_on="mousemove",axis_pointer_type="cross"

3)通過函數(shù)形式署照,返回JsCode字符串設(shè)置自定義Tooltip文字

3.1) 需要包含from pyecharts.commons.utils import JsCode

3.2)JsCode字符串中的字符串必須用單引號'包擴,否則會報錯

3.3)函數(shù)的參數(shù)是個列表吗浩,具體形式可以通過console.log(params)查看建芙,自定義文字所需要的數(shù)據(jù)均在params中,可以通過拼接字符串的型式懂扼,將python中的變量引入到JsCode中禁荸。

def getToolip():
    a1 = yaxis_dwjz[0]
    a2 = yaxis_jljz[0]
    return JsCode("""function (params) {
               var dwjz_per =  (params[0].value[1]-"""+str(a1)+""")/"""+str(a1)+""";
               dwjz_per = (dwjz_per*100).toFixed(2);
               var jljz_per = (params[1].value[1]-"""+str(a2)+""")/"""+str(a2)+""";
               jljz_per = (jljz_per*100).toFixed(2);
               return params[0].axisValue+'<br>'+
               params[0].seriesName+' : '+params[0].value[1]+'('+dwjz_per+'%)<br>'+
               params[1].seriesName+' : '+params[1].value[1]+'('+jljz_per+'%)<br>';
           }""")

定義曲線

from pyecharts.commons.utils import JsCode
datas = both_dict["data"]
xaxis_all = list(datas.keys())
xaxis_all.sort()#升序排列,返回的數(shù)據(jù)是降序的
beginX = "20191113"#設(shè)置繪制的開始時間
endX = "20200221"#設(shè)置繪制的結(jié)束時間
xaxis = []
yaxis_dwjz = []
yaxis_jljz = []
for key in xaxis_all:#提取y軸數(shù)據(jù)
    if key<beginX or key>endX:
        continue
    data = datas[key]
    xaxis.append(key)
    yaxis_dwjz.append(data["dwjz"])
    yaxis_jljz.append(data["jljz"])
#計算坐標軸范圍
max = round(1.05*np.max([yaxis_dwjz,yaxis_jljz]),1)
min = round(0.95*np.min([yaxis_dwjz,yaxis_jljz]),1)
dy_min = (min-yaxis_dwjz[0])/yaxis_dwjz[0]*100
dy_max = (max-yaxis_dwjz[0])/yaxis_dwjz[0]*100

def both_line_smooth_1() -> Line:
    c = (
        Line()
        .add_xaxis(xaxis)
        .add_yaxis("單位凈值", yaxis_dwjz)
        .add_yaxis("積累凈值", yaxis_jljz)
        .extend_axis(
            yaxis=opts.AxisOpts(
                axislabel_opts=opts.LabelOpts(formatter="{value} %"),
                min_=round(dy_min,1),
                max_=round(dy_max,1)
            )
        )
        .set_global_opts(title_opts=opts.TitleOpts(title="Line-smooth"),
                         yaxis_opts=opts.AxisOpts(min_=min,max_=max,interval=round((max-min)/8,1)),
                         tooltip_opts=opts.TooltipOpts(is_show=True,trigger="axis",
                                                       trigger_on="mousemove",axis_pointer_type="cross",
                                                       formatter=getToolip()))
        .set_series_opts(label_opts = opts.LabelOpts(is_show = False), is_smooth=True,is_hover_animation=True,
                         markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_ = "max",name = "max"),
                                                                 opts.MarkPointItem(name = "min",type_ = "min")]))
    )
    return c
line = both_line_smooth_1()
line.render_notebook()

歷史數(shù)據(jù)折線圖

通過同樣的方式阀湿,繪制 歷史回報曲線赶熟、以及排位百分比曲線

歷史回報曲線

排位百分比曲線

總結(jié)

本文為處理量化投資數(shù)據(jù),做了最基本的事情陷嘴。爬取數(shù)據(jù)映砖,解析,并且研究了如何美觀的繪制折線圖灾挨,希望對您有所幫助邑退!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末竹宋,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子地技,更是在濱河造成了極大的恐慌逝撬,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乓土,死亡現(xiàn)場離奇詭異,居然都是意外死亡溯警,警方通過查閱死者的電腦和手機趣苏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來梯轻,“玉大人食磕,你說我怎么就攤上這事≡簦” “怎么了彬伦?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長伊诵。 經(jīng)常有香客問我单绑,道長,這世上最難降的妖魔是什么曹宴? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任搂橙,我火速辦了婚禮,結(jié)果婚禮上笛坦,老公的妹妹穿的比我還像新娘区转。我一直安慰自己,他們只是感情好版扩,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布废离。 她就那樣靜靜地躺著,像睡著了一般礁芦。 火紅的嫁衣襯著肌膚如雪蜻韭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天宴偿,我揣著相機與錄音湘捎,去河邊找鬼。 笑死窄刘,一個胖子當(dāng)著我的面吹牛窥妇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播娩践,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼活翩,長吁一口氣:“原來是場噩夢啊……” “哼烹骨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起材泄,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤沮焕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后拉宗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體峦树,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年旦事,在試婚紗的時候發(fā)現(xiàn)自己被綠了魁巩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡姐浮,死狀恐怖谷遂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卖鲤,我是刑警寧澤肾扰,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站蛋逾,受9級特大地震影響集晚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜换怖,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一甩恼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧沉颂,春花似錦条摸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至彻坛,卻和暖如春顷啼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背昌屉。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工钙蒙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人间驮。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓躬厌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親竞帽。 傳聞我的和親對象是個殘疾皇子扛施,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容