简介这份压缩包汇总了US News、软科、QS、THE四大全球大学排名截至2021年11月10日的数据并附有配套Python脚本面向需要做高校对比、留学选校或排名数据分析的研究者与学生。包内共有15个文件包括8个py脚本、4个zip数据包和3个txt说明文件整体约13.21MB。脚本覆盖各排名综合榜与学科榜的抓取和解析利用requests、BeautifulSoup、pandas等工具可自动化下载与清洗数据zip内为各机构原始排名表txt则存放院校链接与名称等辅助信息。借助这些材料使用者既能直接读取2022年最新排名也能通过脚本二次开发开展趋势分析和地区对比。该资源已有1182人学习适合具备一定Python基础、希望获取结构化排名数据的学习者。 每年四大世界大学排名集中放榜的那几周我手机基本都是炸的。学弟学妹问选校到底该看哪个榜单客户问合同里的院校定位按什么口径算连家里亲戚都要我解释同一所帝国理工在QS和软科里为什么差了几十位。问的人多了我干脆把US News、软科、QS、THE 2022世界大学排名数据全部找齐写一个python脚本统一清洗合并成一张表之后谁再问直接把表甩过去。这篇就把整个项目的完整思路讲清楚数据从哪来、字段怎么对齐、学校名怎么统一、脚本怎么写以及我实际跑数据时踩过的坑适合所有准备跟排行榜数据打交道的人参考。1. 四个榜单四种游戏规则合并之前先看清它们怎么排1.1 各榜单的指标重心差异做数据脚本的第一步不是写代码而是先理解数据背后的规则。四个榜单看着都在给大学排名实际上它们的考核口径差异很大这决定了合并后的字段设计和分析逻辑。榜单发布方核心指标倾向直观特点US News全球大学排名《美国新闻与世界报道》全球学术声誉、论文引用、专著、国际合作医学与理工科学校占优学校规模越大有优势软科世界大学学术排名ARWU上海软科教育信息咨询诺奖/菲尔兹奖、高被引学者、Nature/Science论文、国际论文纯学术成果导向不碰声誉问卷QS世界大学排名Quacquarelli Symonds学术声誉、雇主声誉、师生比、国际教师/学生比例声誉类指标权重高英语区学校天然吃香THE世界大学排名泰晤士高等教育教学、研究、引用、国际展望、产业收入比QS更偏引用与科研产出指标体系最细一句话总结软科看硬成果US News和THE看科研影响QS看声誉。同一个学校在不同榜单排名相差很大是正常现象不是你眼睛出了问题。1.2 “2022年”的版本陷阱处理这些数据时第一个坑就是“2022年”本身有歧义。四个榜单的发布时间并不同步QS在2022年6月发布的是QS World University Rankings 2023THE在2022年10月发布的是THE World University Rankings 2023US News在2022年10月发布的是2022-2023 Best Global Universities Rankings只有软科在2022年8月发布的是ARWU 2022。如果你笼统地把它们称为“2022排名”那么QS 2022和QS 2023其实相差整整一年。我在脚本里把“2022”定义为榜单版本号或发布年份而不是自然年。也就是说如果用户传--year 2022脚本默认匹配的是软科2022、QS 2023、THE 2023、US News 2022-2023。这样既符合大多数人口中“2022年发布的世界大学排名”又避免了版本混乱。你在复现时也可以按自己需要调整参数化的好处就在这。1.3 为什么非要合并成一张表把四个榜单合并不只是为了省去来回切换网页的麻烦。合并之后可以做很多单张表做不了的事对比学校在不同体系里的位次差、计算排名极差识别稳定性、筛选出某一地区在四个榜单都进入前100的学校。这些分析对留学选校、合作评估、乃至自媒体内容创作都有实际价值。所以这个项目不是简单爬虫而是一个典型的数据清洗与集成任务。2. 数据从哪来软科Excel、THE的CSV、QS的导出和US News的网页表格2.1 软科官方Excel是最省事的入口软科官网每年会提供世界大学学术排名的完整数据下载常见格式是Excel。这份表格里的字段一般是学校排名、学校名称、国家/地区、总分等信息非常规整个人研究用起来很舒服。用pandas读取时需要注意工作区有些年份的表格不是第一个sheet就是数据建议先打印sheet名和表头确认一下。df pd.read_excel(arwu_2022.xlsx, engineopenpyxl, sheet_name0) print(df.head())软科也有中文版和英文版表格字段名不同中文版是“学校名称”英文版是“University”。为了统一脚本我建议下载英文版实在只能拿到中文版也没有关系后面做字段映射时一并处理。2.2 QS和THECSV顺手但字段名各不相同THE官网排名页面提供了CSV格式的数据字段基本是Rank、Name、Country、Score之类读起来比较直接。QS虽然有时需要从网页表格里复制但官网排名页也会开放数据导出入口。重点提醒一句QS页面里的Rank列经常出现10这样的写法THE在部分年份会把“501-600”这种区间直接塞进Rank列这些都不能直接用int()转换。df_the pd.read_csv(the_2023.csv, encodingutf-8-sig) df_qs pd.read_csv(qs_2023.csv, encodingutf-8-sig)字段名在不同年份可能发生变化不要写死。我每次拿到新数据都会先打印所有列名。2.3 US News必须抓网页时的正确姿势US News的Best Global Universities ranking没有像软科那样直接的Excel下载更多时候需要通过网页表格抓取。好在它的排名表是标准HTML表格可以直接用pandas的read_html解析。页面如果做了分页就循环拼接如果页面比较慢要设置headers和请求间隔。tables pd.read_html(usnews_2022.html) df tables[0]这里我的经验是先把网页保存成HTML文件再解析而不是每次都实时请求。这样一方面减少被网站限制的风险另一方面数据版本也更可控。抓取时设置一个常见的User-Agent请求间隔控制在1秒以上遇到验证码或访问异常就停下来不要硬刚。2.4 数据使用的合规底线判断哪些能抓哪些不能抓我的原则是优先下载官方公开数据其次用pd.read_html解析静态表格绝不去绕过登录、验证码或付费墙。这些排名数据用于个人学习、课堂演示、博客分析没有问题但如果要做商业发布或批量转售必须对照各官网的使用条款。脚本里我也只在代码注释里写了数据来源不附带任何抓取破解逻辑省得给读者和自己惹麻烦。3. 脚本设计的关键决策字段映射、学校名统一和参数传递3.1 字段到底怎么映射四份数据的原始字段各不相同合并前必须统一成一套标准字段。我常用的标准字段是rank_raw: 原始排名字符串如 10、101-150 rank_int: 用于排序的整数排名 school: 学校标准名称 country: 国家/地区 score: 总分如果有 source: 榜单来源USNews / ARWU / QS / THE year: 版本年份不同来源的原始字段要通过一个映射字典转换。数据源原始排名字段学校名字段国家字段分数段软科排名学校名称 / University国家/地区总分QSRankUniversityLocationOverallTHERankNameCountryScoreUS NewsRankUniversityLocationGlobal Score这一步看起来简单但我建议不要直接把原始列名改掉而是保留一份原始数据再加一列新字段。做数据清洗时最怕的是不可回溯。3.2 学校名称统一是最大的体力活四份数据合并时最耗时间的不是写代码而是处理同一所学校的多种写法。同一所加州大学伯克利分校在US News里写作University of California--Berkeley软科英文版写作University of California, Berkeley中文版直接写“加州大学伯克利分校”。如果你不做统一合并后同一个学校会被拆成三条记录分析结果完全不能用。我的处理方案是三层兜底先写一个normalize_name函数把所有名称转成小写、去掉标点、压缩空格再维护一个手动别名映射表把确认过的别名指向标准名最后跑完合并再抽检看看哪些学校出现了多条记录。别指望正则一次性解决所有问题教育机构名称的写法太散了人工核对必不可少。3.3 让主脚本通过命令行参数调度子脚本涉及“python给另一个py脚本传递参数”的常见场景就是我把项目拆成了多个脚本。主脚本负责调度子脚本负责处理单个榜单这样任何一个榜单更新了我只重跑对应的子脚本就行。python main.py --year 2022 --sources qs the arwu usnews --output merged_2022.csv python process_single_rank.py --source qs --year 2022 --output data/qs_2022_clean.csv在Python里子脚本内部用argparse解析参数主脚本用subprocess.run把参数传过去。import subprocess subprocess.run([ python, process_single_rank.py, --source, arwu, --year, 2022, --output, data/arwu_clean.csv ])也完全可以不通过子进程直接把子脚本写成函数用函数参数传递source和year。我之所以用命令行拼接是因为这样每个子脚本都能独立运行调试单个数据源时不需要把整个流程跑一遍。4. 可运行的完整示例四榜合并的Python实现下面是我这个项目里精简过的核心代码可以直接跑通“读取四个数据源 - 清洗标准化 - 合并导出”的完整流程。你只需要把下载好的原始文件放进data目录然后运行命令行参数。import argparse import re import pandas as pd ALIASES { university of california berkeley: university of california berkeley, university of california, berkeley: university of california berkeley, university of california--berkeley: university of california berkeley, university of cambridge: university of cambridge, university of oxford: university of oxford, } def parse_rank(raw): 将排名文本转成可排序的整数。 10 - 10, #5 - 5, 101-150 - 101 if pd.isna(raw): return None text str(raw).strip().lstrip(#) match re.match(r(\d), text) return int(match.group(1)) if match else None def normalize_name(name): if not isinstance(name, str): return text name.lower() text text.replace(--, ).replace(,, ) text re.sub(r[^a-z0-9\u4e00-\u9fff ], , text) text re.sub(r\s, , text).strip() return ALIASES.get(text, text) def safe_extract(df, mapping, columns): for target, src in mapping.items(): if src in df.columns: df[target] df[src] else: df[target] None return df[columns] def load_shanghai(path): df pd.read_excel(path, engineopenpyxl) df safe_extract(df, { rank_raw: 排名, school: 学校名称, country: 国家/地区, score: 总分, }, [rank_raw, school, country, score]) df[source] ARWU return df def load_qs(path): df pd.read_html(path)[0] df safe_extract(df, { rank_raw: Rank, school: University, country: Location, score: Overall, }, [rank_raw, school, country, score]) df[source] QS return df def load_the(path): df pd.read_csv(path, encodingutf-8-sig) df safe_extract(df, { rank_raw: Rank, school: Name, country: Country, score: Score, }, [rank_raw, school, country, score]) df[source] THE return df def load_usnews(path): df pd.read_html(path)[0] df safe_extract(df, { rank_raw: Rank, school: University, country: Location, score: Global Score, }, [rank_raw, school, country, score]) df[source] USNews return df def merge_rankings(sources, year): loader_map { arwu: load_shanghai, qs: load_qs, the: load_the, usnews: load_usnews, } frames [] for source in sources: path fdata/{source}_{year}.csv if source arwu: path fdata/{source}_{year}.xlsx print(floading {path}) frames.append(loader_map[source](path)) merged pd.concat(frames, ignore_indexTrue) merged[rank_int] merged[rank_raw].apply(parse_rank) merged[school_norm] merged[school].apply(normalize_name) merged[year] year return merged def main(): parser argparse.ArgumentParser(descriptionMerge university rankings) parser.add_argument(--year, default2022) parser.add_argument(--sources, nargs, default[arwu, qs, the, usnews]) parser.add_argument(--output, defaultmerged_rankings.csv) args parser.parse_args() result merge_rankings(args.sources, args.year) result.to_csv(args.output, indexFalse, encodingutf-8-sig) print(fsaved: {args.output}, rows: {len(result)}) if __name__ __main__: main()运行方式python merge_rankings.py --year 2022 --sources qs the arwu usnews --output all_2022.csv这段代码里safe_extract是我觉得比较重要的一个函数遇到列名对不上的情况它不会报错而是填None。这是因为不同年份、不同版本的榜单列名经常微调留一个可见的缺失值比让整个脚本崩溃好很多。5. 实测踩坑记录区间排名、等号、编码和地区字段5.1 “101-150”这类区间排名不能直接转整数软科和THE都有区间排名比如“101-150”“201-300”。如果你直接int(101-150)Python会直接报错。我在parse_rank里用正则只取第一个数字也就是把区间下限当作排序依据。这样处理之后101-200排名的学校会排在101位和真正第101名的学校并列虽然不完美但足够排序使用。如果非要更精确一点可以生成一个rank_display字段保留原始字符串再生成rank_int用于排序。这样最终Excel里既能看到原始区间也能参与排序和筛选。data[rank_display] data[rank_raw] data[rank_int] data[rank_raw].apply(parse_rank)5.2 QS的号和THE的区间号QS排名里10表示并列第十如果不处理字符串转整数会失败。我在parse_rank中先lstrip(#)把等号和井号去掉。THE同样会有区间排名甚至不同年份区间格式还不一样有的写“501-600”有的写“401–500”注意中间是短横线不是标准连字符。正则(\d)能兼容这两种情况因为它只要找到第一串数字就够了。处理这些脏数据最关键的习惯是永远先打印数据分布看看rank_raw这个字段到底有多少种非数字写法。5.3 CSV编码肉眼看不见的BOM从官网下载的CSV很多是UTF-8带BOM的格式。如果用默认参数读表头第一列会出现一个看不见的\ufeff字符导致列名匹配不上。我在读CSV时固定用encodingutf-8-sig输出合并结果时也用utf-8-sig。这样文件在Excel里打开也不会乱码中文学校名能正常显示。5.4 地区字段的对照包袱不同榜单对国家和地区的写法差异很大US News和QS喜欢用“USA”“United States”软科中文版直接写“美国”THE有时写“United States of America”。香港和台湾的写法更是五花八门。我的做法是单独建一个地区映射字典把常见写法统一成标准中文或标准英文不要试图在清洗函数里写死所有分支。5.5 学校名里的撇号与特殊符号伦敦大学国王学院写作Kings College London正常化时会去掉撇号变成kings college london但有些榜单写作Kings College London有些写作Kings College London处理之后能对上。真正麻烦的是那些带特殊字符的欧洲学校比如“Universität”和“Université”经过正则清洗后都会变成“universit”正好落进同一批很难区分。遇到这种问题我的建议是维护手动映射表把这类学校在四个榜单的写法全部人工核对一遍。虽然累但这是唯一可靠的办法。6. 合并数据之后我实际拿来做的三类分析6.1 找偏科学校谁在软科很强却不在QS榜单前列合并表最有价值的应用之一是快速识别“偏科”学校。比如加州大学旧金山分校是一所医学研究生院在US News全球排名里能排在非常靠前的位置但到了QS体系里因为主要依赖声誉和本科指标排名一下子就跌到很难找到。用合并表做筛选条件很简单source ARWU且rank_int 50同时source QS且rank_int 100。列出来之后你对这些学校的定位会立刻清晰很多。这种“偏科学校”恰恰是很多人选校时最容易误解的地方。6.2 中国高校在不同榜单中的排位差异拿国内高校来说清北复交、浙大、上交这些学校无论哪个榜单都稳居前列但具体名次波动非常大。理工科强校在软科和US News里通常更靠前因为这两个榜单更看重论文和引用而QS因为雇主声誉权重高综合性大学和商科强的学校表现会更亮眼。这些差异不是谁错了而是指标选择的结果。把四列排名放到同一张表里看比单独盯一个榜单容易理解得多。我常用的一行代码是把每个学校在四个榜单的排名转成长表再做一次透视pivot merged.pivot_table( indexschool_norm, columnssource, valuesrank_int, aggfuncmin )这个透视结果就是一张校园对比表下一步无论是排序还是画图都很方便。6.3 稳定性分析排名起伏很大的学校要留意合并数据还能帮你判断一所学校的排名“性格”。有的学校四个榜单排名都稳定在前50说明各方共识高有的学校在QS排第30在软科却排到第150这种巨大落差本身就是信息。在学校名对齐之后计算每个学校的排名极差或者标准差非常容易。pivot[max_rank] pivot.max(axis1) pivot[min_rank] pivot.min(axis1) pivot[spread] pivot[max_rank] - pivot[min_rank]对于申请者来说如果一所学校排名极差过大你需要多确认一步它是某一领域特别强导致的指标偏科还是近年来实力波动比较大。纯粹追求排名稳定的读者可以优先锁定那些四个榜单都排名靠前、极差又小的学校。6.4 可视化扩展散点图一眼看清格局合并表同样适合可视化。用matplotlib或plotly画一张散点图横轴是QS排名纵轴是THE排名每个点是一所学校感兴趣的话还可以把点大小映射成软科排名。看到点的分布后你会很直观地感受到不同榜单的差异程度。这个操作不需要写太多代码但做出来的图很适合扔进PPT或者直接发到朋友圈。7. 一点个人习惯这套脚本后来我又改过好几版合并逻辑一直没有大动。最后分享一个我踩坑之后养成的习惯每次下载原始数据文件我都会在文件名后加上榜单名和发布日期例如qs_20230610.csv、the_20221012.csv。这样脚本处理出错时我能根据日期快速回溯到对应版本而不是对着一个叫final.csv的文件发呆。数据源随时可能改格式脚本最怕的就是原始文件已经变了而你还不知道。本文还有配套的精品资源点击获取
