寫在前面
忙于學(xué)習(xí),我已經(jīng)好久沒有寫過博客了漓概。最近漾月,由于越來越意識到了理財(cái)?shù)闹匾圆∩遥谑俏疫x擇了從最容易入門且風(fēng)險(xiǎn)較低的基金入手,看的同時(shí)也能夠?qū)W習(xí)到一些金融知識梁肿。不過蜓陌,不買就沒有看的欲望,所以我也還是選擇了幾支基金入手了吩蔑,當(dāng)然钮热,最終還是以學(xué)習(xí)為主,收益只能作為一個(gè)檢驗(yàn)學(xué)習(xí)效果的手段烛芬,而不是我當(dāng)前的目的(是未來的目的hhh)隧期。
要想分析基金,少不了歷年的數(shù)據(jù)赘娄,為了分析方便仆潮,我還是覺得先把所有的數(shù)據(jù)爬下來,然后再做進(jìn)一步處理遣臼。
接口分析
爬數(shù)據(jù)需要先思考從哪里爬性置?經(jīng)過一番搜索和考慮,我發(fā)現(xiàn)天天基金網(wǎng)的數(shù)據(jù)既比較全揍堰,又十分容易爬取鹏浅,所以就從它入手了嗅义。
首先,隨便點(diǎn)開一支基金隐砸,我們可以看到域名就是該基金的代碼之碗,十分方便,其次下面有生成的凈值圖凰萨。
打開chrome的開發(fā)者調(diào)試继控,選擇Network,然后刷新一下胖眷,很快我們就能發(fā)現(xiàn)我們想要的東西了武通。可以看到珊搀,這是基金代碼加當(dāng)前時(shí)間的一個(gè)接口冶忱,請求的url是http://fund.eastmoney.com/pingzhongdata/003511.js?v=20190304115823
也就是說我們可以簡單的通過http://fund.eastmoney.com/pingzhongdata/基金代碼.js?v=當(dāng)前時(shí)間
這樣一個(gè)接口就能獲取到相應(yīng)的數(shù)據(jù)了。
現(xiàn)在我們來看看這個(gè)文件的具體內(nèi)容是什么境析?
顯然囚枪,這里面的東西就是我們想要的,Data_netWorthTrend
里面的"y"就包含了每一天的凈值
獲取數(shù)據(jù)
現(xiàn)在我們的接口已經(jīng)十分明確了劳淆,就是http://fund.eastmoney.com/pingzhongdata/基金代碼.js?v=當(dāng)前時(shí)間
通過基金代碼和當(dāng)前時(shí)間我們就能夠獲取到相應(yīng)的數(shù)據(jù)链沼,接下來就是需要將我們想要的數(shù)據(jù)從獲取的文件中提取出來了,也就是我們說的數(shù)據(jù)清洗的過程沛鸵。
這個(gè)網(wǎng)站提供的數(shù)據(jù)不是常見的json格式括勺,因此提取會(huì)有點(diǎn)麻煩,比如通過字符串查找等曲掰,但是由于這個(gè)是js文件疾捍,因此,我找到了更合適的方法——利用了PyExecJs模塊就能很方便地編譯解析js代碼啦栏妖。
現(xiàn)在直接上代碼乱豆。
首先終端里,pip install PyExecJs
安裝上該模塊吊趾。然后引入這些模塊
import requests
import time
import execjs
接口構(gòu)造
構(gòu)造一個(gè)url
def getUrl(fscode):
head = 'http://fund.eastmoney.com/pingzhongdata/'
tail = '.js?v='+ time.strftime("%Y%m%d%H%M%S",time.localtime())
return head+fscode+tail
獲取凈值
def getWorth(fscode):
#用requests獲取到對應(yīng)的文件
content = requests.get(getUrl(fscode))
#使用execjs獲取到相應(yīng)的數(shù)據(jù)
jsContent = execjs.compile(content.text)
name = jsContent.eval('fS_name')
code = jsContent.eval('fS_code')
#單位凈值走勢
netWorthTrend = jsContent.eval('Data_netWorthTrend')
#累計(jì)凈值走勢
ACWorthTrend = jsContent.eval('Data_ACWorthTrend')
netWorth = []
ACWorth = []
#提取出里面的凈值
for dayWorth in netWorthTrend[::-1]:
netWorth.append(dayWorth['y'])
for dayACWorth in ACWorthTrend[::-1]:
ACWorth.append(dayACWorth[1])
print(name,code)
return netWorth, ACWorth
查看數(shù)據(jù)
這樣我們就可以通過基金代碼來查到對應(yīng)的數(shù)據(jù)啦
netWorth, ACWorth = getWorth('003511')
print(netWorth)
可以看到宛裕,最近一天的凈值是1.0831,從網(wǎng)站上我們也可以驗(yàn)證一下這個(gè)數(shù)據(jù)是否正確
當(dāng)然论泛,我們也可以自己畫一個(gè)走勢圖來驗(yàn)證一下
import matplotlib.pyplot as plt
plt.figure(figsize=(10,5))
plt.plot(netWorth[:60][::-1])
plt.show()
可以看到揩尸,和天天基金網(wǎng)畫的是一樣的。
不過這個(gè)方法獲取的數(shù)據(jù)有個(gè)小問題孵奶,就是無法獲得對應(yīng)的確切日期疲酌。我們?nèi)绻治鲎罱鼛讉€(gè)周、幾個(gè)月的數(shù)據(jù),其實(shí)也可以不需要了解具體某一天的數(shù)據(jù)朗恳,取最近20天湿颅、40天等方式即可棵里。當(dāng)然症概,也可以從當(dāng)天開始逆推回去,給每個(gè)凈值標(biāo)上日期邢锯,不過這個(gè)需要忽略節(jié)假日怀浆,處理起來比較麻煩且必要性不大谊囚,我就沒有做這個(gè)處理。
獲取所有基金數(shù)據(jù)
這里我通過同樣的方式执赡,找到了所有基金列表的接口镰踏。
通過'http://fund.eastmoney.com/js/fundcode_search.js'
便可以直接獲取到所有的基金代碼,再通過基金代碼可以遍歷爬取所有基金的數(shù)據(jù)沙合,具體就不再演示了奠伪,下面提供一個(gè)可用的代碼供參考。
我將下載的數(shù)據(jù)存成了csv首懈,方便excel打開或用代碼讀取绊率。當(dāng)然,總共有近8000支基金究履,爬取需要大量的時(shí)間滤否,因此我將它放在了服務(wù)器后臺爬取,如果你想提高效率最仑,可以改寫成多進(jìn)程同步爬取藐俺,時(shí)間將會(huì)大大縮短。
import requests
import time
import execjs
def getUrl(fscode):
head = 'http://fund.eastmoney.com/pingzhongdata/'
tail = '.js?v='+ time.strftime("%Y%m%d%H%M%S",time.localtime())
return head+fscode+tail
# 根據(jù)基金代碼獲取凈值
def getWorth(fscode):
content = requests.get(getUrl(fscode))
jsContent = execjs.compile(content.text)
name = jsContent.eval('fS_name')
code = jsContent.eval('fS_code')
#單位凈值走勢
netWorthTrend = jsContent.eval('Data_netWorthTrend')
#累計(jì)凈值走勢
ACWorthTrend = jsContent.eval('Data_ACWorthTrend')
netWorth = []
ACWorth = []
for dayWorth in netWorthTrend[::-1]:
netWorth.append(dayWorth['y'])
for dayACWorth in ACWorthTrend[::-1]:
ACWorth.append(dayACWorth[1])
print(name,code)
return netWorth, ACWorth
def getAllCode():
url = 'http://fund.eastmoney.com/js/fundcode_search.js'
content = requests.get(url)
jsContent = execjs.compile(content.text)
rawData = jsContent.eval('r')
allCode = []
for code in rawData:
allCode.append(code[0])
return allCode
allCode = getAllCode()
netWorthFile = open('./netWorth.csv','w')
ACWorthFile = open('./ACWorth.csv','w')
for code in allCode:
try:
netWorth, ACWorth = getWorth(code)
except:
continue
if len(netWorth)<=0 or len(ACWorth)<0:
print(code+"'s' data is empty.")
continue
netWorthFile.write("\'"+code+"\',")
netWorthFile.write(",".join(list(map(str, netWorth))))
netWorthFile.write("\n")
ACWorthFile.write("\'"+code+"\',")
ACWorthFile.write(",".join(list(map(str, ACWorth))))
ACWorthFile.write("\n")
print("write "+code+"'s data success.")
netWorthFile.close()
ACWorthFile.close()
這是我用服務(wù)器爬取的數(shù)據(jù)盯仪,可以看到紊搪,總共大概35M+35M蜜葱。