Python高级应用程序设计任务
Posted 二蛋君
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python高级应用程序设计任务相关的知识,希望对你有一定的参考价值。
Python高级应用程序设计任务要求
用Python实现一个面向主题的网络爬虫程序,并完成以下内容:
(注:每人一题,主题内容自选,所有设计内容与源代码需提交到博客园平台)
一、主题式网络爬虫设计方案(15分)
1.主题式网络爬虫名称
爬取去哪儿所有攻略帖子数据及其分析
2.主题式网络爬虫爬取的内容与数据特征分析
A、爬虫的内容
文章连接、标题、发布者、发布者的个人标签、出发日期、天数、拍照数量、出行的类型、旅行的标签、途经、行程路线、人均消费、观看数、点赞数、评论数
B、数据特征分析
b1、旅游天数分布图分图
b2、拍照数量分布图
b3、出行类型分布图
b4、各种出行方式人均消费箱型图
b5、对出行天数、拍照数量、人均消费、观看数、点赞数和评论数进行相关性分析
b6、人均消费价格和观看数的散点图分析
3.主题式网络爬虫设计方案概述(包括实现思路与技术难点)
A、实现思路
首先通过 get_page()方法获取网页的源码,然后通过 parse_page()方法提取所需要爬取的数据,将其设置为字典的格式,本文这里所采用的提取所用的工具是 bs4 中的 BeautifulSoup,使用的方法是 find 和find_all 方法,最后将爬取到的数据存储到 csv 文件之中。
B、技术难点
在数据提取的过程之中,存在有一定的难点,在爬取部分汉字内容时只能爬取下汉字所对应拼音内容。
二、主题页面的结构特征分析(15分)
1.主题页面的结构特征
本文爬取了共两百页数据,其中每页包含 10 条数据,总计两千条数据。
2.Htmls页面解析
需要爬取网站的数据如图所示:
3.节点(标签)查找方法与遍历方法
(必要时画出节点树结构)
本文获得网页源码之后,主要是运用 BeautifulSoup 中的 find 和 find_all 来获取所需要的数据,节点部分如下图所示:
可以看出,每条数据都在一个 li 标签下,因此使用 BeautifulSoup提取较为方便。
三、网络爬虫程序设计(60分)
爬虫程序主体要包括以下各部分,要附源代码及较详细注释,并在每部分程序后面提供输出结果的截图。
1.数据爬取与采集
爬虫代码如下所示:
# !/usr/bin/env python # -*- coding:utf-8-*- import requests from bs4 import BeautifulSoup import csv headers = {\'User-Agent\':\'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36\'} #获取网页源码 def get_page(url): response = requests.get(url,headers = headers) if response.status_code == 200: return response.text return None #提取所需要爬取的数据 def parse_page(html): soup = BeautifulSoup(html,\'lxml\') #使用BeautifulSoup来解析网页 tables = soup.find_all(\'li\',class_ = \'list_item\') #每个数据所存储的节点位置 #对每个节点遍历循环 for table in tables: datas = {} datas[\'url\'] = \'https://travel.qunar.com\' + table.h2.a.get(\'href\') datas[\'title\'] = table.h2.a.get_text() describe = table.h2.p datas[\'username\'] = table.find(class_ = \'user_name\').a.get_text() label = table.find(class_ = \'user_name_icon\') if label: datas[\'label\'] = label.get(\'title\') datas[\'date\'] = table.find(class_ = \'date\').get_text().replace(\'出发\',\'\') datas[\'days\'] = table.find(class_ = \'days\').get_text().replace(\'共\',\'\').replace(\'天\',\'\') datas[\'photo_nums\'] = table.find(class_ = \'photo_nums\').get_text().replace(\'张照片\',\'\') people = table.find(class_ = \'people\') if people: datas[\'people\'] = people.get_text() trip = table.find(class_ = \'trip\') if trip: datas[\'trip\'] = trip.get_text().replace(\'\\xa0\',\',\') places = table.find_all(class_ = \'places\') if places: datas[\'via_places\'] = places[0].get_text().replace(\'途经:\',\'\') if len(places) == 2: datas[\'distance\'] = places[1].get_text().replace(\'行程:\',\'\') price = table.find(class_ = \'fee\') if price: datas[\'price\'] = price.get_text().replace(\'人均\',\'\').replace(\'元\',\'\') view_nums = table.find(class_ = \'icon_view\').get_text().replace(\'\\ue09d\',\'\') if \'万\' in view_nums: datas[\'view_nums\'] = float(view_nums.replace(\'万\',\'\')) * 10000 else: datas[\'view_nums\'] = view_nums datas[\'praise_nums\'] = table.find(class_ = \'icon_love\').get_text().replace(\'\\uf04f\',\'\') datas[\'comment_nums\'] = table.find(class_ = \'icon_comment\').get_text().replace(\'\\uf060\',\'\') yield datas #设置csv文件的标题 def write_csv_header(fileheader): with open("qunaer.csv", "a", newline=\'\',encoding = \'utf-8\') as csvfile: writer = csv.DictWriter(csvfile, fileheader) writer.writeheader() #将获取到的数据保存到csv def save_to_csv(result,fileheader): with open("qunaer.csv", "a", newline=\'\',encoding = \'utf-8\') as csvfile: print(\'正在保存\') writer = csv.DictWriter(csvfile, fieldnames=fileheader) writer.writerow(result) if __name__ == \'__main__\': fileheader = [\'url\',\'title\',\'username\',\'label\',\'date\',\'days\',\'photo_nums\',\'people\',\'trip\',\'via_places\',\'distance\',\'price\',\'view_nums\',\'praise_nums\',\'comment_nums\'] write_csv_header(fileheader) for page in range(1,201): #爬取200页 url = \'https://travel.qunar.com/travelbook/list.htm?page=\' + str(page) + \'&order=hot_heat\' html = get_page(url) datas = parse_page(html) for data in datas: save_to_csv(data,fileheader)
2.对数据进行清洗和处理
在爬取数据的过程中,已经对数据做了一定的的清洗工作,如所其他的文章链接中不全,给他前面加上 https://travel.qunar.com,出发日期中的出发二字剔除,只取其中的日期部分,人均消费中如果含有万字,则删掉万字,并在原来数值的基础之上乘以 10000,天数中的共和天二字剔除,只取具体的天数部分,拍照数量中剔除张照片的字样,只取具体的拍照数量等。其中部分数据的某些指标为空值,但是不影响接下来继续分析。
3.文本分析(可选):jieba分词、wordcloud可视化
4.数据分析与可视化
(例如:数据柱形图、直方图、散点图、盒图、分布图、数据回归分析等)
导包
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns
获取数据
#防止matplotlib中文乱码 plt.rcParams[\'font.sans-serif\'] = [\'KaiTi\'] # 指定默认字体 plt.rcParams[\'axes.unicode_minus\'] = False #读取数据 data = pd.read_csv(\'qunaer.csv\')
A、旅游天数分布图:
实现代码如下所示:
#旅游天数分布图 date_count = data.groupby(\'days\')[\'people\'].count().to_frame().reset_index() _,ax = plt.subplots(figsize = (15,6)) sns.barplot(x = \'days\',y = \'people\',data = date_count,ax = ax ) ax.set_title(\'旅游天数分布图\') ax.set_xlabel(\'旅游天数\') ax.set_ylabel(\'次数\') plt.show()
所得到的分布图如下图所示:
B、拍照数量分布图
代码如下图所示:
#拍照数量分布图 _,ax = plt.subplots(figsize = (15,6)) sns.distplot(data[\'photo_nums\'],kde = False,ax = ax) ax.set_title(\'拍照数量分布图\') ax.set_xlabel(\'拍照数量\') ax.set_ylabel(\'数量\') plt.show()
所得到的分布图如下所示:
C、出行类型分布图
代码如下图所示:
data_people = data.groupby(\'people\')[\'trip\'].count().to_frame().reset_index() _,ax = plt.subplots(figsize = (15,6)) sns.barplot(x = \'trip\',y = \'people\',data = data_people,orient = \'h\',ax = ax) ax.set_title(\'各种出行方式人数汇总\') ax.set_xlabel(\'人数\') ax.set_ylabel(\'出行方式\') plt.show()
所得到的分布图如下所示:
D、各种出行方式人均消费箱型图
代码如下图所示:
_,ax = plt.subplots(figsize = (15,6)) sns.boxplot(x = \'people\',y = \'price\',data = data,ax = ax) ax.set_title(\'各种出行方式人均消费箱型图\') ax.set_xlabel(\'出行方式\') ax.set_ylabel(\'人均消费\') plt.show()
所得到的箱型图如下图所示:
E、对出行天数、拍照数量、人均消费、观看数、点赞数和评论数进行相关性分析,并作热力图可视化
代码如下图所示:
#相关性分析 select_data = data[[\'days\',\'photo_nums\',\'price\',\'view_nums\',\'praise_nums\',\'comment_nums\']] corr = select_data.corr() print(corr) sns.heatmap(corr) plt.show()
得到的相关性矩阵如下图所示:
所得到的热力图如下图所示:
F、人均消费价格和观看数的散点图分析
代码如下图所示:
#散点图 _,ax = plt.subplots(figsize = (15,6)) sns.scatterplot(data[\'price\'],data[\'view_nums\'],ax = ax) ax.set_xlabel(\'观看数\') ax.set_ylabel(\'人均消费价格\') plt.show()
所得到的散点图如下图所示:
5.数据持久化
将爬取到的数据以 csv 文件的格式存储起来,这样方便用 pandas 进行读取和分析。保存的数据格式如图所示:
6.附完整程序代码
# !/usr/bin/env python # -*- coding:utf-8-*- import requests from bs4 import BeautifulSoup import csv import pandas as pd import matplotlib.pyplot as plt import seaborn as sns headers = {\'User-Agent\':\'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36\'} #获取网页源码 def get_page(url): response = requests.get(url,headers = headers) if response.status_code == 200: return response.text return None #提取所需要爬取的数据 def parse_page(html): soup = BeautifulSoup(html,\'lxml\') #使用BeautifulSoup来解析网页 tables = soup.find_all(\'li\',class_ = \'list_item\') #每个数据所存储的节点位置 #对每个节点遍历循环 for table in tables: datas = {} datas[\'url\'] = \'https://travel.qunar.com\' + table.h2.a.get(\'href\') datas[\'title\'] = table.h2.a.get_text() describe = table.h2.p datas[\'username\'] = table.find(class_ = \'user_name\').a.get_text() label = table.find(class_ = \'user_name_icon\') if label: datas[\'label\'] = label.get(\'title\') datas[\'date\'] = table.find(class_ = \'date\').get_text().replace(\'出发\',\'\') datas[\'days\'] = table.find(class_ = \'days\').get_text().replace(\'共\',\'\').replace(\'天\',\'\') datas[\'photo_nums\'] = table.find(class_ = \'photo_nums\').get_text().replace(\'张照片\',\'\') people = table.find(class_ = \'people\') if people: datas[\'people\'] = people.get_text() trip = table.find(class_ = \'trip\') if trip: datas[\'trip\'] = trip.get_text().replace(\'\\xa0\',\',\') places = table.find_all(class_ = \'places\') if places: datas[\'via_places\'] = places[0].get_text().replace(\'途经:\',\'\') if len(places) == 2: datas[\'distance\'] = places[1].get_text().replace(\'行程:\',\'\') price = table.find(class_ = \'fee\') if price: datas[\'price\'] = price.get_text().replace(\'人均\',\'\').replace(\'元\',\'\') view_nums = table.find(class_ = \'icon_view\').get_text().replace(\'\\ue09d\',\'\') if \'万\' in view_nums: datas[\'view_nums\'] = float(view_nums.replace(\'万\',\'\')) * 10000 else: datas[\'view_nums\'] = view_nums datas[\'praise_nums\'] = table.find(class_ = \'icon_love\').get_text().replace(\'\\uf04f\',\'\') datas[\'comment_nums\'] = table.find(class_ = \'icon_comment\').get_text().replace(\'\\uf060\',\'\') yield datas #设置csv文件的标题 def write_csv_header(fileheader): with open("qunaer.csv", "a", newline=\'\',encoding = \'utf-8\') as csvfile: writer = csv.DictWriter(csvfile, fileheader) writer.writeheader() #将获取到的数据保存到csv def save_to_csv(result,fileheader): with open("qunaer.csv", "a", newline=\'\',encoding = \'utf-8\') as csvfile: print(\'正在保存\') writer = csv.DictWriter(csvfile, fieldnames=fileheader) writer.writerow(result) if __name__ == \'__main__\': fileheader = [\'url\',\'title\',\'username\',\'label\',\'date\',\'days\',\'photo_nums\',\'people\',\'trip\',\'via_places\',\'distance\',\'price\',\'view_nums\',\'praise_nums\',\'comment_nums\'] write_csv_header(fileheader) for page in range(1,201): #爬取200页 url = \'https://travel.qunar.com/travelbook/list.htm?page=\' + str(page) + \'&order=hot_heat\' html = get_page(url) datas = parse_page(html) for data in datas: save_to_csv(data,fileheader) #防止matplotlib中文乱码 plt.rcParams[\'font.sans-serif\'] = [\'KaiTi\'] # 指定默认字体 plt.rcParams[\'axes.unicode_minus\'] = False #读取数据 data = pd.read_csv(\'qunaer.csv\') #旅游天数分布图 date_count = data.groupby(\'days\')[\'people\'].count().to_frame().reset_index() _,ax = plt.subplots(figsize = (15,6)) sns.barplot(x = \'days\',y = \'people\',data = date_count,ax = ax ) ax.set_title(\'旅游天数分布图\') ax.set_xlabel(\'旅游天数\') ax.set_ylabel(\'次数\') plt.show() #拍照数量分布图 _,ax = plt.subplots(figsize = (15,6)) sns.distplot(data[\'photo_nums\'],kde = False,ax = ax) ax.set_title(\'拍照数量分布图\') ax.set_xlabel(\'拍照数量\') ax.set_ylabel(\'数量\') plt.show() #出行方式分布图 data_people = data.groupby(\'people\')[\'trip\'].count().to_frame().reset_index() _,ax = plt.subplots(figsize = (15,6)) sns.barplot(x = \'trip\',y = \'people\',data = data_people,orient = \'h\',ax = ax) ax.set_title(\'各种出行方式人数汇总\') ax.set_xlabel(\'人数\') ax.set_ylabel(\'出行方式\') plt.show() #各种出行方式人均消费箱型图 _,ax = plt.subplots(figsize = (15,6)) sns.boxplot(x = \'people\',y = \'price\',data = data,ax = ax) ax.set_title(\'各种出行方式人均消费箱型图\') ax.set_xlabel(\'出行方式\') ax.set_ylabel(\'人均消费\') plt.show() #相关性分析 select_data = data[[\'days\',\'photo_nums\',\'price\',\'view_nums\',\'praise_nums\',\'comment_nums\']] corr = select_data.corr() print(corr) sns.heatmap(corr) plt.show() #散点图 _,ax = plt.subplots(figsize = (15,6)) sns.scatterplot(data[\'price\'],data[\'view_nums\'],ax = ax) ax.set_xlabel(\'观看数\') ax.set_ylabel(\'人均消费价格以上是关于Python高级应用程序设计任务的主要内容,如果未能解决你的问题,请参考以下文章