一篇文章详细讲解爬虫入门,以爬取基金净值为例|Python 主题月

1,590 阅读5分钟

本文正在参加「Python主题月」,详情查看[活动链接]

序言

    最近工作稳定了下来,手头上的闲钱也变多了,每天放在银行,收益小的不忍直视,每天上班的心情都没了,都在想着怎么提高收益。我在有一天午饭的时候看到了身边的同事各个都在买基金,顿时也想入这个坑了,真的是意识到了理财的重要性,每天下班了也不看什么源码、JVM这些课程了,而是开始去看一些B站的财经视频的科普。

image-20210719132709612.png

    要想分析基金,从几千只基金里面挑选出一只好基金,那肯定少不了历年的数据,作为一名程序员,为了分析方便,我还是觉得先把所有的数据爬下来,然后再做进一步处理。但是怎么获取数据处理数据呢?莫非是要一条条自己看,然后那笔写下来?达咩,这是不可能的。

image-20210719132759115.png

我选取了爬虫这种比较常见的新兴技术,去简单学习了一下Python后就开始自己写爬虫程序开始,给爷爬!

image-20210719133031745.png

分析

    爬数据需要先思考从哪里爬?经过一番搜索和考虑,我发现天天基金网的数据既比较全,又十分容易爬取,所以就从它入手了。

    我们随便选取一只去年的人气王—招商中证白酒(161725),上面有他的各种信息。

    我使用的是chrome浏览器,按住F12可以进入到开发者模式,选择Network,在刷新一下就可以看到普通人看不到的一面。我们在Network下面拉一点可以看到基金代码.js?v开头的,点开他可以看到旁边的URL请求地址:http://fund.eastmoney.com/pingzhongdata/161725.js?v=20210719125054,也就是说我们可以简单的通过http://fund.eastmoney.com/pingzhongdata/基金代码.js?v=当前时间这样一个接口就能获取到相应的数据了。

image-20210719130352355.png

        我们点开旁边的Preview,我滴乖乖,原来我们需要的数据都藏在这里。

image-20210719130802396.png

开始实战

引入模块

    现在接口有了,数据分析也有了,就是http://fund.eastmoney.com/pingzhongdata/基金代码.js?v=当前时间

    通过基金代码当前时间我们就能够获取到相应的数据,接下来就是需要将我们想要的数据从获取的文件中提取出来了,也就是我们说的数据清洗的过程。     这个网站提供的数据不是常见的json格式,因此提取会有点麻烦,比如通过字符串查找等,但是由于这个是js文件,因此,我找到了更合适的方法——利用了PyExecJs模块就能很方便地编译解析js代码啦。

    首先我们需要在终端安装PyExecJs这个模块。

pip install PyExecJs

    然后引入这些模块

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

获取净值

def getWorth(fscode):
    #用requests获取到对应的文件
    content = requests.get(getUrl(fscode))
    
   #使用execjs获取到相应的数据
    jsContent = execjs.compile(content.text)
    name = jsContent.eval('fS_name')
    code = jsContent.eval('fS_code')
    #单位净值走势
    netWorthTrend = jsContent.eval('Data_netWorthTrend')
    #累计净值走势
    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

查看数据

    这样我们就可以通过基金代码来查到对应的数据啦。

netWorth, ACWorth = getWorth('161725')
print(netWorth)

image-20210719131518396.png

    我们可以看到结果确实没错,第一个就是今天的单位净值。

    当然,我们也可以自己画一个走势图来验证一下。

import matplotlib.pyplot as plt
plt.figure(figsize=(10,5))
plt.plot(netWorth[:60][::-1])
plt.show()

image-20210719131645709.png

    下面给出源代码。

import requests
import time
import execjs
import matplotlib.pyplot as plt
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获取到对应的文件
    content = requests.get(getUrl(fscode))
    
   #使用execjs获取到相应的数据
    jsContent = execjs.compile(content.text)
    name = jsContent.eval('fS_name')
    code = jsContent.eval('fS_code')
    #单位净值走势
    netWorthTrend = jsContent.eval('Data_netWorthTrend')
    #累计净值走势
    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

netWorth, ACWorth = getWorth('161725')

plt.figure(figsize=(10,5))
plt.plot(netWorth[:60][::-1])
plt.show()

获取所有基金数据

    这里我通过同样的方式,找到了所有基金列表的接口。 通过'http://fund.eastmoney.com/js/fundcode_search.js'便可以直接获取到所有的基金代码,再通过基金代码可以遍历爬取所有基金的数据,我将下载的数据存成了csv,方便excel打开或用代码读取。

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

# 根据基金代码获取净值
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')
    #累计净值走势
    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()