一、选题背景
随着综合国力的上涨,百年大计,教育为本。党的十八大以来,我国高等教育与时代同行,建成世界规模最大的高等教育体系,培育了一大批高素质专门人才,为民族振兴、经济建设、社会发展、科技进步发挥了极端重要作用,高等教育事业取得历史性成就,发生格局性变化。越来越多的高校将目光放在了国际上,那么国际上的大学排名又是根据那些来进行排名的呢?
二、程序设计方案
1.寻找权威的且排名广泛的大学排行榜http://rankings.betteredu.net/qs/world-university-rankings/latest/2022.html,这个网站具有1300左右的学校排行。
2.准备python爬取需要的class,tbody,tr等,并且对格式进行分析
3.存储在表格中,便于可视化
4.可视化分析
三、爬取结果及代码
首先是对http://rankings.betteredu.net/qs/world-university-rankings/latest/2022.html的爬取,并且存入excel表格中,为后续的可视化做准备
1 #导入requests用requests库的函数爬取网页 2 import requests 3 from bs4 import BeautifulSoup 4 import openpyxl 5 6 # 创建一个新的Excel工作簿 7 workbook = openpyxl.Workbook() 8 # 选择默认的活动工作表 9 sheet = workbook.active 10 11 # 表头数据 12 headers = ['排名', '学校中文名称', '学校英文名称', '总分', '国际学生占比', '国际教师比例', '师生比', '每位教员引用率', '学术声誉', '雇主声誉'] 13 # 写入表头 14 sheet.append(headers) 15 16 #发送HTTP请求并获取网页内容 17 url = "http://rankings.betteredu.net/qs/world-university-rankings/latest/2022.html" 18 response = requests.get(url) 19 #指定编码方式为utf-8,没有utf-8会出现中文乱码 20 response.encoding = 'utf-8' 21 content = response.content 22 23 #用beautifsoup解析网页内容 24 soup = BeautifulSoup(content, 'html.parser') 25 #查找具有class为ranksshow_ct的div,确定爬取页面板块 26 ranksshow_ct_div = soup.find('div', class_='ranksshow_ct') 27 # 在ranksshow_ct_div中查找具有class为rks_qsshowct的div 28 rks_qsshowct_div = ranksshow_ct_div.find('div', class_='rks_qsshowct') 29 # 查找表格 30 table = rks_qsshowct_div.find('table') 31 # 查找tbody 32 tbody = table.find('tbody') 33 34 # 表格内容数据 35 content = [] 36 # 遍历tbody中的表格行 37 for row in tbody.find_all('tr'): 38 row_data = [] 39 #如果有等号就将等号去除 40 if cell.text.strip().startswith('='): 41 cell_text = cell.text.strip()[1:] 42 #如果没有等号就继续遍历 43 else: 44 cell_text = cell.text.strip() 45 row_data.append(cell_text) 46 content.append(row_data) 47 # 写入表格内容 48 for row in content: 49 sheet.append(row) 50 51 # 保存Excel文件,在文件pythonsj中生成表sjdx.xlsx 52 file_path = r'D:\pythonsj\sjdx.xlsx' 53 workbook.save(file_path) 1
import pandas as pd 2 3 # 读取Excel文件数据 4 df = pd.read_excel(r'D:\pythonsj\sjdx.xlsx') 5 6 # 修改排名列为整型 7 df.loc[:449, '排名'] = df.loc[:449, '排名'].astype(int) 8 9 # 修改其他列为浮点型 10 columns = ['总分', '国际学生占比', '国际教师比例', '师生比', '每位教员引用率', '学术声誉', '雇主声誉'] 11 df.loc[:449, columns] = df.loc[:449, columns].astype(float) 12 13 # 保存修改后的表格 14 df.to_excel(r'D:\Edge download\university_rankings.xlsx', index=False)
这是形成的表格的部分图片,总共有1300左右的数据。
这是爬取过程中(未存入表格)的数据遍历
多页面爬取及其存储
1 import requests 2 from bs4 import BeautifulSoup 3 from openpyxl import Workbook 4 5 start_year = 2018 6 end_year = 2022 7 8 for year in range(start_year, end_year + 1): 9 url = f"https://www.shanghairanking.cn/rankings/arwu/{year}" 10 response = requests.get(url) 11 12 if response.status_code == 200: 13 response.encoding = "utf-8" # 指定编码格式 14 soup = BeautifulSoup(response.text, "html.parser") 15 table = soup.find("table", class_="rk-table") 16 17 rows = table.find_all("tr") 18 19 # 创建Excel文件和工作表 20 wb = Workbook() 21 ws = wb.active 22 23 # 写入表头 24 ws.append(["排名", "学校名称", "国家", "总分", "校友获奖"]) 25 26 for row in rows[1:]: # 跳过表头行 27 cells = row.find_all("td") 28 rank = cells[0].text.strip() 29 university = cells[1].text.strip() 30 country = cells[2].text.strip() 31 score = cells[3].text.strip() 32 alumni_award = cells[4].text.strip() 33 34 # 写入数据行 35 ws.append([rank, university, country, score, alumni_award]) 36 37 # 保存Excel文件 38 save_path = f"D:\\pythonsj\\cn{year}.xlsx" 39 wb.save(save_path) 40 print(f"{year}年的数据已保存到文件:{save_path}") 41 else: 42 print(f"{year}年的数据无法访问网页。")
对表格进行数据清清洗,遍历
import pandas as pd # 读取Excel文件 df = pd.read_excel(r'D:\pythonsj\cn2022.xlsx') # 将排名、总分和校友获奖列的数据类型转换为浮点型 df['排名'] = df['排名'].astype(float) df['总分'] = df['总分'].astype(float) df['校友获奖'] = df['校友获奖'].astype(float) # 打印清洗后的数据 print(df)
对表格进行调整
1 from openpyxl import load_workbook 2 from openpyxl.utils import get_column_letter 3 4 # 加载Excel文件 5 filename = r'D:\Edge download\university_rankings.xlsx' 6 wb = load_workbook(filename) 7 8 # 获取第一个工作表 9 sheet = wb.active 10 11 # 调整学校中文名称列宽 12 column_letter = get_column_letter(2) # 学校中文名称在第二列 13 max_length = 0 14 for cell in sheet[column_letter]: 15 try: 16 if len(str(cell.value)) > max_length: 17 max_length = len(cell.value) 18 except: 19 pass 20 adjusted_width = (max_length + 2) * 1.2 # 调整宽度留出一定的空隙 21 sheet.column_dimensions[column_letter].width = adjusted_width 22 23 # 保存调整后的表格 24 wb.save(filename) 25 26 # 输出运行结果 27 print(f"学校中文名称列的宽度已调整为:{adjusted_width}")
可视化:对排名前500的学校,按排名和总分绘制成散点图
分析学校排名和总分的关系
1 #前500名学校排名和总分形成的散点图 2 import pandas as pd 3 import matplotlib.pyplot as plt 4 5 # 读取Excel文件数据 6 df = pd.read_excel(r'D:\pythonsj\sjdx.xlsx' ) 7 8 # 将排名数据转换为整数类型 9 df['排名'] = pd.to_numeric(df['排名'], errors='coerce').fillna(0).astype(int) 10 11 # 对排名进行预处理,将超过500的排名限制在500以内 12 df['排名'] = df['排名'].clip(upper=500) 13 14 # 绘制散点图 15 plt.scatter(df['排名'], df['总分']) 16 plt.xlabel('排名') 17 plt.ylabel('总分') 18 plt.title('排名与总分的关系') 19 plt.show()
字母频次
import pandas as pd import matplotlib.pyplot as plt # 读取Excel文件数据 df = pd.read_excel(r'D:\pythonsj\sjdx.xlsx' ) # 获取前300名大学的数据 top_300 = df.head(300).copy() # 使用copy()方法创建副本 # 提取学校英文名称最后一个字母 top_300['最后一个字母'] = top_300['学校英文名称'].str[-1] # 计算字母频次并选取前十个字母范围 top_letters = top_300['最后一个字母'].value_counts().head(10) # 绘制柱状图 plt.bar(top_letters.index, top_letters.values) plt.xlabel('字母范围') plt.ylabel('频次') plt.title('前300名大学中学校英文名称最后一个字母频次前十') # 旋转x轴刻度标签 plt.xticks(rotation=90) plt.show()
选择两校进行各项对比
1 import pandas as pd 2 import matplotlib.pyplot as plt 3 from pylab import mpl 4 5 # 设置显示中文字体 6 mpl.rcParams["font.sans-serif"] = ["SimHei"] 7 8 # 读取Excel文件数据 9 df = pd.read_excel(r'D:\pythonsj\sjdx.xlsx' ) 10 11 # 输入两个学校的排名 12 rank1 = int(input("请输入学校1的排名:")) 13 rank2 = int(input("请输入学校2的排名:")) 14 15 # 根据排名选择学校数据 16 school1 = df[df['排名'] == rank1] 17 school2 = df[df['排名'] == rank2] 18 19 # 检查学校选择结果 20 if school1.empty or school2.empty: 21 print("因排名并列,该排名为空。") 22 exit() 23 24 # 提取学校名称 25 name1 = school1['学校中文名称'].iloc[0] 26 name2 = school2['学校中文名称'].iloc[0] 27 28 # 提取指标数据 29 indicators = ['总分', '国际学生占比', '国际教师比例', '师生比', '每位教员引用率', '学术声誉', '雇主声誉'] 30 data1 = school1[indicators].values[0] 31 data2 = school2[indicators].values[0] 32 33 # 绘制对比曲线图 34 plt.plot(indicators, data1, label=name1) 35 plt.plot(indicators, data2, label=name2) 36 plt.xlabel('指标') 37 plt.ylabel('数值') 38 plt.title('学校指标对比') 39 plt.legend() 40 plt.show()
通过爬取的第二个数据表进行绘制地图
1 from pyecharts.charts import Map 2 from pyecharts import options as opts 3 import pandas as pd 4 5 # 读取Excel文件 6 df = pd.read_excel(r'D:\pythonsj\cn2022.xlsx') 7 8 # 提取学校所在国家和排名数据 9 country_data = df[['国家', '排名']] 10 11 # 将学校所在国家和排名转换为字典格式 12 country_rank_dict = dict(zip(country_data['国家'], country_data['排名'])) 13 14 # 绘制地图 15 map_data = ( 16 Map() 17 .add("学校排名", [list(z) for z in country_rank_dict.items()], "world") 18 .set_series_opts(label_opts=opts.LabelOpts(is_show=True)) 19 .set_global_opts( 20 title_opts=opts.TitleOpts(title="ARWU世界大学排名"), 21 visualmap_opts=opts.VisualMapOpts(max_=30), 22 ) 23 ) 24 25 # 生成HTML文件并在浏览器中显示 26 map_data.render(r'D:\pythonsj\worldmap.html')
四、程序设计过程和问题
1.爬取:确定使用requests和BeautifulSoup进行网络爬后,发现难以确定class形式,一层层相套,电脑没办法确定爬取目标。解决:用包含的方式,从第一层class=rankshow_ct确定rks_qsshowct再重复确定到tbody从而找到表格
2然后第一次找到内容,发现输出的时全部的。 解决:确定表格位置遍历表格的内容。
3改善后,遍历了<tr>中的内容,但是出现了中文乱码,经过查询和翻阅课本后发现是忘记了utf-8编码
4加上后就出现完整的遍历,于是就存入表格中,查看表格后发现有等号(并列排名),但是在可视化时需要排名来进行对比。解决:在循环遍历时加入一个if语句,将多余的等号删除。
还有就是没有表头,因为爬取的这个表格,他将表头和内容分开(分出一个<thead>和<tr>,<th>的镶嵌模式),于是就自己插入一个表头。
5可视化中,出现一个很奇怪的问题,有的时候不用自己添加一个字体,有时候要自己添加字体,不然会出现字体错误。上面所给的是成功的截图
1.#from pylab import mpl
#mpl.rcParams["font.sans-serif"] = ["SimHei"]
2#plt.rcParams['font.sans-serif']=['SimHei'] #显示中文标签
#plt.rcParams['axes.unicode_minus']=False #这两行需要手动设置
3#设置字体为楷体
#matplotlib.rcParams['font.sans-serif'] = ['KaiTi']
这是一些解决方法,有的可以有的不行。
6选择俩学校生成对比线条是最麻烦的,关键就是其中的选择,因为有的学校并列,所有花费很多时间在选择,导入数据上。
这是最开始做的选择比较,但是基本无法看出差距,如果排名6的学校比排名2的学校数值高,那么就无法看出差距,所有转折线图。
7最后的地图问题出现在,如果要用颜色标记,会出现没有颜色出现的状况,因为许多国家重叠,导致颜色冲突,我试过许多方法,例如重复国家颜色加深,按频次越多颜色越深。
例如:# 根据国家去重,并取第一个国家作为标记 (data = data.drop_duplicates(subset=['国家'], keep='first'))都无法实现,只能用名字标记国家。
以上是印象较为深刻的问题,困扰时间较久。过程中还有许多的报错问题都是在百度搜索解决。
五、全部代码
1 #导入requests用requests库的函数爬取网页 2 import requests 3 from bs4 import BeautifulSoup 4 import openpyxl 5 6 # 创建一个新的Excel工作簿 7 workbook = openpyxl.Workbook() 8 # 选择默认的活动工作表 9 sheet = workbook.active 10 11 # 表头数据 12 headers = ['排名', '学校中文名称', '学校英文名称', '总分', '国际学生占比', '国际教师比例', '师生比', '每位教员引用率', '学术声誉', '雇主声誉'] 13 # 写入表头 14 sheet.append(headers) 15 16 #发送HTTP请求并获取网页内容 17 url = "http://rankings.betteredu.net/qs/world-university-rankings/latest/2022.html" 18 response = requests.get(url) 19 #指定编码方式为utf-8,没有utf-8会出现中文乱码 20 response.encoding = 'utf-8' 21 content = response.content 22 23 #用beautifsoup解析网页内容 24 soup = BeautifulSoup(content, 'html.parser') 25 #查找具有class为ranksshow_ct的div,确定爬取页面板块 26 ranksshow_ct_div = soup.find('div', class_='ranksshow_ct') 27 # 在ranksshow_ct_div中查找具有class为rks_qsshowct的div 28 rks_qsshowct_div = ranksshow_ct_div.find('div', class_='rks_qsshowct') 29 # 查找表格 30 table = rks_qsshowct_div.find('table') 31 # 查找tbody 32 tbody = table.find('tbody') 33 34 # 表格内容数据 35 content = [] 36 # 遍历tbody中的表格行 37 for row in tbody.find_all('tr'): 38 row_data = [] 39 #如果有等号就将等号去除 40 if cell.text.strip().startswith('='): 41 cell_text = cell.text.strip()[1:] 42 #如果没有等号就继续遍历 43 else: 44 cell_text = cell.text.strip() 45 row_data.append(cell_text) 46 content.append(row_data) 47 # 写入表格内容 48 for row in content: 49 sheet.append(row) 50 51 # 保存Excel文件,在文件pythonsj中生成表sjdx.xlsx 52 file_path = r'D:\pythonsj\sjdx.xlsx' 53 workbook.save(file_path) 54 55 #可视化分析 56 #前500名学校排名和总分形成的散点图 57 import pandas as pd 58 import matplotlib.pyplot as plt 59 60 # 读取Excel文件数据 61 df = pd.read_excel(r'D:\Edge download\university_rankings.xlsx') 62 63 # 将排名数据转换为整数类型 64 df['排名'] = pd.to_numeric(df['排名'], errors='coerce').fillna(0).astype(int) 65 66 # 对排名进行预处理,将超过500的排名限制在500以内 67 df['排名'] = df['排名'].clip(upper=500) 68 69 # 绘制散点图 70 plt.scatter(df['排名'], df['总分']) 71 plt.xlabel('排名') 72 plt.ylabel('总分') 73 plt.title('排名与总分的关系') 74 plt.show() 75 #前500名学校排名和总分形成的散点图 76 import pandas as pd 77 import matplotlib.pyplot as plt 78 #from pylab import mpl 79 #plt.rcParams['font.sans-serif']=['SimHei'] #显示中文标签 80 #plt.rcParams['axes.unicode_minus']=False 81 # 设置显示中文字体,设置字体为楷体 82 #matplotlib.rcParams['font.sans-serif'] = ['KaiTi'] 83 #mpl.rcParams["font.sans-serif"] = ["SimHei"] 84 # 读取Excel文件数据 85 df = pd.read_excel(r'D:\pythonsj\sjdx.xlsx' ) 86 87 # 将排名数据转换为整数类型 88 df['排名'] = pd.to_numeric(df['排名'], errors='coerce').fillna(0).astype(int) 89 90 # 对排名进行预处理,将超过500的排名限制在500以内 91 df['排名'] = df['排名'].clip(upper=500) 92 93 # 绘制散点图 94 plt.scatter(df['排名'], df['总分']) 95 plt.xlabel('排名') 96 plt.ylabel('总分') 97 plt.title('排名与总分的关系') 98 plt.show() 99 import pandas as pd 100 import matplotlib.pyplot as plt 101 102 # 读取Excel文件数据 103 df = pd.read_excel(r'D:\pythonsj\sjdx.xlsx' ) 104 105 # 获取前300名大学的数据 106 top_300 = df.head(300).copy() # 使用copy()方法创建副本 107 108 # 提取学校英文名称最后一个字母 109 top_300['最后一个字母'] = top_300['学校英文名称'].str[-1] 110 111 # 计算字母频次并选取前十个字母范围 112 top_letters = top_300['最后一个字母'].value_counts().head(10) 113 114 # 绘制柱状图 115 plt.bar(top_letters.index, top_letters.values) 116 plt.xlabel('字母范围') 117 plt.ylabel('频次') 118 plt.title('前300名大学中学校英文名称最后一个字母频次前十') 119 120 # 旋转x轴刻度标签 121 plt.xticks(rotation=90) 122 123 plt.show() 124 import pandas as pd 125 import matplotlib.pyplot as plt 126 from pylab import mpl 127 128 # 设置显示中文字体 129 mpl.rcParams["font.sans-serif"] = ["SimHei"] 130 131 # 读取Excel文件数据 132 df = pd.read_excel(r'D:\pythonsj\sjdx.xlsx' ) 133 134 # 输入两个学校的排名 135 rank1 = int(input("请输入学校1的排名:")) 136 rank2 = int(input("请输入学校2的排名:")) 137 138 # 根据排名选择学校数据 139 school1 = df[df['排名'] == rank1] 140 school2 = df[df['排名'] == rank2] 141 142 # 检查学校选择结果 143 if school1.empty or school2.empty: 144 print("因排名并列,该排名为空。") 145 exit() 146 147 # 提取学校名称 148 name1 = school1['学校中文名称'].iloc[0] 149 name2 = school2['学校中文名称'].iloc[0] 150 151 # 提取指标数据 152 indicators = ['总分', '国际学生占比', '国际教师比例', '师生比', '每位教员引用率', '学术声誉', '雇主声誉'] 153 data1 = school1[indicators].values[0] 154 data2 = school2[indicators].values[0] 155 156 # 绘制对比曲线图 157 plt.plot(indicators, data1, label=name1) 158 plt.plot(indicators, data2, label=name2) 159 plt.xlabel('指标') 160 plt.ylabel('数值') 161 plt.title('学校指标对比') 162 plt.legend() 163 plt.show()
164 import requests 165 from bs4 import BeautifulSoup 166 from openpyxl import Workbook 167 168 start_year = 2018 169 end_year = 2022 170 171 for year in range(start_year, end_year + 1): 172 url = f"https://www.shanghairanking.cn/rankings/arwu/{year}" 173 response = requests.get(url) 174 175 if response.status_code == 200: 176 response.encoding = "utf-8" # 指定编码格式 177 soup = BeautifulSoup(response.text, "html.parser") 178 table = soup.find("table", class_="rk-table") 179 180 rows = table.find_all("tr") 181 182 # 创建Excel文件和工作表 183 wb = Workbook() 184 ws = wb.active 185 186 # 写入表头 187 ws.append(["排名", "学校名称", "国家", "总分", "校友获奖"]) 188 189 for row in rows[1:]: # 跳过表头行 190 cells = row.find_all("td") 191 rank = cells[0].text.strip() 192 university = cells[1].text.strip() 193 country = cells[2].text.strip() 194 score = cells[3].text.strip() 195 alumni_award = cells[4].text.strip() 196 197 # 写入数据行 198 ws.append([rank, university, country, score, alumni_award]) 199 200 # 保存Excel文件 201 save_path = f"D:\\pythonsj\\cn{year}.xlsx" 202 wb.save(save_path) 203 print(f"{year}年的数据已保存到文件:{save_path}") 204 else: 205 print(f"{year}年的数据无法访问网页。")import pandas as pd 206 207 # 读取Excel文件 208 df = pd.read_excel(r'D:\Edge download\cn2022.xlsx') 209 210 # 将排名、总分和校友获奖列的数据类型转换为浮点型 211 df['排名'] = df['排名'].astype(float) 212 df['总分'] = df['总分'].astype(float) 213 df['校友获奖'] = df['校友获奖'].astype(float) 214 from pyecharts.charts import Map 215 from pyecharts import options as opts 216 import pandas as pd 217 218 # 读取Excel文件 219 df = pd.read_excel(r'D:\pythonsj\cn2022.xlsx') 220 221 # 提取学校所在国家和排名数据 222 country_data = df[['国家', '排名']] 223 224 # 将学校所在国家和排名转换为字典格式 225 country_rank_dict = dict(zip(country_data['国家'], country_data['排名'])) 226 227 # 绘制地图 228 map_data = ( 229 Map() 230 .add("学校排名", [list(z) for z in country_rank_dict.items()], "world") 231 .set_series_opts(label_opts=opts.LabelOpts(is_show=True)) 232 .set_global_opts( 233 title_opts=opts.TitleOpts(title="ARWU世界大学排名"), 234 visualmap_opts=opts.VisualMapOpts(max_=30), 235 ) 236 ) 237 238 # 生成HTML文件并在浏览器中显示 239 map_data.render(r'D:\pythonsj\worldmap.html')
1 from openpyxl import load_workbook 2 from openpyxl.utils import get_column_letter 3 4 # 加载Excel文件 5 filename = r'D:\Edge download\university_rankings.xlsx' 6 wb = load_workbook(filename) 7 8 # 获取第一个工作表 9 sheet = wb.active 10 11 # 调整学校中文名称列宽 12 column_letter = get_column_letter(2) # 学校中文名称在第二列 13 max_length = 0 14 for cell in sheet[column_letter]: 15 try: 16 if len(str(cell.value)) > max_length: 17 max_length = len(cell.value) 18 except: 19 pass 20 adjusted_width = (max_length + 2) * 1.2 # 调整宽度留出一定的空隙 21 sheet.column_dimensions[column_letter].width = adjusted_width 22 23 # 保存调整后的表格 24 wb.save(filename) 25 26 # 输出运行结果 27 print(f"学校中文名称列的宽度已调整为:{adjusted_width}")
标签:plt,网页,df,text,爬取,可视化,pd,import,排名 From: https://www.cnblogs.com/c1-dream/p/17464378.html