爬虫 – QS世界大学排名数据

  • 网站简介
  • 爬虫方法概述
    • 使用工具
    • 爬虫概述
  • 第一部分
    • 导入需要用到的python包
    • 设置selenium控制浏览器打开网页
    • 控制鼠标操作
      • 定位节点
    • 提取数据
    • 滚轮翻页
    • 构建循环自动爬取数据
    • 数据储存
  • 第二部分
    • 导入需要用到的python包
    • 获取网页
      • 设置请求头
      • 读取链接
      • 获取网页信息
      • 定位节点获取数据
  • 第三部分
      • 读取数据
      • 合并数据

网站简介

QS世界大学排名 是由教育组织Quacquarelli Symonds(简称QS)每年发布的全球各地大学排名情况的系列排名之一。该排名是根据大学的学术水平、研究质量、国际化程度、教师素质、学生满意度等多项指标综合评估得出的,参考数据来源广泛,包括了全球各大权威研究机构的数据统计和排名情况。

QS世界大学排名分为多个子排名,包括综合排名、学科排名、地区排名等。其中,综合排名按照学术水平、教学质量、研究产出、国际化程度等指标对全球大学进行排名,参考数据来源为全球各大权威研究机构的数据统计和排名情况。学科排名按照学科领域对全球大学进行排名,包括了商科、工程、生命科学、医学、法律等多个领域。地区排名则按照地理位置和学术水平对全球大学进行排名,涵盖了全球多个地区。

除了以上的排名系列,QS还发布了一些其他相关的大学排名,如根据毕业生就业率、教师满意度等指标的QS世界大学毕业生就业排名和根据国际留学生比例、教师国际化程度等指标的QS世界大学国际化排名等。

总的来说,QS世界大学排名是全球最具权威性和影响力的大学排名之一,被认为是评估全球大学综合实力和学术水平的重要指标之一。

爬虫方法概述

使用工具

爬虫相关seleniumrequestslxmlxpath
数据处理pandas
IDEvscode + jupyter

爬虫概述

本案例共分为三个部分:

  • 第一部分:爬取排名指标下面的,排名、大学名称、大学详情链接地址、综合得分、学术声誉、雇主声誉、每位教员引用率、师生比、国际学生占比、国际教师占比,中的前1000名的数据。使用selenium来模拟浏览器爬取。

  • 第二部分:爬取大学详情中的数据,高校性质、研究成果、学生人数、教师人数、国际学生人数。由于这些网址都是独立的,所以直接使用requests+xpath来获取数据。

  • 第三部分:数据合并,把前两部分获取的数据,使用pandas来把数据合并到一起。

话不多说,开始干活。

第一部分

导入需要用到的python包

导入需要用到的python包,第一部分主要使用selenium 来获取数据,所以导入selenium包中使用到的部分,控制爬虫时间我使用的是time模块,用起来比较简单,数据保存使用pandas

from selenium import webdriverfrom selenium.webdriver.chrome.service import Servicefrom selenium.webdriver.common.by import Byimport timeimport pandas as pd

设置selenium控制浏览器打开网页

使用selenium打开操作打开浏览器网址。
网址:https://www.qschina.cn/university-rankings/world-university-rankings/2023
设置完成后就可以使用selenium来打开浏览器和网址了。

# 设置浏览器内核路径servic = Service(executable_path =r'****/chromedriver.exe')driver = webdriver.Chrome(service=servic) # 获取网页driver.get("https://www.qschina.cn/university-rankings/world-university-rankings/2023")# 通过设置sleep时间来控制爬虫的速度,根据情况,也可不用。time.sleep(1)

效果如下:

控制鼠标操作

完成上一步后,就可以打开网页了,但是网页默认显示的是排名榜单,里面只有学校的名称和排名,如下图。

但是我们要获取的数据实在排名指标下面。如下图。
需要通过鼠标点击排名指标,才能显示出需要爬取的数据信息。

所以需要我们通过selenium来控制鼠标实现点击的动作。需要先定位鼠标点击的节点(xpath定位),然后通过selenium实现点击。

定位节点

打开网址:https://www.qschina.cn/university-rankings/world-university-rankings/2023
然后在页面点击右键,选择最下方检查来打开开发者工具。

然后页面是这样:在右边,开发这工具的左上角元素检查的图标,如下图红圈位置。点击后鼠标挪到左侧网页上面(先不要点击)。

鼠标就会变成一个选区的工具,鼠标所指示的地方都会有蓝色方块来显示元素的区域。把鼠标移动到排名指标位置,会有蓝色选中的样式。如下图

选中后点击鼠标左键,在右侧开发者工具中就会显示出这个元素的位置信息。在此处(下图红框位置)点击鼠标右键。

可以通过鼠标右键-复制-复制xpath来获取元素的定位信息。

检查定位信息是否准确,可以在打开开发者工具模式下,键盘按键 ctrl + f 来打开搜索工具框,然后把刚才复制的xpath信息粘贴进去,所定位的元素就会有绿色高亮来标记出来,并且搜索框后面会显示出xpath定位的元素个数(绿圈标记)。此处应该是位置的所以后面会显示1 of 1。

获取到元素定位后,就开始写代码啦,完成鼠标点击只需要一行代码就可以了。代码如下:

driver.find_element(By.XPATH,'//*[@id="qs-rankings-datatables"]/div[1]/ul/li[2]/a').click()# 通过设置sleep时间来控制爬虫的速度,根据情况,也可不用。看心情time.sleep(1)

提取数据

前面的步骤完成后,页面就能显示出需要爬取的数据了,接下来就开始研究如何提取页面的数据了。

先定位数据的元素位置,如何选择参考前面。

找到数据的位置后,复制xpath路径,在使用ctrl+f来检验是否正确。

确定定位没问题后,那么就表示其他需要获取的数据也在此处,分析查看上下代码后可知道,需要的数据确实都在同一个tr中,那么下面就可以逐个去获取数据了。

开始编写获取数据的代码。

我们需要获取的数据内容分别是 排名、大学名称、大学详情链接地址、综合得分、学术声誉、雇主声誉、每位教员引用率、师生比、国际学生占比、国际教师占比

先编写获取一个的代码,其他的都可以以此为例之改变定位信息就可以了。
以排名为例:

# 新建一个空的列表用来储存获取的数据rank_all = []#在selenium中使用xpath定位,#因为定位的是多个元素,所以此处要使用find_elements,不能使用find_elementlist_rank = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" rank"]')# 遍历每个元素提取数据信息for li_rank in list_rank:rank = li_rank.find_element(By.XPATH,'./div/div').text# 数据保存到列表中 rank_all.append(rank)

根据上面的代码,逐个编写获取其他数据的代码。

由于网页上面每一页只有25条数据,需要翻页然后多次调用获取数据信息的代码,所以把获取数据信息的代码打包为一个def来方便多次调用。代码如下

# 创建空的数据列表用来保存数据# 排名rank_all = []# 大学名称name_all = []# 大学详情链接地址href_all = []# 综合得分scor_all = []# 学术声誉xueshu_all = []# 雇主声誉guzhu_all = []# 每位教员引用率jiaoyuan_all = []# 师生比shishengbi_all = []# 国际学生占比guoji_xuesheng_all = []# 国际教师占比guoji_jiaoshi_all = []def get_text():# rank排名list_rank = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" rank"]')for li_rank in list_rank:rank = li_rank.find_element(By.XPATH,'./div/div').text# 保存数据到列表rank_all.append(rank)# name大学名称list_name = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" uni"]/div/div')for li_name in list_name:name = li_name.find_element(By.XPATH,'./a').text# 保存数据到列表name_all.append(name)# href大学详情链接地址list_href = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" uni"]/div/div')for li_href in list_href:href = li_href.find_element(By.XPATH,'./a').get_attribute('href')# 保存数据到列表href_all.append(href)# 综合得分list_scor = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class="ind-col ind-overall sorting_1"]')for li_scor in list_scor:scor = li_scor.text# 保存数据到列表scor_all.append(scor)# 学术声誉list_xueshu = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" ind-col ind-76"]')for li_xueshu in list_xueshu:xueshu = li_xueshu.find_element(By.XPATH,'./div/div').text# 保存数据到列表xueshu_all.append(xueshu)# 雇主声誉list_guzhu = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" ind-col ind-77"]')for li_guzhu in list_guzhu:guzhu = li_xueshu.find_element(By.XPATH,'./div/div').text# 保存数据到列表guzhu_all.append(guzhu)# 每位教员引用率list_jiaoyuan = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" ind-col ind-73"]')for li_jiaoyuan in list_jiaoyuan:jiaoyuan = li_jiaoyuan.find_element(By.XPATH,'./div/div').text# 保存数据到列表jiaoyuan_all.append(jiaoyuan)# 师生比list_shishengbi = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" ind-col ind-36"]')for li_shishengbi in list_shishengbi:shishengbi = li_shishengbi.find_element(By.XPATH,'./div/div').text# 保存数据到列表shishengbi_all.append(shishengbi)# 国际学生占比list_guoji_xuesheng = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" ind-col ind-14"]')for li_guoji_xuesheng in list_guoji_xuesheng:guoji_xuesheng = li_guoji_xuesheng.find_element(By.XPATH,'./div/div').text# 保存数据到列表guoji_xuesheng_all.append(guoji_xuesheng)# 国际教师占比list_guoji_jiaoshi = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" ind-col ind-14"]')for li_guoji_jiaoshi in list_guoji_jiaoshi:guoji_jiaoshi = li_guoji_jiaoshi.find_element(By.XPATH,'./div/div').text# 保存数据到列表guoji_jiaoshi_all.append(guoji_jiaoshi)

滚轮翻页

前面我们已经完成了页面数据的获取,不过获取的只是第一页的25条数据,想要获取更多的数据,需要我们去实现翻页然后再调用获取数据信息的代码来去获取新的数据,从而实现我们1000条数据的目标。

如何实现翻页呢?

我么看下页面(下图),想要实现翻页,首先要操作右侧的滚动条下拉,到达能显示翻页元素的位置,然后获取向后翻页的元素按钮,点击实现翻页。

第一步 :先实现滚动条下滑
通过selenium控制滚动条,实现向下滑动。

# 滚动滑轮下滑, = 2500 为向下滑动的距离,这个数值可以根据实际情况调整。driver.execute_script("document.documentElement.scrollTop=2500")# 通过设置sleep时间来控制爬虫的速度,根据情况,也可不用。看心情time.sleep(1)

效果如下:

第二步:实现翻页
实现翻页只需要获取到下一页按钮元素的定位信息,然后再操作鼠标点击,就完成了向下翻页的效果。不需要去获取页码,那样太麻烦。

通过selenium实现鼠标点击,进行翻页。

# 控制鼠标点击进行翻页driver.find_element(By.XPATH,'//*[@id="qs-rankings-indicators_next"]').click()# 通过设置sleep时间来控制爬虫的速度,根据情况,也可不用。看心情time.sleep(1)

滚动翻页效果:

到这一步基本上已经把获取数据的操作功能全部都实现了,后面只需要构建循环,让爬虫自动去爬取数据就ok了。

构建循环自动爬取数据

在构建循环的时候遇到一个问题,在滚动条下滑翻页的时候,第一次翻页需要向下滑动的距离长一些,之后所有的下滑距离都是一样的,那么就需要把第一次翻页单独的执行后,之后的翻页可以用循环的形式来不停的实现翻页。
具体代码如下(截止目前所有代码):

# 导入需要的模块from selenium import webdriverfrom selenium.webdriver.chrome.service import Servicefrom selenium.webdriver.common.by import Byimport timeimport pandas as pd# 创建空的数据列表用来保存数据# 排名rank_all = []# 大学名称name_all = []# 大学详情链接地址href_all = []# 综合得分scor_all = []# 学术声誉xueshu_all = []# 雇主声誉guzhu_all = []# 每位教员引用率jiaoyuan_all = []# 师生比shishengbi_all = []# 国际学生占比guoji_xuesheng_all = []# 国际教师占比guoji_jiaoshi_all = []def get_text():# rank排名list_rank = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" rank"]')for li_rank in list_rank:rank = li_rank.find_element(By.XPATH,'./div/div').text# 保存数据到列表rank_all.append(rank)# name大学名称list_name = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" uni"]/div/div')for li_name in list_name:name = li_name.find_element(By.XPATH,'./a').text# 保存数据到列表name_all.append(name)# href大学详情链接地址list_href = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" uni"]/div/div')for li_href in list_href:href = li_href.find_element(By.XPATH,'./a').get_attribute('href')# 保存数据到列表href_all.append(href)# 综合得分list_scor = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class="ind-col ind-overall sorting_1"]')for li_scor in list_scor:scor = li_scor.text# 保存数据到列表scor_all.append(scor)# 学术声誉list_xueshu = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" ind-col ind-76"]')for li_xueshu in list_xueshu:xueshu = li_xueshu.find_element(By.XPATH,'./div/div').text# 保存数据到列表xueshu_all.append(xueshu)# 雇主声誉list_guzhu = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" ind-col ind-77"]')for li_guzhu in list_guzhu:guzhu = li_xueshu.find_element(By.XPATH,'./div/div').text# 保存数据到列表guzhu_all.append(guzhu)# 每位教员引用率list_jiaoyuan = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" ind-col ind-73"]')for li_jiaoyuan in list_jiaoyuan:jiaoyuan = li_jiaoyuan.find_element(By.XPATH,'./div/div').text# 保存数据到列表jiaoyuan_all.append(jiaoyuan)# 师生比list_shishengbi = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" ind-col ind-36"]')for li_shishengbi in list_shishengbi:shishengbi = li_shishengbi.find_element(By.XPATH,'./div/div').text# 保存数据到列表shishengbi_all.append(shishengbi)# 国际学生占比list_guoji_xuesheng = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" ind-col ind-14"]')for li_guoji_xuesheng in list_guoji_xuesheng:guoji_xuesheng = li_guoji_xuesheng.find_element(By.XPATH,'./div/div').text# 保存数据到列表guoji_xuesheng_all.append(guoji_xuesheng)# 国际教师占比list_guoji_jiaoshi = driver.find_elements(By.XPATH,'//*[@id="qs-rankings-indicators"]/tbody/tr//td[@class=" ind-col ind-14"]')for li_guoji_jiaoshi in list_guoji_jiaoshi:guoji_jiaoshi = li_guoji_jiaoshi.find_element(By.XPATH,'./div/div').text# 保存数据到列表guoji_jiaoshi_all.append(guoji_jiaoshi)# 设置浏览器路径servic = Service(executable_path =r'***/chromedriver.exe')driver = webdriver.Chrome(service=servic) # 获取网页driver.get("https://www.qschina.cn/university-rankings/world-university-rankings/2023")time.sleep(2)# 定位要找的元素# 调用鼠标操作方法driver.find_element(By.XPATH,'//*[@id="qs-rankings-datatables"]/div[1]/ul/li[2]/a').click()time.sleep(2)# 获取第一页数据#####################get_text()# 获取第二页数据 ########################## 滚动东滑轮下滑driver.execute_script("document.documentElement.scrollTop=2500")time.sleep(2)# 进行翻页driver.find_element(By.XPATH,'//*[@id="qs-rankings-indicators_next"]').click()# 获取第二页数据get_text()time.sleep(1.5)# 从第三页开始 循环爬取######## 此处page设置需要的页数page = 40i = 1# 由于前面已经获取了两页数据,用page-2 来把页数统一while i <= page-2:driver.execute_script("document.documentElement.scrollTop=2100")time.sleep(2)# 进行翻页driver.find_element(By.XPATH,'//*[@id="qs-rankings-indicators_next"]').click()# 获取第三页数据get_text()time.sleep(0.5)i += 1

数据储存

前面已经完成了所有的数据获取,并且都储存在指定的列表中了,下面就只需要把这些数据导出保存到电脑中。python中处理数据,尤其是表的形式,用pandas最方便一些。
代码如下():

# 数据合并为数据表data = pd.DataFrame({'排名':rank_all,'中文名称':name_all,'详情链接':href_all,'综合得分':scor_all,'学术声誉':xueshu_all,'雇主声誉':guzhu_all,'每位教员引用率':jiaoyuan_all,'师生比':shishengbi_all,'国际学生占比':guoji_xuesheng_all,'国际教师占比':guoji_jiaoshi_all})# 保存为CSV文件data.to_csv('QS世界大学排名.csv',index=False)# 下面代码可用可不用#查看数据前5行,可以检查下数据看是想要的样子data.head()

第二部分

前面第一部分数据获取完毕之后,第二部分就比较简单了,就是通过前面获取到的每个学校的详情页链接中的:高校性质、研究成果、学生人数、教员人数、国际学生人数。

使用requests配合xpath就可以完成数据获取了。

导入需要用到的python包

import pandas as pdimport requestsfrom lxml import etreeimport time

获取网页

使用requests时最好设置请求头,也算是一种最简单的防止反扒的措施,关于反扒每个网站都不一样,比如第一部分使用selenium来获取数据,也是一种防止反扒的手段,因为用简单requests是获取不到想要的数据,页面数据是动态加载的。

设置请求头

如何设置请求头,可以到网上搜索很容易就找到设置方法。就不再细说这块了。

# 设置请求头header = {'user-agent':'****'}

读取链接

使用pandas读取前面获取到的数据,其实我们只需要两列数据,中文名称和详情链接。名称用来在合并数据的时候去对应数据不会弄乱,详情链接就是我们需要获取数据的目标地址了。

# 读取数据df = pd.read_csv('./QS世界大学排名.csv')# 只保留需要用到的两列数据df = df[['中文名称','详情链接']]# 查看数据前5行df.head()

获取网页信息

在获取网页数据的时候,我们可以先用其中一个链接去构建爬虫代码,只要一个网页的数据获取到了,那么其他的网页格式只要是一样的,就可以构建循环去遍历全部的地址获取数据就可以了。

下面就拿第一个链接来去获取数据信息。

# 先用一个链接去搭建代码url = df['详情链接'][0]# 请求网页html = requests.get(url=link,headers=header)# 把请求到的网页转换为xpath提取样式,方便下面通过xpath直接提取数据信息。text = etree.HTML(html.text)

定位节点获取数据

通过选取节点,然后查看页面代码,可以看到,这些数据都在同一个ul中,不同的信息存在不同的li中,下面我们就可以编写代码来获取数据。

# 同样我们要新建几个空列表用来存储不同的数据信息。name_all = []title_all = []info_all = []# 获取要爬取内容的所有标签list_all = text.xpath('//div[@class="uni_snapshot"]/ul/li')for li in list_all:title = li.xpath('./span/text()')[0]info = li.xpath('./span/b/text()')[0]

获取到需要的数据后,下面我们就要构建循环去把1000所学校的信息都获取到,然后把数据保存为csv格式。

第二部分完整代码如下:

# 导入需要的模块import pandas as pdimport requestsfrom lxml import etreeimport time# 读取数据df = pd.read_csv('./QS世界大学排名.csv')df = df[['中文名称','详情链接']]# 设置请求头header = {'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.58'}# 创建空列表储存数据name_all = []title_all = []info_all = []# 遍历全部数据,构建循环爬取for i in range(len(df)):name = df['中文名称'][i]link = df['详情链接'][i]# 请求网页html = requests.get(url=link,headers=header)# 把请求到的网页转换为xpath提取样式,方便下面通过xpath直接图区text = etree.HTML(html.text)# 获取要爬取内容的所有标签list_all = text.xpath('//div[@class="uni_snapshot"]/ul/li')for li in list_all:title = li.xpath('./span/text()')[0]info = li.xpath('./span/b/text()')[0]# 把数据存入列表name_all.append(name)title_all.append(title)info_all.append(info)# 显示爬取到第几个学校 print(name,'*** OK ***','{}/1000'.format(i+1))# time.sleep(0.5)# 把数据合并为数据表data = pd.DataFrame({'name':name_all,'title':title_all,'info':info_all})# 把数据保存为csvdata.to_csv('详细内容.csv',index=False)

第二部分获取到的数据样式如下,是以长表的形式保存的,第一部分的数据是宽表的形式保存的,所以下面还需要把第二部分的数据合并到第一部分,形成完整的数据表。

第三部分

合并第一部分和第二部分的数据,我这里用的方法比较简单,略显笨拙,应该会有更简便的方法,不过能干活就行。

读取数据

处理数据只用了pandas,所以只需要导入一个pandas就行了

import pandas as pd# 读取第一部分数据df_1 = pd.read_csv('./QS世界大学排名.csv')# 读取第二部分数据df_2 = pd.read_csv('./详细内容.csv')

部分数据样式

合并数据

合并数据的流程就是,把表df_2中需要的数据按照title中的分类去分别提取出来,然后合并到df_1中。
代码如下:

# 先把df_2中的高校性质提取出来,保留学校name和info两列gaoxiaoxingzhi = df_2[df_2.title =='高校性质'][['name','info']]# 重新设置两列的名称,使的数据中高校的名称这一列的列名和df_1中的一样,方便合并数据。gaoxiaoxingzhi.columns = ['中文名称','高校性质']

如下样子:

然后把数据合并到df_1中。

df_1 = df_1.merge(gaoxiaoxingzhi,how='left',on='中文名称')

合并后如下:数据最右边就多了一列数据

后面几列数据合并方法一样,下面是完整的合并数据代码:

# 导入pandasimport pandas as pd# 读取数据df_1 = pd.read_csv('./QS世界大学排名.csv')df_2 = pd.read_csv('./详细内容.csv')# 合并 高校性质gaoxiaoxingzhi = df_2[df_2.title =='高校性质'][['name','info']]gaoxiaoxingzhi.columns = ['中文名称','高校性质']df_1 = df_1.merge(gaoxiaoxingzhi,how='left',on='中文名称')# 合并 研究成果yanjiuchengguo = df_2[df_2.title =='研究成果'][['name','info']]yanjiuchengguo.columns = ['中文名称','研究成果']df_1 = df_1.merge(yanjiuchengguo,how='left',on='中文名称')# 合并 学生人数xuesheng = df_2[df_2.title =='学生人数'][['name','info']]xuesheng.columns = ['中文名称','学生人数']df_1 = df_1.merge(xuesheng,how='left',on='中文名称')# 合并 教员人数jiaoyuan = df_2[df_2.title =='教员人数'][['name','info']]jiaoyuan.columns = ['中文名称','教员人数']df_1 = df_1.merge(jiaoyuan,how='left',on='中文名称')# 合并 国际学生人数guojixuesheng = df_2[df_2.title =='国际学生人数'][['name','info']]guojixuesheng.columns = ['中文名称','国际学生人数']df_1 = df_1.merge(guojixuesheng,how='left',on='中文名称')# 保存数据df_1.to_csv('QS世界大学排名前1000数据.csv',index=False)

全部数据合并后:

完成 !!

全部代码:
上传审核中