在B站上学的一个小项目

用来新手爬虫可视化练练手挺适合

爬取站点【软科排名】2024年最新软科中国大学排名|中国最好大学排名 (shanghairanking.cn)

爬取内容:大学排名,大学名称,大学省份位置,大学类型,大学评分

别总想着白嫖呀,给我博客点个赞行不

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
import requests
from bs4 import BeautifulSoup
import csv
import matplotlib.pyplot as plt


def getHTMLText(url):
try:
r = requests.get(url, timeout=30)#使用get请求url,且设置请求的超时时间为30秒
r.raise_for_status()#检查访问是否成功
r.encoding = r.apparent_encoding#根据响应内容的类型设置正确的编码,确保后续处理时不会出现编码错误
html = r.text#将响应的 HTML 内容(文本格式)赋值给变量 html

# 将html内容写入文件,检查爬取情况
filename = '测试html.text'
with open(filename, 'w', encoding='utf-8') as f:
f.write(html)

return html

except:
print("爬取失败")
return None


def fillUnivList(ulist, html):#这个函数作用是对爬取数据的筛选,建议按f12打开爬取网页元素构成以便于理解爬虫步骤
soup = BeautifulSoup(html, 'html.parser')#使用 BeautifulSoup 库解析传入的 HTML 文本,创建一个 soup 对象,方便后续进行 HTML 元素的查找。
table = soup.find('table', class_='rk-table')#在 soup 对象中查找第一个 <table> 标签,且其类名为 rk-table。将找到的表格赋值给变量 table。
#table: 这是我们要查找的 HTML 标签类型。在这里,我们在寻找一个 <table> 标签。
#class_='rk-table': 这是一个过滤条件,表示我们只想找到具有特定类名(rk-table)的 <table> 标签。class_ 是一个参数,用于指定 HTML 元素的类属性。
if table is None:
print("未找到排名表格")
return
tbody = table.find('tbody')#将tboy标签里的内容全部存入变量tbody中
#print(tbody) #检查数据内容用的,便于理解操作效果
if tbody is None:
print("未找到<tbody>标签")
return
data = tbody.find_all('tr')#在 <tbody> 中查找所有的 <tr> 标签(表格行),并将其赋值给变量 data。
#print(data) #测试 查看数据
for tr in data:
tds = tr.find_all('td')
if len(tds) < 5: # 爬取5行td的内容
continue
td_2 = tds[2].text.strip() if tds[2].text else ""#这边的if else判断tds[2]是否为空,如果为空就赋予引号的值
#总而言之:从列表tds中获取第三个元素的文本内容,并去掉该文本两端的空白字符。
td_3 = tds[3].text.strip() if tds[3].text else ""
#print(tds[1]) #观察里面的内容,并对其中的内容进行筛选
ulist.append([tds[0].string.strip(), tds[1].find('span').string.strip(),
td_2, td_3, tds[4].string.strip()])
#tds[1].find('span').string.strip() 的意思是:
# 从 tds 列表中获取第二个 <td> 元素,找到该元素内的第一个 <span> 标签,获取该标签中的文本内容,并去掉文本前后的空白字符。


def printUnivList(ulist, num):#将爬取的内容存入.csv文件
file_name = "大学排行.csv"
with open(file_name, 'w', newline='', encoding='utf-8') as f:#创建或覆盖一个名为 "大学排行.csv" 的文件,使用 UTF-8 编码以支持中文字符。
writer = csv.writer(f)#使用 csv.writer 创建一个写入器,并写入表头。
writer.writerow(["排名", "大学名称", "省市", "类型", "总分"])
for i in range(num):#写入数据并打印数据用于检查
u = ulist[i]
writer.writerow(u)
print(f"排名:{u[0]}\t大学名称:{u[1]}\t省市:{u[2]}\t类型:{u[3]}\t总分:{u[4]}")

# 折线图
def drawLineChart(ulist):
ranks = [(u[0]) for u in ulist]#ranks:从 ulist 中提取每个大学的排名
scores = [float(u[4]) for u in ulist]#scores:从 ulist 中提取每个大学的总分,并将其转换为浮点数
names = [u[1] for u in ulist]#names:从 ulist 中提取大学的名称


plt.rcParams['font.sans-serif'] = ['SimHei']#设置字体为 SimHei,以支持中文显示。
plt.figure(dpi=300) # 设置图像分辨率为300
plt.figure(figsize=(12, 8)) #设置图像的大小为12x8英寸
plt.plot(names, scores)#绘制以 ranks 为横坐标、scores 为纵坐标的折线图。

plt.xlabel('大学名称')
plt.ylabel('总分')
plt.title('大学排行榜折线图')

for i in range(len(names)):#在每个点上加上排名
plt.text(names[i], scores[i], ranks[i], ha='center', va='bottom', multialignment='center')

plt.xticks(rotation='vertical') # 将x轴的字体改为竖向显示

plt.savefig('大学排行榜折线图.pdf', format='pdf', bbox_inches='tight') # bbox_inches='tight' 可以去除多余的空白

plt.show()

# 饼图
def generatePieChart(ulist, num):
provinces = {}
for i in range(num):
province = ulist[i][2]
if province in provinces:
provinces[province] += 1
else:
provinces[province] = 1

labels = provinces.keys()
sizes = provinces.values()
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.figure(dpi=300) # 设置图像分辨率为300
plt.figure(figsize=(8, 6))
plt.pie(sizes, labels=labels, autopct='%1.1f%%')
plt.axis('equal')
plt.title('大学排行前30名的省份分布')
plt.show()

# plt.rcParams['font.sans-serif'] = ['SimHei']


# 柱形图
def printUnivList2(ulist, num):
ranks = []
scores = []
names = []

for i in range(num):
u = ulist[i]
ranks.append(int(u[0]))
scores.append(float(u[4]))
names.append(u[1])

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.figure(dpi=300) # 设置图像分辨率为300
plt.bar(ranks, scores)
plt.xlabel('排名')
plt.ylabel('总分')
plt.title('大学排名')

for i in range(len(ranks)):
# 在每个柱形图上方显示大学名称,并将其旋转45度
plt.text(ranks[i], scores[i], names[i], ha='center', va='bottom', fontsize=3, rotation=45)

plt.show()


# 散点图
def generateScatterPlot(ulist, num):
scores = [float(ulist[i][4]) for i in range(num)]
ranks = [i + 1 for i in range(num)]
names = [ulist[i][1] for i in range(num)]
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.figure(dpi=300) # 设置图像分辨率为300
plt.figure(figsize=(12, 8))
plt.scatter(ranks, scores)
plt.title('大学排名与总分的关系')
plt.xlabel('排名')
plt.ylabel('总分')

for i, name in enumerate(names):
plt.annotate(name, (ranks[i], scores[i]), xytext=(5, 5), textcoords='offset points', fontsize=8, rotation=45)

plt.show()


# 箱形图
def generateBoxPlot(ulist, num):
scores = [float(ulist[i][4]) for i in range(num)]
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.figure(dpi=300) # 设置图像分辨率为300
plt.figure(figsize=(8, 6))
plt.boxplot(scores)
plt.title('大学总分箱形图')
plt.ylabel('总分')
plt.show()


# 环形图
def generateDonutChart(ulist, num):
provinces = {}
for i in range(num):
province = ulist[i][2]
if province in provinces:
provinces[province] += 1
else:
provinces[province] = 1

labels = provinces.keys()
sizes = provinces.values()
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.figure(dpi=300) # 设置图像分辨率为300
plt.figure(figsize=(8, 6))
_, _, autotexts = plt.pie(sizes, labels=labels, autopct='%1.1f%%', wedgeprops=dict(width=0.8))
plt.setp(autotexts, size=8)
plt.title('大学排行前30名的省份分布(环形图)')
plt.axis('equal')
plt.show()


def main():
ulist = []
url = 'https://www.shanghairanking.cn/rankings/bcur/202411.html'
html = getHTMLText(url)
if html is not None:
fillUnivList(ulist, html)
printUnivList(ulist, 30)
printUnivList2(ulist, 30) # 柱形图
drawLineChart(ulist) # 折线图
generatePieChart(ulist, 30) # 饼图
generateScatterPlot(ulist, 30) # 调用生成散点图的函数
generateBoxPlot(ulist, 30) # 调用生成箱形图的函数
generateDonutChart(ulist, 30) # 调用生成环形图的函数


main()