近半年多表箭,基金又變得異沉蘖火爆,很多小朋友開始投資基金,但是基金的選擇是個(gè)頭疼的問(wèn)題序目,網(wǎng)上眾多up主臂痕,各自心懷鬼胎、眾說(shuō)紛紜猿涨。之前火爆的“坤坤”握童,一夜之間也跌回解放前。所以叛赚,想賺錢澡绩,還得靠自己,任何人都不會(huì)對(duì)你的選擇負(fù)責(zé)俺附!
最近很流行的一句話:“你只能賺到自己認(rèn)知范圍內(nèi)的錢肥卡。”
那么事镣,自己如何選擇步鉴?
孫子曾經(jīng)曰過(guò):**知己知彼…… **
先看看某寶的“金選好基”:
再看看已經(jīng)跌下神壇的坤坤的基金在某寶上是個(gè)什么狀態(tài):
金選!
金牌經(jīng)理璃哟!
驚不驚喜氛琢?意不意外?
所以随闪,平臺(tái)推薦的你敢買嗎阳似?
毛爺爺說(shuō)的好:自己動(dòng)手,豐衣足食铐伴。 基金好不好撮奏,我們自己來(lái)判斷。
自己來(lái)分析基金的好壞当宴,其實(shí)步驟也很簡(jiǎn)單畜吊,類似把大象放進(jìn)冰箱里:
- 打開冰箱——獲取數(shù)據(jù)
- 把大象塞進(jìn)冰箱——分析數(shù)據(jù)
- 關(guān)上冰箱門——買入
1. 獲取數(shù)據(jù)
按照國(guó)際慣例,我們以東方財(cái)富的天天基金網(wǎng)作為數(shù)據(jù)源:
網(wǎng)上其實(shí)很多教我們?nèi)绾斡胮ython爬天天基金的數(shù)據(jù)的文章即供,很顯然這些文章幫助了很多人定拟,但也給天天基金網(wǎng)造成了不少的困擾,所以他們經(jīng)常修改一些參數(shù)名或者id名逗嫡。
好老師應(yīng)該授人予漁,而非授人予魚株依,文章會(huì)有點(diǎn)長(zhǎng)驱证,我把小白可能遇到的坑以及解題思路都會(huì)盡量詳細(xì)的分享出來(lái),目的就是讓小白真正掌握獲取數(shù)據(jù)的能力恋腕,不管別人的網(wǎng)站再如何變化抹锄,我們都能找到應(yīng)對(duì)的辦法。
數(shù)據(jù)獲取方式
通常來(lái)說(shuō),公開網(wǎng)站的數(shù)據(jù)獲取方式有兩種:
- 爬蟲——最簡(jiǎn)單粗暴
- Web API——最優(yōu)雅
1.1 爬蟲
爬蟲方式是網(wǎng)上文章最多的伙单,雖然看上去簡(jiǎn)單获高,但很多經(jīng)常被爬的網(wǎng)站都會(huì)設(shè)計(jì)一些反爬機(jī)制,小白在實(shí)際操作時(shí)卻會(huì)遇到無(wú)數(shù)的坑吻育∧钛恚坑有很多種:
- 反DDOS
- 異步加載數(shù)據(jù)
- 用戶真實(shí)性驗(yàn)證
我們先把坑的事情放一邊,回到爬蟲本身布疼,看看如何展開接下來(lái)的工作摊趾。
想爬數(shù)據(jù),第一步就是分析頁(yè)面的代碼游两,打開瀏覽器的開發(fā)者模式砾层,選擇頁(yè)面中數(shù)據(jù)的部分,然后分析其HTML代碼的特征:
以上圖為例贱案,所有的數(shù)據(jù)都在 <table id="dbtable">...</table> 標(biāo)簽中肛炮。id在一個(gè)html頁(yè)面中是唯一的,因此通過(guò)代碼只要提取出id=“dbtable”的對(duì)象宝踪,理論上就可以得到table中的所有數(shù)據(jù)了侨糟。
但是,眾所周知肴沫,事情總不會(huì)一帆風(fēng)順粟害,不過(guò),我先上一段代碼吧:
import requests
url = 'http://fund.eastmoney.com/data/fundranking.html#tgp;c0;r;s1nzf;pn50;ddesc;qsd20200715;qed20210715;qdii;zq;gg;gzbd;gzfs;bbzt;sfbb'
# 獲取url的結(jié)果
response = requests.get(url)
# 看看我們都拿到了什么東西
print(response.content)
以下是結(jié)果的局部:
b'\xef\xbb\xbf\r\n\r\n<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r\n<html xmlns="http://www.w3.org/1999/xhtml">\r\n<head>\r\n <title>\xe5\xbc\x80\xe6\x94\xbe\xe5\xbc\x8f\xe5\x9f\xba\xe9\x87\x91\xe6\x8e\x92\xe8\xa1\x8c _ \xe5\xa4\xa9\xe5\xa4\xa9\xe5\x9f\xba\xe9\x87\x91\xe7\xbd\x91</title>\r\n
是不是看不懂颤芬?不要內(nèi)疚悲幅,我也看不懂,因?yàn)檫@東西本來(lái)就有問(wèn)題站蝠, \xe5\xbc\x80\xe6\x94\xbe\xe5\xbc\x8f\xe5\x9f\這些有規(guī)律但不知所云的東西其實(shí)是中文汰具,只不過(guò)request庫(kù)默認(rèn)的編碼方式是ISO-8859-1,在ISO-8859-1的字符集是不包涵中文的菱魔,所以就把原始信息直接丟了出來(lái)留荔。這是小白們遇到的第一個(gè)小坑——中文字符編碼問(wèn)題。如何解決也非常的簡(jiǎn)單澜倦,只要做一個(gè)decode操作聚蝶,把字符集設(shè)置成utf-8,那么一切都回來(lái)了藻治。不信你就試試看:
print(response.content.decode('utf8'))
# 以下是部分結(jié)果:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>開放式基金排行 _ 天天基金網(wǎng)</title>
<meta name="keywords" content="基金排行,開放式基金排行,創(chuàng)新基金排行,貨幣基金排行,漲幅排行,基金排行查詢,漲幅分布,自定義基金排行,股票型基金,混合型基金,債券型基金,指數(shù)型基金,保本型基金,QDII,LOF,按基金公司篩選" />
<meta name="description" content="天天基金網(wǎng)每日及時(shí)更新開放式基金收益率排行碘勉。" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="mobile-agent" content="format=html5; url=https://m.1234567.com.cn/?page=jjph&tab=qb" />
<meta http-equiv="Content-Language" content="zh-CN" />
<meta http-equiv="Cache-Control" content="no-cache" />
<meta http-equiv="Expires" content="-1" />
很明顯,中文正常顯示了桩卵,連換行也正常了验靡。
接下來(lái)的問(wèn)題就是想辦法從這堆html代碼中把<table id="dbtable">...</table> 的內(nèi)容過(guò)濾出來(lái)倍宾。還記得前面截圖中的XPath嗎?
什么是XPath胜嗓?不知道的看這里高职。
按照最簡(jiǎn)單的做法,看看我們能得到什么辞州,先看代碼:
from lxml import etree
tree = etree.HTML(response.content.decode('utf8'))
dbtab = tree.xpath('//*[@id=\"dbtable\"]')
print(dbtab[0].text)
但是結(jié)果什么都沒(méi)有怔锌。也許這是我們遇到的第二個(gè)坑!回去翻翻print(response.content.decode('utf8'))孙技,找到<table id="dbtable">發(fā)現(xiàn):
<table id="dbtable">
<thead>
<tr>
<th>比較</th>
<th>序號(hào)</th>
<th col="dm" class="tworow"><a><span class="ades">基金<br />
代碼</span><span class="showway"></span></a></th>
<th col="jc"><a>基金簡(jiǎn)稱</a></th>
<th col="jzrq"><a>日期</a></th>
<th col="dwjz"><a>單位凈值</a></th>
<th col="ljjz"><a>累計(jì)凈值</a></th>
<th col="rzdf"><a>日增長(zhǎng)率</a></th>
<th col="zzf"><a>近1周</a></th>
<th col="1yzf"><a>近1月</a></th>
<th col="3yzf"><a>近3月</a></th>
<th col="6yzf"><a>近6月</a></th>
<th col="1nzf"><a>近1年</a></th>
<th col="2nzf"><a>近2年</a></th>
<th col="3nzf"><a>近3年</a></th>
<th col="jnzf"><a>今年來(lái)</a></th>
<th col="lnzf" style="white-space: nowrap;"><a>成立來(lái)</a></th>
<th col="qjzf" id="sortclass" class="datespan">
<div style="position: relative" col="qjzf">
<a onmouseover="show_tip();">自定義</a>
<b class="cal" id="calen"></b>
</div>
</th>
<th class="yh_head">手續(xù)費(fèi)</th>
<th>
<label style="text-align: center; vertical-align: middle">
<input id="onlysale" style="margin-top: 0px" type="radio" value="1" name="showsale" class="md" checked="checked" /><span class="md">可購(gòu)</span></label><br />
<label style="text-align: center; vertical-align: middle;">
<input style="margin-top: 0px" type="radio" value="0" name="showsale" class="md" id="allfund" checked="" /><span class="md">全部</span>
</label>
</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
只有表頭产禾,tbody竟然是空的,果然牵啦,我們遇到了第二個(gè)坑亚情,數(shù)據(jù)異步加載。
雖然這是個(gè)坑哈雏,但有好也有壞楞件,通常我們有兩個(gè)解題思路:
- 順著爬蟲思路往下走,我們需要一個(gè)瀏覽器的模擬器裳瘪,拿到瀏覽器渲染完成的數(shù)據(jù)土浸。
- 既然是異步,那么一定有web API彭羹,這樣我們就不需要用爬蟲爬去數(shù)據(jù)了黄伊,省去了后面繁瑣的數(shù)據(jù)整理工作。
1.1.1 瀏覽器模擬器
本文不作為重點(diǎn)派殷,這里只簡(jiǎn)單介紹一下还最。python生態(tài)的瀏覽器模擬器最有名的就是selinum,它可以調(diào)用本地的瀏覽器驅(qū)動(dòng)毡惜,完整的模擬瀏覽器的操作拓轻,包括點(diǎn)擊事件等,非常強(qiáng)大经伙,在一些需要通過(guò)交互過(guò)程才能獲取到數(shù)據(jù)的場(chǎng)景下非常有用扶叉。
1.2 Web API
既然我們確定了有Web API,那么帕膜,應(yīng)該去哪找它呢枣氧?
首先,還是去看瀏覽器的開發(fā)者工具:
打開Network選項(xiàng)卡垮刹。如果你的選項(xiàng)卡中有一大堆東西作瞄,可以點(diǎn)擊左上角第二排的第二個(gè)按鈕清理一下。接下來(lái)按照下圖的示意危纫,隨便點(diǎn)擊表格上方的分類按鈕,如圖中所示,我點(diǎn)擊的是混合型按鈕:
在下方開發(fā)者工具的列表中多了兩個(gè)請(qǐng)求种蝶,點(diǎn)開最長(zhǎng)的那個(gè)契耿,看到這個(gè)請(qǐng)求的Response中剛好是表格中的內(nèi)容!看來(lái)螃征,這應(yīng)該就是我們要找的東西了搪桂。復(fù)制這個(gè)請(qǐng)求地址:http://fund.eastmoney.com/data/rankhandler.aspx?op=ph&dt=kf&ft=hh&rs=&gs=0&sc=1nzf&st=desc&sd=2020-07-15&ed=2021-07-15&qdii=&tabSubtype=,,,,,&pi=1&pn=50&dx=1&v=0.726345617727655 我們單獨(dú)打開看看:
var rankData ={ErrCode:-999,Data:"無(wú)訪問(wèn)權(quán)限"}
為什么會(huì)這樣?我們也不是注冊(cè)用戶盯滚,打開網(wǎng)頁(yè)就能正程咝担看到數(shù)據(jù)了,哪來(lái)的訪問(wèn)權(quán)限魄藕?
其實(shí)這個(gè)就是網(wǎng)站設(shè)計(jì)的典型反爬機(jī)制内列,也就是前面說(shuō)的第三個(gè)坑,驗(yàn)證用戶的真實(shí)性背率。我簡(jiǎn)單解釋一下背后的邏輯:
一個(gè)正常人類去訪問(wèn)這個(gè)頁(yè)面话瞧,這個(gè)url地址的真正訪問(wèn)者應(yīng)該是http://fund.eastmoney.com/data/fundranking.html 這個(gè)頁(yè)面中的JavaScript代碼,所以它可以通過(guò)驗(yàn)證流量來(lái)源的身份來(lái)確認(rèn)是否是一個(gè)正常訪問(wèn)請(qǐng)求寝姿。
這個(gè)可以偽裝嗎交排?答案是肯定的。為了保持用戶和服務(wù)器端的交互連續(xù)性饵筑,用戶和服務(wù)器之前存在一個(gè)叫做會(huì)話的東西埃篓,在http協(xié)議中叫做request(請(qǐng)求)。request中可以存儲(chǔ)許多與用戶相關(guān)的信息根资,有一些是協(xié)議默認(rèn)的架专,我們還可以在程序里面自定義添加一些特殊信息,實(shí)現(xiàn)從瀏覽器向服務(wù)器傳遞數(shù)據(jù)嫂冻。
注意:通過(guò)URL傳遞參數(shù)的方式是明文的胶征,請(qǐng)勿傳遞敏感信息。這種傳輸方式也叫GET請(qǐng)求桨仿。敏感信息可以采用POST非明文方式睛低,具體方法本文不展開,感興趣的同學(xué)請(qǐng)自行搜索服傍。
說(shuō)到Request钱雷,我們不妨去瀏覽器的開發(fā)者工具中看看剛才的url請(qǐng)求中都有些什么東西:
在請(qǐng)求的Headers里面,我們可以找到Request Headers吹零,我們注意看里面的Host和Referer這兩個(gè)字段罩抗,它倆其實(shí)就是前面說(shuō)的web API去驗(yàn)證請(qǐng)求來(lái)源的依據(jù),我們只要把和兩個(gè)東西塞到我們的Request Header中灿椅,應(yīng)該就能拿到數(shù)據(jù)了套蒂。來(lái)看看代碼:
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36',
'Host': 'fund.eastmoney.com',
'Accept-Encoding': 'gzip, deflate',
'Referer': 'http://fund.eastmoney.com/data/fundranking.html'
}
response = requests.get(url, headers=headers)
我們?cè)黾恿艘粋€(gè)叫做headers的字典钞支,把剛才瀏覽器的Request Headers中的關(guān)鍵內(nèi)容塞進(jìn)去就行,User-Agent和Cookie也可以塞進(jìn)去操刀,一般這種API還會(huì)去校驗(yàn)這兩個(gè)東西烁挟。
偽裝的Header做好了以后,我們?cè)趓equests.get方法中傳入剛才做好的headers骨坑,這樣就能拿到真正的數(shù)據(jù)了:
var rankData = {datas:["000209,信誠(chéng)新興產(chǎn)業(yè)混合,XCXXCYHH,2021-07-16,4.6530,4.6530,-1.81,1.35,35.38,68.71,53.97,153.16,301.12,277.07,60.84,365.30,2013-07-17,1,142.1564,1.50%,0.15%,1,0.15%,1,157.36",
"002190,農(nóng)銀新能源主題,NYXNYZT,2021-07-16,3.8259,3.8259,-3.01,0.54,25.48,53.12,36.05,140.99,352.02,288.26,37.18,282.59,2016-03-29,1,138.3444,1.50%,0.15%,1,0.15%,1,268.34",
"400015,東方新能源汽車混合,DFXNYQCHH,2021-07-16,4.1490,4.6090,-3.93,-0.55,33.22,70.17,42.06,135.85,278.83,221.85,47.79,453.21,2011-12-28,1,136.1310,1.50%,0.15%,1,0.15%,1,164.20",
"001951,金鷹改革紅利混合,JYGGHLHH,2021-07-16,3.3520,3.3520,-3.12,0.06,23.37,48.85,44.05,125.57,224.18,243.79,52.36,235.20,2015-12-02,1,119.8221,1.50%,0.15%,1,0.15%,1,209.80",
……
"700003,平安策略先鋒混合,PACLXFHH,2021-07-16,5.3350,5.4350,0.40,2.18,33.98,61.28,37.01,82.77,208.03,233.65,42.91,483.74,2012-05-29,1,71.7518,1.50%,0.15%,1,0.15%,1,180.64"],
allRecords:4476,
pageIndex:1,
pageNum:50,
allPages:90,
allNum:8252,
gpNum:1610,
hhNum:4476,
zqNum:1983,
zsNum:1164,
bbNum:0,
qdiiNum:183,
etfNum:0,
lofNum:330,
fofNum:169
};
看起來(lái)這是我們要的數(shù)據(jù)了撼嗓,但這個(gè)數(shù)據(jù)還不能被python直接識(shí)別到,因?yàn)榍懊嬗幸欢?*var rankData = * 的鬼東西欢唾。這個(gè)東西是js代碼且警,對(duì)他們網(wǎng)站的前端游泳,但是對(duì)我們毫無(wú)意義礁遣。仔細(xì)分析一下拿到的數(shù)據(jù)發(fā)現(xiàn)斑芜,我們需要的其實(shí)是datas后面的 [ …… ] 里面的東西。數(shù)據(jù)的最后面還有一段allRecords:4476,pageIndex:1,pageNum:50,allPages:90,allNum:8252,gpNum:1610,hhNum:4476,zqNum:1983,zsNum:1164,bbNum:0,qdiiNum:183,etfNum:0,lofNum:330,fofNum:169亡脸。這些是一些參數(shù)值押搪,后面我們都用得著,所以我們干脆把 {……}都弄出來(lái)浅碾,這個(gè)結(jié)構(gòu)和python中的dict結(jié)構(gòu)是一樣的大州。所以,我們只需要把前面的 “var rankData =”去掉就好了垂谢,來(lái)看代碼:
# 截取第14個(gè)字符到倒數(shù)第一個(gè)字符之間的所有內(nèi)容厦画,注意,最后還有一個(gè);號(hào)也要去掉
js_data = response.text[14:-1]
# 把得到的{···}轉(zhuǎn)成dict對(duì)象滥朱。這里我們用到了第三方庫(kù)execjs根暑,沒(méi)有的同學(xué)自己pip install一下
dt = execjs.eval(js_data)
到這里,我們才算真正白嫖到了網(wǎng)站的數(shù)據(jù)徙邻。那么有了數(shù)據(jù)排嫌,接下來(lái)就是分析了。Python以爬蟲和數(shù)據(jù)分析著稱缰犁,而說(shuō)到數(shù)據(jù)分析淳地,必須提到的就是無(wú)所不能的pandas庫(kù)。那么接下來(lái)就來(lái)教大家如何用pandas進(jìn)行數(shù)據(jù)分析帅容。
2. 分析數(shù)據(jù)
前文我們已經(jīng)拿到了網(wǎng)站數(shù)據(jù)并且放到了一個(gè)叫做dt的字典中颇象。但是真正我們需要的數(shù)據(jù)在dt的一個(gè)叫做datas的字段中,這個(gè)數(shù)據(jù)是一個(gè)數(shù)組并徘,我們只需要把它取出來(lái)丟給pandas就可以了遣钳,代碼也非常的簡(jiǎn)單:
import pandas as pd
em_data = pd.DataFrame(dt['datas'])
來(lái)看看我們得到的DataFrame是什么樣的
很奇怪,數(shù)據(jù)的行數(shù)沒(méi)問(wèn)題麦乞,但是只有一列蕴茴,這是什么原因劝评?先回去看看拿到的數(shù)據(jù):
"000209,信誠(chéng)新興產(chǎn)業(yè)混合,XCXXCYHH,2021-07-16,4.6530,4.6530,-1.81,1.35,35.38,68.71,53.97,153.16,301.12,277.07,60.84,365.30,2013-07-17,1,142.1564,1.50%,0.15%,1,0.15%,1,157.36",
"002190,農(nóng)銀新能源主題,NYXNYZT,2021-07-16,3.8259,3.8259,-3.01,0.54,25.48,53.12,36.05,140.99,352.02,288.26,37.18,282.59,2016-03-29,1,138.3444,1.50%,0.15%,1,0.15%,1,268.34"
為了方便,我截取了前面兩條數(shù)據(jù)荐开,并且做了換行處理付翁。我們看到,每條數(shù)據(jù)都被一對(duì)“”引號(hào)包起來(lái)了晃听,這是一個(gè)二維數(shù)組結(jié)構(gòu),但是pandas無(wú)法直接識(shí)別出來(lái)砰识,不過(guò)也不麻煩能扒,我們只需要做一個(gè)小小的處理就可以——對(duì)這個(gè)字段做分隔符的拆分即可:
# DataFrame的str可以自動(dòng)對(duì)每行的數(shù)據(jù)進(jìn)行處理
em_data = pd.DataFrame(dt['datas'])[0].str.split(',', expand = True)
# 字段拆分完畢后,為了便于分析辫狼,我們需要給它加上字段名初斑,以下是我不辭辛苦一個(gè)個(gè)對(duì)出來(lái)的,拿走不謝~
cols=['代碼', '名稱', '簡(jiǎn)稱', '日期','單位凈值','累計(jì)凈值','日增長(zhǎng)率','近1周','近1月','近3月','近6月','近1年','近2年','近3年','今年來(lái)','成立來(lái)', '成立日期','自定義', 'A', 'B', '手續(xù)費(fèi)', 'C', 'D', 'E', 'F']
em_data.columns = cols
這樣我們就得到了一個(gè)完美的DataFrame:
至于后面如何進(jìn)行分析膨处,就完全是個(gè)人主觀的事情了见秤,這個(gè)必須自己去學(xué)習(xí)金融知識(shí)和統(tǒng)計(jì)學(xué)知識(shí),一點(diǎn)點(diǎn)積累真椿,技術(shù)部分自己去看pandas的文檔即可鹃答,你能知道的計(jì)算方法pandas都有現(xiàn)成的函數(shù)可以直接使用,非常的強(qiáng)大突硝。
不過(guò)测摔,在拿到一個(gè)數(shù)據(jù)的初期,我喜歡先對(duì)數(shù)據(jù)進(jìn)行一個(gè)整體的了解解恰,做一個(gè)overview锋八,這里強(qiáng)烈安利一個(gè)基于pandas的庫(kù),可以幫助我們進(jìn)行數(shù)據(jù)探索——pandas_profiling护盈,使用也非常非常簡(jiǎn)單:
import pandas_profiling
pandas_profiling.ProfileReport(df)
如果你使用Jupyter Notebook編寫代碼挟纱,那么經(jīng)過(guò)短暫的等待,你就會(huì)看到一個(gè)非常驚人的交互式報(bào)告:
One more thing:優(yōu)化
到這里腐宋,基本技能已經(jīng)介紹完了紊服,但細(xì)心的同學(xué)會(huì)發(fā)現(xiàn),里面隱藏了一個(gè)小問(wèn)題脏款,就是數(shù)據(jù)量的問(wèn)題围苫。我們從開發(fā)者工具中拿到的那個(gè)url只返回了50條數(shù)據(jù),但是一共有幾千個(gè)基金撤师,這么多數(shù)據(jù)我們應(yīng)該怎么燃粮?如果每次只能取50條剃盾,5000條數(shù)據(jù)我們就要取100次腺占,不光速度慢淤袜,而且很有可能被對(duì)方的安全設(shè)備識(shí)別為DDOS攻擊。那么衰伯,有沒(méi)有更佳優(yōu)雅的解決方案呢铡羡?
還記得我們前面提過(guò)的Request參數(shù)傳遞的事情嗎?我們來(lái)分析一下這個(gè)接口的URL地址意鲸,看看能有什么發(fā)現(xiàn):
# 我把它簡(jiǎn)單處理一下烦周,在&符號(hào)后面加上換行,得到了這個(gè)東西怎顾,:
http://fund.eastmoney.com/data/rankhandler.aspx?
op=ph&
dt=kf&
ft=hh&
rs=&
gs=0&
sc=1nzf&
st=desc&
sd=2020-07-15&
ed=2021-07-15&
qdii=&
tabSubtype=,,,,,&
pi=1&
pn=50&
dx=1&
v=0.726345617727655
簡(jiǎn)單解釋一下读慎,url中的“?”號(hào)后面是請(qǐng)求的參數(shù),多個(gè)參數(shù)用&符號(hào)進(jìn)行連接槐雾。
根據(jù)參數(shù)值我們可以簡(jiǎn)單得到以下猜測(cè):
- sd:start date 開始日期
- ed:end date 結(jié)束日期
- pi:page index 所在分頁(yè)的頁(yè)數(shù)
- pn:page number 每頁(yè)的數(shù)量
剩下的參數(shù)感興趣的同學(xué)可以自己去研究夭委,pi和pn應(yīng)該就是我們可以利用的地方。如果pn沒(méi)有上限限制募强,那么我們就可以一次性拿到所有的數(shù)據(jù)了株灸,我測(cè)試了4476,也就是所有的混合基金的數(shù)量擎值,順利拿到了所有的數(shù)據(jù)慌烧。
既然,我們摸清楚了這個(gè)接口的一些參數(shù)幅恋,是不是可以把它封裝成一個(gè)python的function呢杏死?說(shuō)干就干,以下是完整的代碼:
import pandas as pd
import requests
import execjs
def get_eastMoney(start_date='2020-07-15', end_date='2020-07-15', page_index=1, page_number=50, fund_type='all', sc='6yzf'):
"""
:param start_date:
:param end_date:
:param page_index:
:param page_number:
:param fund_type: 基金類型捆交,hh為混合淑翼,all為全部
:param sc: 排序規(guī)則,6yzf為近六個(gè)月品追,1nzf為近1年
:return:
"""
url = 'http://fund.eastmoney.com/data/rankhandler.aspx?op=ph&dt=kf&rs=&gs=0&st=desc&qdii=&tabSubtype=,,,,,&dx=1&v=0.5137439179039982'
cols=['代碼', '名稱', '簡(jiǎn)稱', '日期','單位凈值','累計(jì)凈值','日增長(zhǎng)率','近1周','近1月','近3月','近6月','近1年','近2年','近3年','今年來(lái)','成立來(lái)', '成立日期','自定義', 'A', 'B', '手續(xù)費(fèi)', 'C', 'D', 'E', 'F']
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36',
'Host': 'fund.eastmoney.com',
'Accept-Encoding': 'gzip, deflate',
'Referer': 'http://fund.eastmoney.com/data/fundranking.html'
}
params = {
'ft': fund_type,
'sd': start_date,
'ed': end_date,
'pi': page_index,
'pn': page_number,
'sc': sc
}
response = requests.get(url, headers=headers, params=params)
js_data = response.text[14:-1]
dt = execjs.eval(js_data)
print('allRecords: ', dt['allRecords'])
em_data = pd.DataFrame(dt['datas'])[0].str.split(',', expand = True)
em_data.columns = cols
return em_data
df = get_eastMoney(fund_type='hh', page_number=500)
經(jīng)過(guò)一個(gè)簡(jiǎn)單的封裝玄括,我們就有了自己的python的函數(shù),以后我們只要通過(guò)一行代碼就可以得到想要的數(shù)據(jù)肉瓦。