好买基金优质基金的提取分析
一、选题的背景
为什么要选择此选题?
要达到的数据分析的预期目标是什么?(10 分)
从社会、经济、技术、数据来源等方面进行描述(200 字以内)
随着时间的推移,人民币是不断的贬值的,可能今天100块值100块,明天就只价值90了,所以学习如何理财是人生的主要课程,本次课程设计我选取了好买基金网的各类基金近一周的前十基金进行信息获取和数据分析,为我们选取基金理财具有一定的了解作用,预期目标是能通过信息获取的方式了解到近期的热门行业和对优质基金的选取,了解基金的普遍年化收益和基金投资是否有价值,了解基金的年化风险和收益,技术上面用request获取网页信息,用beautifulsoup对网页进行解析,并利用一些算法从中提取我们需要的数据
二、主题式网络爬虫设计方案(10 分)
1.主题式网络爬虫名称
好买基金优质基金的提取分析
主页面url= 'https://www.howbuy.com/fund/',主页面来爬取基金的链接,爬取的数据是在url='https://www.howbuy.com/fund/'+基金代码的链接页面中的
2.主题式网络爬虫爬取的内容与数据特征分析
我们将通过好买网提取每个基金的基金代码、基金名称、单位净值、涨跌幅、基金排名、3月涨幅、1年涨幅、基金规模、成立日期、所属行业,他们的特征是在各个网页中html静态页面中有他们的数据,可以进行简单爬取
3.主题式网络爬虫设计方案概述(包括实现思路与技术难点)
首先我们在好买网查看各个基金的名称,打开网页源码进行搜索查看是否在静态页面里面可以找到,然后我们找到单个基金的超链接,并查看源码,发现静态页面中也有基金的数据,所以我们可以用简单的静态页面分析和加工来提取其中数据。技术的难点是做一半发现其中的一些单个基金超链接页面里面的标签和别的基金不一样,需要进行一点的修改来完成项目,比较耗时
网页数据查找的图片,如下图所示


下面是网页首页和爬取的未经处理的网页文本,划红线地方表示需要的主页面基金的链接和代表的单个基金


三、主题页面的结构特征分析(10 分)
1.主题页面的结构与特征分析
2.Htmls 页面解析
3.节点(标签)查找方法与遍历方法 (必要时画出节点树结构)

如上图所示是单个基金页面的数据,在html静态页面中包含了他们的所有数据,观察这些数据的位置我们可以看出他们是在HTML页面中的一些标签中的,而且这些标签可以通过他们的一些属性精确定位提取数据,比如单位净值可以通过beautifulsoup的find("div",cRed).string来获取,基金名称可以通过h1标签获取,涨跌幅可以通过上级标签属性cRed b-3来定位获取等

页面的节点树如上图所示,可以通过标签来进行遍历和查找,比如em的涨跌幅可以通过定位某个div的属性,再通过em的标签特点来获取最终数据,可以通过逐步提取的方法来获得信息,有一些标签他没有属性值,我们可以通过他的上一级标签获取之后进行切片获取来提取数据
四、网络爬虫程序设计(60 分)
爬虫的代码如下
1 import requests 2 import re 3 from bs4 import BeautifulSoup 4 import re 5 import matplotlib.pyplot as plt 6 import jieba 7 from wordcloud import WordCloud 8 from PIL import Image 9 import numpy as np 10 jieba.setLogLevel(jieba.logging.INFO) 11 #-------------------------------------------------------------------- 12 #爬虫部分 13 #获取网页信息的函数 14 def getHTMLText(jiurl): 15 try: 16 response = requests.get(jiurl) 17 response.raise_for_status() 18 response.encoding = response.apparent_encoding 19 print("访问成功:",jiurl) 20 return response.text 21 except: 22 return "失败" 23 24 def getjiInfo(jiurl,allinfo): 25 #用来放基金代码的容器 26 lst=[] 27 g=getHTMLText(jiurl) 28 soup = BeautifulSoup(g, 'html.parser') 29 #寻找td标签 属性为width="27%"的基金代码 30 t= soup.find_all('td',width="27%") 31 for i in t: 32 #用来放一个基金的信息的容器 33 part=[] 34 #获取td标签下的a标签下的属性为href的值 35 href = i.a.attrs['href'] 36 #[0]是为了放进lst的是字符串 37 lst.append(re.findall(r"\d{6}", href)[0]) 38 #把刚获取的基金代码放入容器里 39 part.append(lst[-1]) 40 num=lst[-1] 41 #jiurld是单个基金的地址 42 jiurld = jiurl+num 43 g2 = getHTMLText(jiurld) 44 soup = BeautifulSoup(g2, 'html.parser') 45 h=soup.h1 46 hstr=str(h) 47 #由于h1里的基金名称里面还有一个span标签所以不能用.string,用切片的方法获取 48 name='' 49 for i in hstr[4:-1]: 50 if i!='<': 51 name+=i 52 else: 53 break 54 #基金名称放入容器里面 55 part.append(name) 56 #由于后来发现单位净值的一些标签class属性为cGreen,下面做以下操作try 57 try: 58 #获取单位净值 59 dwjz=soup.find('div', attrs={'class': 'cRed'}) 60 part.append(eval(dwjz.string)) 61 except: 62 dwjz = soup.find('div', attrs={'class': 'cGreen'}) 63 part.append(eval(dwjz.string)) 64 #获取em标签的属性class:b-rate的单日涨跌幅和基金行业排名 65 zdf = soup.find_all('em', attrs={'class': 'b-rate'}) 66 for i in zdf: 67 part.append(i.string) 68 #排名和参加排名的基金是分开获取的,下面进行整合操作 69 pop1=part.pop(-1) 70 pop2=part.pop(-1) 71 part.append(pop2+pop1) 72 #获取三月和一年的涨跌幅 73 threey = soup.find_all('li', attrs={'class': 'point'}) 74 #用作测试是否基金成立超过一年或者3个月的容器 75 cwroom=[] 76 for i in threey: 77 # 由于一些基金成立不确定有没有超过一年或者3个月,为程序正常运行用try方法 78 try: 79 cwroom.append(i.span.string) 80 except: 81 continue 82 #值为2说明有超过一年 83 if len(cwroom)==2: 84 for i in threey: 85 part.append(i.span.string) 86 #值为2说明没有超过一年 87 elif len(cwroom)==1: 88 #用作定值输入的标志 89 mark2=0 90 for i in threey: 91 part.append(i.span.string) 92 mark2+=1 93 if mark2==1: 94 part.append('--') 95 break 96 else: 97 for i in range(2): 98 part.append('--') 99 #获取基金规模和发行的日期 100 zxgm = soup.find_all('ul', attrs={'class':'clearfix'}) 101 #用来获取标签ul,属性class;clearfix的信息的容器 102 room=[] 103 #定点获取基金规模和发行的日期的标志 104 mark3=0 105 #一个用来获取所属行业的计数标 106 for i in zxgm: 107 mark3+=1 108 if mark3==2: 109 for j in i: 110 #部分标签中没有string内容,为防止程序报错中断用try方法 111 try: 112 room.append(j.span.string) 113 except: 114 continue 115 # 下面用截取room容器中需要的信息来实现提取 116 part.append(room[-2]) 117 part.append(room[-1]) 118 #获取所属行业 119 hy = soup.find_all('ul', attrs={'class': 'fund_tags clearfix'}) 120 #一个定点获取所属行业的游标 121 mark=0 122 #因为每个网页的数据不一致,设置一个筛选的容器 123 sxuan=[] 124 for i in hy: 125 for j in i: 126 mark = mark + 1 127 #观察发现所属行业和评价的游标在4、8 128 if mark==2: 129 sxuan.append(j.string) 130 elif mark==4: 131 sxuan.append(j.string) 132 elif mark ==6: 133 sxuan.append(j.string) 134 elif mark==8: 135 sxuan.append(j.string) 136 #是否有说明行业的标志 137 mark4=0 138 for s in sxuan: 139 if s in jiHye: 140 part.append(s) 141 mark4+=1 142 if mark4==0: 143 part.append("未说明") 144 #所有的单个基金的信息都放进总容器内 145 allinfo.append(part) 146 147 #所有行业 148 jiHye=["农林牧渔","食品饮料","生物医药","建筑材料","房地产" ,'家用电器', '电子', '公用事业', '重组', '交通运输' ,'医药生物',\ 149 '轻工制造', '高铁', '采掘', '休闲服务', '汽车', '传媒', '美丽中国', '国资改革', '计算机', '纺织服装','银行','建筑装饰',\ 150 '银行','建筑装饰','国防军工' ,'一带一路' ,'非银金融', '移动互联网' ,'机械设备' , '通信' ,'环保概念' , '化工' , '钢铁' ,\ 151 '高端装备制造','有色金属' ,'电气设备' ,'综合'] 152 153 # 存放所有基金信息的总容器 154 allinfo = [] 155 def main(): 156 #爬取的网页地址 157 jiurl = 'https://www.howbuy.com/fund/' 158 getjiInfo(jiurl,allinfo) 159 160 main() 161 162 #输出效果 163 ges = "{:<5}\t{:<18}\t{:<5}\t{:<4}\t{:<7}\t{:<5}\t{:<5}\t{:<5}\t{:<7}\t{:<4}" 164 print(ges.format("基金代码", "基金名称", "单位净值", "涨跌幅", "基金排名","3月涨幅","1年涨幅","基金规模","成立日期","所属行业")) 165 for ai in allinfo: 166 print(ges.format(ai[0], ai[1], ai[2], ai[3], ai[4], ai[5], ai[6], ai[7], ai[8], ai[9]))
爬取的效果图如下

词云的代码如下
1 #-------------------------------------------------------------------------------- 2 #jieba wordcloud部分 3 4 #用来装基金名称的容器 5 jieroom=[] 6 #所属行业的容器 7 jieroom2=[] 8 for j in allinfo: 9 jieroom.append(j[1]) 10 jieroom2.append(j[-1]) 11 strjieroom2=' '.join(jieroom2) 12 13 #基金名称 对jieba分词的容器 14 jieroomOk=[] 15 for i in jieroom: 16 j=jieba.lcut(i) 17 #除杂操作,对无用字符进行清洗 18 jieroomOk.extend(j) 19 strjieroom=' '.join(jieroomOk) 20 21 # 打开图片 22 mg = Image.open("d:\\rooms\\love.jpg") 23 # 将图片装换为数组 24 img_array = np.array(mg) 25 stopword={'未说明'} 26 wc = WordCloud(font_path='D:\\rooms\\SimHei.ttf', # 设置字体 27 background_color="black", # 背景颜色 28 max_words=2000, # 词云显示的最大词数 29 mask=img_array , # 设置背景图片 30 max_font_size=100, # 字体最大值 31 stopwords=stopword, 32 ) 33 34 #所属行业的分词 35 wc.generate(strjieroom2) 36 # 以下代码显示图片 37 plt.imshow(wc) 38 plt.axis("off") 39 plt.show() 40 # 保存图片到需要的位置 41 wc.to_file('d:/wordcloud2.png') 42 43 #所属行业的分词 44 wc.generate(strjieroom) 45 # 以下代码显示图片 46 plt.imshow(wc) 47 plt.axis("off") 48 plt.show() 49 # 保存图片到需要的位置 50 wc.to_file('d:/wordcloud3.png')
词云效果图如下


数据可视化代码如下
1 #------------------------------------------------------------------------- 2 #数据分析和可视化操作 3 4 #所选基金的年收益率的比例的扇形图 5 #所有基金的年收益率 6 oneySY=[] 7 for i in allinfo: 8 oneySY.append(i[-4]) 9 sy20j=0 10 sy15j=0 11 sy10j=0 12 sy5j=0 13 sy0j=0 14 syf5=0 15 syf10=0 16 syf15=0 17 for i in oneySY: 18 if i!='--': 19 onestr=float(i[:-1]) 20 if -15.0 <= onestr < -10.0: 21 syf15 += 1 22 elif -10.0 <= onestr < -5.0: 23 syf10+= 1 24 elif -5.0 <= onestr< 0.0: 25 syf5 += 1 26 elif 0.0 <= onestr < 5.0: 27 sy0j+= 1 28 elif 5.0 <= onestr< 10.0: 29 sy5j += 1 30 elif 10.0 <= onestr< 15.0: 31 sy10j += 1 32 elif 15.0 <= onestr< 20.0: 33 sy15j += 1 34 elif onestr>=20.0: 35 sy20j+=1 36 numberroom= [syf15,syf10,syf5,sy0j,sy5j,sy10j,sy15j,sy20j] 37 labels = ['-15--10','-10--5','-5-0','0-5', '5-10','10-15','15-20','20+'] 38 # 用Matplotlib制作可视化饼图 39 plt.pie(x = numberroom, labels=labels) 40 plt.show()
所选基金的年收益率的比例的扇形图

散点图的代码如下
1 #关于基金单日净值和基金规模的散点图 2 x=[] 3 y=[] 4 for i in allinfo: 5 x.append(i[2]) 6 y.append(i[-3][:-1]) 7 # 用Matplotlib画散点图 8 plt.scatter(x, y,marker='*') 9 plt.show()
散点图效果如下

数据持久化的代码如下
1 #数据持久化 写入csv文件 2 import csv 3 file = open('d:\\ji.csv','w',newline='',encoding='gb18030') 4 writer = csv.writer(file) 5 for i in allinfo: 6 writer.writerow(i) 7 file.close()
文件中的效果如下

下面是完整代码
1 import requests 2 import re 3 from bs4 import BeautifulSoup 4 import re 5 import matplotlib.pyplot as plt 6 import jieba 7 from wordcloud import WordCloud 8 from PIL import Image 9 import numpy as np 10 jieba.setLogLevel(jieba.logging.INFO) 11 #-------------------------------------------------------------------- 12 #爬虫部分 13 #获取网页信息的函数 14 def getHTMLText(jiurl): 15 try: 16 response = requests.get(jiurl) 17 response.raise_for_status() 18 response.encoding = response.apparent_encoding 19 print("访问成功:",jiurl) 20 return response.text 21 except: 22 return "失败" 23 24 def getjiInfo(jiurl,allinfo): 25 #用来放基金代码的容器 26 lst=[] 27 g=getHTMLText(jiurl) 28 soup = BeautifulSoup(g, 'html.parser') 29 #寻找td标签 属性为width="27%"的基金代码 30 t= soup.find_all('td',width="27%") 31 for i in t: 32 #用来放一个基金的信息的容器 33 part=[] 34 #获取td标签下的a标签下的属性为href的值 35 href = i.a.attrs['href'] 36 #[0]是为了放进lst的是字符串 37 lst.append(re.findall(r"\d{6}", href)[0]) 38 #把刚获取的基金代码放入容器里 39 part.append(lst[-1]) 40 num=lst[-1] 41 #jiurld是单个基金的地址 42 jiurld = jiurl+num 43 g2 = getHTMLText(jiurld) 44 soup = BeautifulSoup(g2, 'html.parser') 45 h=soup.h1 46 hstr=str(h) 47 #由于h1里的基金名称里面还有一个span标签所以不能用.string,用切片的方法获取 48 name='' 49 for i in hstr[4:-1]: 50 if i!='<': 51 name+=i 52 else: 53 break 54 #基金名称放入容器里面 55 part.append(name) 56 #由于后来发现单位净值的一些标签class属性为cGreen,下面做以下操作try 57 try: 58 #获取单位净值 59 dwjz=soup.find('div', attrs={'class': 'cRed'}) 60 part.append(eval(dwjz.string)) 61 except: 62 dwjz = soup.find('div', attrs={'class': 'cGreen'}) 63 part.append(eval(dwjz.string)) 64 #获取em标签的属性class:b-rate的单日涨跌幅和基金行业排名 65 zdf = soup.find_all('em', attrs={'class': 'b-rate'}) 66 for i in zdf: 67 part.append(i.string) 68 #排名和参加排名的基金是分开获取的,下面进行整合操作 69 pop1=part.pop(-1) 70 pop2=part.pop(-1) 71 part.append(pop2+pop1) 72 #获取三月和一年的涨跌幅 73 threey = soup.find_all('li', attrs={'class': 'point'}) 74 #用作测试是否基金成立超过一年或者3个月的容器 75 cwroom=[] 76 for i in threey: 77 # 由于一些基金成立不确定有没有超过一年或者3个月,为程序正常运行用try方法 78 try: 79 cwroom.append(i.span.string) 80 except: 81 continue 82 #值为2说明有超过一年 83 if len(cwroom)==2: 84 for i in threey: 85 part.append(i.span.string) 86 #值为2说明没有超过一年 87 elif len(cwroom)==1: 88 #用作定值输入的标志 89 mark2=0 90 for i in threey: 91 part.append(i.span.string) 92 mark2+=1 93 if mark2==1: 94 part.append('--') 95 break 96 else: 97 for i in range(2): 98 part.append('--') 99 #获取基金规模和发行的日期 100 zxgm = soup.find_all('ul', attrs={'class':'clearfix'}) 101 #用来获取标签ul,属性class;clearfix的信息的容器 102 room=[] 103 #定点获取基金规模和发行的日期的标志 104 mark3=0 105 #一个用来获取所属行业的计数标 106 for i in zxgm: 107 mark3+=1 108 if mark3==2: 109 for j in i: 110 #部分标签中没有string内容,为防止程序报错中断用try方法 111 try: 112 room.append(j.span.string) 113 except: 114 continue 115 # 下面用截取room容器中需要的信息来实现提取 116 part.append(room[-2]) 117 part.append(room[-1]) 118 #获取所属行业 119 hy = soup.find_all('ul', attrs={'class': 'fund_tags clearfix'}) 120 #一个定点获取所属行业的游标 121 mark=0 122 #因为每个网页的数据不一致,设置一个筛选的容器 123 sxuan=[] 124 for i in hy: 125 for j in i: 126 mark = mark + 1 127 #观察发现所属行业和评价的游标在4、8 128 if mark==2: 129 sxuan.append(j.string) 130 elif mark==4: 131 sxuan.append(j.string) 132 elif mark ==6: 133 sxuan.append(j.string) 134 elif mark==8: 135 sxuan.append(j.string) 136 #是否有说明行业的标志 137 mark4=0 138 for s in sxuan: 139 if s in jiHye: 140 part.append(s) 141 mark4+=1 142 if mark4==0: 143 part.append("未说明") 144 #所有的单个基金的信息都放进总容器内 145 allinfo.append(part) 146 147 #所有行业 148 jiHye=["农林牧渔","食品饮料","生物医药","建筑材料","房地产" ,'家用电器', '电子', '公用事业', '重组', '交通运输' ,'医药生物',\ 149 '轻工制造', '高铁', '采掘', '休闲服务', '汽车', '传媒', '美丽中国', '国资改革', '计算机', '纺织服装','银行','建筑装饰',\ 150 '银行','建筑装饰','国防军工' ,'一带一路' ,'非银金融', '移动互联网' ,'机械设备' , '通信' ,'环保概念' , '化工' , '钢铁' ,\ 151 '高端装备制造','有色金属' ,'电气设备' ,'综合'] 152 153 # 存放所有基金信息的总容器 154 allinfo = [] 155 def main(): 156 #爬取的网页地址 157 jiurl = 'https://www.howbuy.com/fund/' 158 getjiInfo(jiurl,allinfo) 159 160 main() 161 162 #-------------------------------------------------------------------------------- 163 #jieba wordcloud部分 164 165 #用来装基金名称的容器 166 jieroom=[] 167 #所属行业的容器 168 jieroom2=[] 169 for j in allinfo: 170 jieroom.append(j[1]) 171 jieroom2.append(j[-1]) 172 strjieroom2=' '.join(jieroom2) 173 174 #基金名称 对jieba分词的容器 175 jieroomOk=[] 176 for i in jieroom: 177 j=jieba.lcut(i) 178 #除杂操作,对无用字符进行清洗 179 jieroomOk.extend(j) 180 strjieroom=' '.join(jieroomOk) 181 182 # 打开图片 183 mg = Image.open("d:\\rooms\\love.jpg") 184 # 将图片装换为数组 185 img_array = np.array(mg) 186 stopword={'未说明'} 187 wc = WordCloud(font_path='D:\\rooms\\SimHei.ttf', # 设置字体 188 background_color="black", # 背景颜色 189 max_words=2000, # 词云显示的最大词数 190 mask=img_array , # 设置背景图片 191 max_font_size=100, # 字体最大值 192 stopwords=stopword, 193 ) 194 195 #所属行业的分词 196 wc.generate(strjieroom2) 197 # 以下代码显示图片 198 plt.imshow(wc) 199 plt.axis("off") 200 plt.show() 201 # 保存图片到需要的位置 202 wc.to_file('d:/wordcloud2.png') 203 204 #所属行业的分词 205 wc.generate(strjieroom) 206 # 以下代码显示图片 207 plt.imshow(wc) 208 plt.axis("off") 209 plt.show() 210 # 保存图片到需要的位置 211 wc.to_file('d:/wordcloud3.png') 212 213 #------------------------------------------------------------------------- 214 #数据分析和可视化操作 215 216 #所选基金的年收益率的比例的扇形图 217 #所有基金的年收益率 218 oneySY=[] 219 for i in allinfo: 220 oneySY.append(i[-4]) 221 sy20j=0 222 sy15j=0 223 sy10j=0 224 sy5j=0 225 sy0j=0 226 syf5=0 227 syf10=0 228 syf15=0 229 for i in oneySY: 230 if i!='--': 231 onestr=float(i[:-1]) 232 if -15.0 <= onestr < -10.0: 233 syf15 += 1 234 elif -10.0 <= onestr < -5.0: 235 syf10+= 1 236 elif -5.0 <= onestr< 0.0: 237 syf5 += 1 238 elif 0.0 <= onestr < 5.0: 239 sy0j+= 1 240 elif 5.0 <= onestr< 10.0: 241 sy5j += 1 242 elif 10.0 <= onestr< 15.0: 243 sy10j += 1 244 elif 15.0 <= onestr< 20.0: 245 sy15j += 1 246 elif onestr>=20.0: 247 sy20j+=1 248 numberroom= [syf15,syf10,syf5,sy0j,sy5j,sy10j,sy15j,sy20j] 249 labels = ['-15--10','-10--5','-5-0','0-5', '5-10','10-15','15-20','20+'] 250 # 用Matplotlib制作可视化饼图 251 plt.pie(x = numberroom, labels=labels) 252 plt.show() 253 254 #关于基金单日净值和基金规模的散点图 255 x=[] 256 y=[] 257 for i in allinfo: 258 x.append(i[2]) 259 y.append(i[-3][:-1]) 260 # 用Matplotlib画散点图 261 plt.scatter(x, y,marker='*') 262 plt.show() 263 264 #数据持久化 写入csv文件 265 import csv 266 file = open('d:\\ji.csv','w',newline='',encoding='gb18030') 267 writer = csv.writer(file) 268 for i in allinfo: 269 writer.writerow(i) 270 file.close() 271 272 #输出效果 273 ges = "{:<5}\t{:<18}\t{:<5}\t{:<4}\t{:<7}\t{:<5}\t{:<5}\t{:<5}\t{:<7}\t{:<4}" 274 print(ges.format("基金代码", "基金名称", "单位净值", "涨跌幅", "基金排名","3月涨幅","1年涨幅","基金规模","成立日期","所属行业")) 275 for ai in allinfo: 276 print(ges.format(ai[0], ai[1], ai[2], ai[3], ai[4], ai[5], ai[6], ai[7], ai[8], ai[9]))
五、总结(10 分)
1.经过对主题数据的分析与可视化,可以得到哪些结论?是否达到预期的目标?
通过数据的分析和可视化可以得到结论:多数基金类型是指数型、偏股、QDII的,近一周的热门行业是农林牧渔、医药生物、食品饮料等,近一周的优质基金公司是汇添富和开源,年化收益在20以上的基金超过一半以上,基金年化收益为负数的概率是极小的,所以基金投资大致是一种低风险有较高收益的行为,已经达到预期的目标
2.在完成此设计过程中,得到哪些收获?以及要改进的建议?
完成里本次课程设计,对爬虫有了更深刻的了解,并对基金的属性有了更深刻的了解,将来可以用爬虫不断获取近期的优质基金实现成功理财。最大的改进建议是以后爬虫单个页面得取多个例子来观察发现其中的稳定规律,提高爬虫的效率

浙公网安备 33010602011771号