Python高级应用程序设计任务
Posted Zhouliangyi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python高级应用程序设计任务相关的知识,希望对你有一定的参考价值。
Python高级应用程序设计任务要求
用Python实现一个面向主题的网络爬虫程序,并完成以下内容:
(注:每人一题,主题内容自选,所有设计内容与源代码需提交到博客园平台)
一、主题式网络爬虫设计方案(15分)
1.主题式网络爬虫名称
《Python爬虫之国家统计局相关数据的爬取及分析》
2.主题式网络爬虫爬取的内容与数据特征分析
爬取内容:本次对于“国家统计局”网站爬取的内容是:自改革开放即(1978年)以来到2018年“国内生产总值(亿元)”、“国内生产总值增长(百分点)”、”人均国内生产总值(元)“和“人均国内生产总值指数(1978年=100)”
数据特征分析:“国内生产总值(亿元)”、“国内生产总值增长(百分点)”、”人均国内生产总值(元)“和“人均国内生产总值指数(1978年=100)”整体呈现上升的趋势,可通过后续绘制直方图、折线图等观察数据的变化情况。
3.主题式网络爬虫设计方案概述(包括实现思路与技术难点)
本次主题式网络爬虫不仅包括了对网站的爬取,也包括对所爬取数据的清洗及分析,对我们的个人能力是一次巨大的提升。本次要爬取的“国家统计局”网站的相关内容,进行网站爬取首要先了解该网站的页面结构,通过分析,该网站的表单属于后台js提交的方式,也就是所谓的动态网页,传统的对于静态网页是爬取方法是行不通的,再对页面进一步分析后,发现元素审查后可获取到后台表单提交的URL,通过该URL可进行后续的爬取工作。后续将所爬取到的内容以excel的形式保存到本地电脑上,以实现数据的持久化,再通过该excel进行数据的清洗及分析,提取所爬取的目标内容,绘制对应图形,得出相应结论。
技术难点:对动态网站的数据获取的URL难发现、所要的爬取的数据分布在网页的不同深度并且2017-2018年数据的搜索方式与之前年份搜索方式不一样、2018年中有一条所需数据空白,需通过分析补充该条数据。
二、主题页面的结构特征分析(15分)
1.主题页面的结构特征
(1)该网站的表单属于后台js提交的方式,在该网站的地址栏下所显示的html标签内容中没有显示我们想要的数据,针对动态网页的爬取,先在搜索栏中搜索“GDP”,显示了我国近两年的GDP,通过分析,所爬取目标数据分布页面的不同深度。
(2)采用页面审查元素,通过Network类别中XHR获取到了我们所需要的URL,
(3)点击该URL再点击右侧的Headers发现了目标爬取网页的完整URL,可通过requests库进行爬取。
2.Htmls页面解析
在这个所获得的完整URL中,发现‘s=GDP’中‘GDP’是我们所搜索的内容,‘p=0’中‘0’是页面的深度,通过这两者的关系可以控制搜索参数和页面的深度,编写迭代程序实现对其循环访问。
仅仅搜索‘GDP’只会显示近两年的数据,因此,需要在GDP前加上年份,通过这样的方式,可以获取到所需的年份数据,并且搜索到‘2017年GDP’和‘2018年GDP’时,无法显示出和2016年GDP及以前相同格式的表单内容,反而不带年份而采用‘GDP’方式搜索能获取到所需的内容。因此综上所述,在循环迭代时只搜索“1978年GDP——2016年GDP”,“2017年GDP和2018年GDP”的情况采用直接搜索“GDP”,搜索页面深度均相同。
3.节点(标签)查找方法与遍历方法
(必要时画出节点树结构)
将上述的链接(http://data.stats.gov.cn/search.htm?s=GDP&m=searchdata&db=&p=0)打开,显示如下:
通过对该页面下标签的解析,可以发现我们所需要的数据均以字典“Key-Value”的形式存储,其中,目标数据在键“result”对应的值中,该值以列表形式存储,在该值对应的列表中再以键值对的形式封装了数据,在其中键“data”,"db","sj","zb"对应的值正是目标数据。因此,可以通过键--->列表--->键--->目标数据。
三、网络爬虫程序设计(60分)
爬虫程序主体要包括以下各部分,要附源代码及较详细注释,并在每部分程序后面提供输出结果的截图。
1.数据爬取与采集
1 import requests 2 import json 3 import pandas as pd 4 import os 5 6 #对数据接口进行http请求,爬取目标网页的内容 7 def getHTMLText(url): 8 try: 9 r = requests.get(url, timeout = 30) #获取信息,请求超时时间为30秒 10 r.raise_for_status() #如果状态不是200,则引发异常 11 r.encoding = "utf-8" #配置编码\'utf-8\' 12 return r.text #返回url对应的页面内容 13 except: 14 return "产生异常" 15 16 #对数据JSON化,爬取目标数据 17 def filterHTMLText(lst,html): 18 try: 19 data = json.loads(html) #对HTTP响应的数据JSON化 20 result = data[\'result\'] #索引到目标标签位置 21 for i in result: #对索引出来的JSON数据进行遍历和爬取 22 target = i[\'zb\'] #爬取“指标” 23 data_time = i[\'sj\'] #爬取“数据时间” 24 value = i[\'data\'] #爬取“数值” 25 attribute = i[\'db\'] #爬取“所属栏目” 26 lst.append([target,data_time,value,attribute]) #将数据以列表的形式存放到lst里 27 return lst #返回lst列表 28 except: 29 return "网络延迟,请稍后重试" 30 31 #保存数据,生成xlsx格式文件 32 def saveHTMLText(lst): 33 try: 34 headers = [\'指标\',\'数据时间\',\'数值\',\'所属栏目\'] #对df数据类型中的columns赋值 35 index = [i for i in range(1,len(lst)+1)] #对df数据类型中的index赋值 36 df = pd.DataFrame(lst,columns=headers,index=index) #将数据列表转换为DataFrame对象 37 if not os.path.exists(\'E:\\\\Test\'): #判断磁盘里是否存在目标文件夹 38 os.makedirs(\'E:\\\\Test\') #不存在,则创建该文件夹 39 df.to_excel(\'E:\\\\Test\\\\国家统计局相关数据.xlsx\') #生成xlsx文件 40 else: 41 df.to_excel(\'E:\\\\Test\\\\data.xlsx\') 42 print("保存成功") #返回成功提示 43 except: 44 print("保存失败") #返回失败提示 45 46 #主程序 47 def main(): 48 uList = [] #存储爬取到的数据 49 for YearIndex in range(1978,2017): #遍历1978-2016年的数据 50 for PageIndex in range(0,6): #遍历每一年前6页的数据 51 url = \'http://data.stats.gov.cn/search.htm?s={0}{1}&m=searchdata&db=&p={2}\'.format(YearIndex,\'GDP\',PageIndex) 52 html = getHTMLText(url) #调用getHTMLText函数 53 filterHTMLText(uList,html) #调用filterHTMLText函数 54 for PageIndex in range(0,6): #遍历2017-2018年前6页的数据 55 url = \'http://data.stats.gov.cn/search.htm?s={0}&m=searchdata&db=&p={1}\'.format(\'GDP\',PageIndex) 56 html = getHTMLText(url) 57 filterHTMLText(uList,html) 58 saveHTMLText(uList) #调用saveHTMLText函数 59 60 #程序执行时调用主程序main() 61 if __name__ == \'__main__\': 62 main()
输出结果:
2.对数据进行清洗和处理
1 #删除excel中的无效index,避免与DataFrame中的index冲突 2 Static_Data=pd.DataFrame(pd.read_excel(\'E:\\\\Test\\\\data.xlsx\')) 3 Static_Data.drop(Static_Data.columns[0],axis = 1,inplace = True) 4 Static_Data.head(20)
输出结果:
1 #查找重复值 2 Static_Data.duplicated()
输出结果:
1 #删除重复值 2 Static_Data = Static_Data.drop_duplicates() 3 Static_Data.head(20)
输出结果:
1 #统计“数值”一列中空值的个数 2 Static_Data[\'数值\'].isnull().value_counts()
输出结果:
1 #删除“数值”一列中空值所对应的行 2 Static_Data.dropna(axis=0,how=\'any\',inplace=True) 3 Static_Data.head(50)
输出结果:
#使用describe查看统计信息 Static_Data.describe()
输出结果:
1 #根据“数据时间”一列升序 2 Static_Data.sort_values(by=\'数据时间\',axis=0,ascending=True,inplace=True) 3 Static_Data.tail(50)
输出结果:
1 #取出分析的数据:1.国内生产总值(亿元) 2 GDP = Static_Data.loc[(Static_Data[\'指标\'] == \'国内生产总值(亿元)\')&(Static_Data[\'所属栏目\'] == \'年度数据\')] 3 GDP
输出结果:
1 #取出分析的数据:2.国内生产总值增长(百分点) 2 GDP_Growth = Static_Data.loc[(Static_Data[\'指标\'] == \'国内生产总值增长(百分点)\')&(Static_Data[\'所属栏目\'] == \'年度数据\')] 3 GDP_Growth
输出结果:
1 #补充“2018年国内生产总值增长(百分点)”的数据 2 New_Data = pd.DataFrame({\'指标\':\'国内生产总值增长(百分点)\',\'数据时间\':\'2018年\',\'数值\':6.6,\'所属栏目\':\'年度数据\'},index=[2443]) 3 GDP_Growth=GDP_Growth.append(New_Data,ignore_index=False) 4 GDP_Growth
输出结果:
1 #取出分析的数据:3.人均国内生产总值(元) 2 GDP_Per_Cap = Static_Data.loc[(Static_Data[\'指标\'] == \'人均国内生产总值(元)\')&(Static_Data[\'所属栏目\'] == \'年度数据\')] 3 GDP_Per_Cap
输出结果:
1 #取出分析的数据:4.人均国内生产总值指数(1978年=100)) 2 import numpy as np 3 Static_Data[\'指标\'] = Static_Data[\'指标\'].astype(\'str\') 4 GDP_Per_Cap_Index = Static_Data.loc[Static_Data[\'指标\'].str.contains(\'人均国内生产总值指数\\(1978年\\=100\\)\')] 5 GDP_Per_Cap_Index
输出结果:
1 #将“国内生产总值(亿元)”和“国内生产总值增长(百分点)”做成index同为“数据时间”的DataFrame,并保存到本地 2 GDP_All = pd.DataFrame({\'国内生产总值(亿元)\':GDP[\'数值\'].tolist(),\'国内生产总值增长(百分点)\':GDP_Growth[\'数值\'].tolist()},index=GDP[\'数据时间\']) 3 GDP_All.to_excel(\'E:\\\\Test\\\\国内生产总值(亿元)和国内生产总值增长(百分点).xlsx\') 4 GDP_All
输出结果:
1 #将“国内生产总值(亿元)”和“国内生产总值增长(百分点)”做成index同为“数据时间”的DataFrame 2 GDP_Per = pd.DataFrame({\'人均国内生产总值(元)\':GDP_Per_Cap[\'数值\'].tolist(),\'人均国内生产总值指数(1978年=100)\':GDP_Per_Cap_Index[\'数值\'].tolist()},index=GDP_Per_Cap[\'数据时间\']) 3 GDP_Per.to_excel(\'E:\\\\Test\\\\人均国内生产总值(元)和人均国内生产总值指数(1978年=100).xlsx\') 4 GDP_Per
输出结果:
3.文本分析(可选):jieba分词、wordcloud可视化
4.数据分析与可视化
(例如:数据柱形图、直方图、散点图、盒图、分布图、数据回归分析等)
1 #绘制“国内生产总值(亿元)”的直方图 2 import matplotlib.pyplot as plt 3 import pandas as pd 4 import numpy as np 5 plt.rcParams[\'font.sans-serif\'] = [\'KaiTi\'] # 指定默认字体 6 plt.rcParams[\'axes.unicode_minus\'] = False # 解决保存图像是负号\'-\'显示为方块的问题 7 GDP_All[\'国内生产总值(亿元)\'].plot(kind=\'bar\',figsize=(15,10)) 8 plt.suptitle(\'1978年--2018年我国GDP统计直方图\',fontsize=20) 9 plt.xticks(fontsize=20) #修改x轴字体大小为20 10 plt.yticks(fontsize=20) #修改y轴字体大小为20 11 plt.xlabel(\'时间\',fontsize=20) #设置x轴标注为‘时间’,并调整字体大小 12 plt.ylabel(\'国内生产总值(亿元)\',fontsize=20) #设置y轴标注为‘国内生产总值(亿元)’,并调整字体大小 13 plt.show()
输出结果:
1 #绘制“国内生产总值增长(百分点)”的折线图 2 GDP_All[\'国内生产总值增长(百分点)\'].plot(figsize=(15,10),marker=\'o\',linewidth=2) 3 plt.suptitle(\'1978年--2018年我国GDP增长率折线图\',fontsize=20) 4 plt.xticks(fontsize=20,rotation=30) 5 plt.yticks(fontsize=20) 6 plt.xlabel(\'时间\',fontsize=20) 7 plt.ylabel(\'国内生产总值增长(百分点)\',fontsize=20) 8 plt.show()
输出结果:
1 #绘制“国内生产总值增长(百分点)”和“国内生产总值(亿元)”的联合分布图,包含拟合回归线 2 import seaborn as sns 3 sns.jointplot(x=\'国内生产总值(亿元)\',y=\'国内生产总值增长(百分点)\',data=GDP_All,height=10,kind=\'reg\') 4 plt.suptitle(\'1978年--2018年我国GDP总量与GDP增长率的联合分布图\',fontsize=20) 5 plt.xticks(fontsize=20) 6 plt.yticks(fontsize=20) 7 plt.xlabel(\'国内生产总值(亿元)\',fontsize=20) 8 plt.ylabel(\'国内生产总值增长(百分点)\',fontsize=20) 9 plt.show()
输出结果:
1 #绘制“人均国内生产总值(元)”的distplot 2 import seaborn as sns 3 plt.figure(figsize=(10,10)) 4 plt.suptitle(\'1978年--2018年我国人均国内生产总值的直方图\',fontsize=20) 5 plt.xticks(fontsize=20) 6 plt.yticks(fontsize=20) 7 plt.xlabel(\'人均国内生产总值(元)\',fontsize=20) 8 sns.distplot(GDP_Per[\'人均国内生产总值(元)\']) 9 plt.show()
输出结果:
1 #绘制“人均国内生产总值指数(1978年=100)”的折线图 2 GDP_Per[\'人均国内生产总值指数(1978年=100)\'].plot(figsize=(15,10),marker=\'o\',linewidth=2,linestyle=\'--\') 3 plt.suptitle(\'1978年--2018年我国人均GDP指数(1978年=100)折线图\',fontsize=20) 4 plt.xticks(fontsize=20) 5 plt.yticks(fontsize=20) 6 plt.xlabel(\'时间\',fontsize=20) 7 plt.ylabel(\'人均国内生产总值指数(1978年=100))\',fontsize=20) 8 plt.show()
输出结果:
1 #绘制“人均国内生产总值(元)”和“人均国内生产总值指数(1978年=100)”的线性回归图 2 sns.lmplot(\'人均国内生产总值(元)\',\'人均国内生产总值指数(1978年=100)\',data=GDP_Per,height=10) 3 plt.suptitle(\'1978年--2018年我国人均GDP指数与人均GDP的线性回归图\',fontsize=20) 4 plt.xticks(fontsize=20) 5 plt.yticks(fontsize=20) 6 plt.xlabel(\'人均国内生产总值(元)\',fontsize=20) 7 plt.ylabel(\'人均国内生产总值指数(1978年=100)\',fontsize=20) 8 plt.show()
输出结果:
5.数据持久化
在上述代码中包括了数据的持久化,将所爬取的数据包括提取分析的数据进行保存到本地磁盘为xlsx文件的处理。
6.附完整程序代码
1 import requests 2 import json 3 import pandas as pd 4 import os 5 6 #对数据接口进行http请求,爬取目标网页的内容 7 def getHTMLText(url): 8 try: 9 r = requests.get(url, timeout = 30) #获取信息,请求超时时间为30秒 10 r.raise_for_status() #如果状态不是200,则引发异常 11 r.encoding = "utf-8" #配置编码\'utf-8\' 12 return r.text #返回url对应的页面内容 13 except: 14 return "产生异常" 15 16 #对数据JSON化,爬取目标数据 17 def filterHTMLText(lst,html): 18 try: 19 data = json.loads(html) #对HTTP响应的数据JSON化 20 result = data[\'result\'] #索引到目标标签位置 21 for i in result: #对索引出的JSON数据进行遍历和爬取 22 target = i[\'zb\'] #爬取“指标” 23 data_time = i[\'sj\'] #爬取“数据时间” 24 value = i[\'data\'] #爬取“数值” 25 attribute = i[\'db\'] #爬取“所属栏目” 26 lst.append([target,data_time,value,attribute]) #将数据以列表的形式存放到lst里 27 return lst #返回lst列表 28 except: 29 return "网络延迟,请稍后重试" 30 31 #保存数据,生成xlsx格式文件 32 def saveHTMLText(lst): 33 try: 34 headers = [\'指标\',\'数据时间\',\'数值\',\'所属栏目\'] #对df数据类型中的columns赋值 35 index = [i for i in range(1,len(lst)+1)] #对df数据类型中的index赋值 36 df = pd.DataFrame(lst,columns=headers,index=index) #将数据列表转换为DataFrame对象 37 if not os.path.exists(\'E:\\\\Test\'): #判断磁盘里是否存在目标文件夹 38 os.makedirs(\'E:\\\\Test\') #不存在,则创建该文件夹 39 df.to_excel(\'E:\\\\Test\\\\国家统计局相关数据.xlsx\') #生成xlsx文件 40 else: 41 df.to_excel(\'E:\\\\Test\\\\国家统计局相关数据.xlsx\') 42 print("保存成功") #返回成功提示 43 except: 44 print("保存失败") #返回失败提示 45 46 #主程序 47 def main(): 48 uList = [] #存储爬取到的数据 49 for YearIndex in range(1978,2017): #遍历1978-2016年的数据 50 for PageIndex in range(0,6): #遍历每一年前6页的数据 51 url = \'http://data.stats.gov.cn/search.htm?s={0}{1}&m=searchdata&db=&p={2}\'.format(YearIndex,\'GDP\',PageIndex) 52 html = getHTMLText(url) #调用getHTMLText函数 53 filterHTML以上是关于Python高级应用程序设计任务的主要内容,如果未能解决你的问题,请参考以下文章