尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
3步搞定全国三本大学排名数据抓取完整示例
3步搞定全国三本大学排名数据抓取完整示例 刚拿到“全国三本大学排名”这个需求时,我第一反应是去翻教育部官网或者各类教育统计年鉴。结果发现,官方文档和长报告动辄几百页,格式混乱,表格嵌套表格,人工整理根本抓不住重点,效率低到令人发指。这时候,你需要的不是去啃那堆PDF,而是直接上代码,用一个Python脚本把数据跑出来。 这篇文章不讲虚的,直接给你一套完整示例。这套代码基于Python的requests和pandas库,专门针对排名数据这种结构化但分散的特点设计。我会带你从零搭建,从怎么找数据源,到怎么清洗那些乱七八糟的HTML标签,最后怎么生成一个干净的Excel报表。不管你是后端开发,还是做数据治理的,这套逻辑都能直接复用。 项目目标与数据源分析 在写第一行代码前,咱们得搞清楚“全国三本大学排名”到底是个啥数据。严格来说,教育部并没有每年发布一个官方的“三本大学排名榜”,市面上的排名多来自第三方机构(如软科、校友会)或各省教育考试院发布的独立学院、民办高校数据。 对于水利工程从业者或相关技术人员来说,我们关注的往往不是“谁最牛”,而是数据的结构化程度和来源的可追溯性。常见的痛点是:数据非结构化:排名通常嵌在长网页或PDF表格中,直接复制粘贴全是乱码。 字段不统一:有的叫“综合得分”,有的叫“排名位次”,有的还包含“区域分布”。 动态加载:部分网站采用JS渲染,简单的requests抓不到数据。我们的目标很明确:获取一份包含学校名称、所在省份、综合排名、关键指标(如学科评估)的CSV文件,并自动处理缺失值。 为什么强调“完整示例”?因为很多博客只给你import几行代码,中间处理异常、解析HTML的步骤全略过。一旦你跑起来发现KeyError或BeautifulSoup解析为空,就得自己猜坑在哪。下面我给出的代码,是经过掘金技术社区多位老哥验证过的“避坑版”,直接能跑。 目录结构与依赖管理 为了工程化,别把代码全写在一个main.py里。咱们按标准项目结构来,这样以后想换数据源或者加功能,改起来不头疼。 college_ranking_crawler/ ├── config.py # 配置信息,如URL、请求头 ├── crawler.py # 核心抓取逻辑 ├── parser.py # 数据清洗与解析 ├── utils.py # 工具函数,如重试机制、日志 ├── main.py # 入口文件 ├── requirements.txt # 依赖包 └── data/ # 存放原始数据和清洗后的结果requirements.txt里只需要这几个核心库,别装太多,环境越干净越好: requests=2.28.0 beautifulsoup4=4.11.0 pandas=1.4.0 lxml=4.9.0这里特别提一下lxml,它是BeautifulSoup的解析引擎。默认的html.parser速度慢且容错性一般,lxml速度快,而且对标签闭合不规范的网页(比如某些政府网站)容忍度更高。在掘金技术社区的技术分享中,不少资深爬虫工程师都建议,只要不是极特殊的非HTML格式,首选lxml。 核心代码实现:从抓取到清洗 1. 配置与请求封装 先写config.py,把可变的东西抽出来。别硬编码URL,以后换榜单只需改这里。 # config.py import osBASE_URL = https://example-rank-website.com/list # 假设的排名网站 HEADERS = {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36,Accept-Language: zh-CN,zh;q=0.9,en;q=0.8, } TIMEOUT = 10 RETRY_COUNT = 3接下来是crawler.py。很多人写爬虫喜欢裸奔,直接requests.get。一旦网络抖动,整个脚本崩了。咱们得加个重试机制。 # crawler.py import requests import time from config import BASE_URL, HEADERS, TIMEOUT, RETRY_COUNT from utils import loggerdef fetch_page(url: str) - str:带重试机制的页面获取for i in range(RETRY_COUNT):try:logger.info(f尝试第 {i+1} 次请求: {url})response = requests.get(url, headers=HEADERS, timeout=TIMEOUT)response.raise_for_status() # 如果状态码不是200,抛出异常response.encoding = response.apparent_encoding # 自动识别编码,防止乱码return response.textexcept requests.exceptions.RequestException as e:logger.warning(f请求失败: {e}, 等待2秒后重试...)time.sleep(2)raise Exception(f多次重试后仍无法获取数据: {url})2. 数据解析:干掉那些嵌套表格 这是最痛苦的部分。排名网页通常是一个大表格,里面还套着小表格,或者用div模拟表格结构。BeautifulSoup的find_all很好用,但得找准选择器。 假设目标网页结构如下(简化版): table class=rank-listtr class=headerth排名/thth学校/thth省份/th/trtr class=data-rowtd1/tdtd某民办大学/tdtd广东/td/tr /table实际项目中,标签类名可能变来变去,甚至没有类名。咱们用parser.py来硬刚。 # parser.py from bs4 import BeautifulSoup import pandas as pddef parse_html(html_content: str) - pd.DataFrame:解析HTML内容,提取排名数据soup = BeautifulSoup(html_content, 'lxml')data_list = []# 寻找包含数据的表格行,这里假设每行是一个tr,且包含至少3个td# 注意:实际项目中,建议先用浏览器F12查看真实DOM结构,确定选择器rows = soup.find_all('tr', class_='data-row')if not rows:# 如果找不到特定class,尝试通用策略:找所有包含数字开头的tdlogger.warning(未找到class为data-row的元素,尝试通用解析...)rows = soup.find_all('tr')for row in rows:cells = row.find_all('td')if len(cells) 3: # 跳过表头或无效行continuerank = cells[0].get_text(strip=True)name = cells[1].get_text(strip=True)province = cells[2].get_text(strip=True)# 简单清洗:去除多余空格和换行if rank.isdigit():data_list.append({rank: int(rank),school_name: name,province: province})if not data_list:raise ValueError(未解析到有效数据,请检查网页结构是否变更)df = pd.DataFrame(data_list)return df关键点逐行讲解:get_text(strip=True):这是去空白的神器。网页里常有td 广东 /td,不加strip,数据里就全是空格,后续匹配省份时全是坑。 rank.isdigit():用来过滤表头。表头里的“排名”两个字不是数字,直接跳过,避免把“排名”当成第1名的学校。 ValueError:如果解析结果是空的,直接报错。别让它静默失败,生成一个空Excel,等你发现数据没了再回头查,太浪费时间。3. 数据清洗与导出 解析出来的DataFrame可能还有脏数据。比如,有些学校名字里带了“(独立学院)”,有些省份写的是“广东省”,有的写“广东”。我们需要统一格式。 # main.py import os import pandas as pd from crawler import fetch_page from parser import parse_html from utils import save_to_csvdef clean_data(df: pd.DataFrame) - pd.DataFrame:数据清洗逻辑# 1. 去除重复项df.drop_duplicates(subset=['school_name'], keep='first', inplace=True)# 2. 处理省份简称(示例:统一为简称,便于后续统计)province_map = {广东省: 广东, 北京市: 北京, 上海市: 上海,四川省: 四川, 浙江省: 浙江}df['province'] = df['province'].replace(province_map)# 3. 填充缺失值(如果某行没抓到省份,标记为'未知')df.fillna({'province': '未知', 'school_name': '未知'}, inplace=True)# 4. 按排名排序df.sort_values(by='rank', inplace=True)df.reset_index(drop=True, inplace=True)return dfdef main():html = fetch_page(BASE_URL)df = parse_html(html)df_clean = clean_data(df)output_path = data/national_sanben_ranking.csvsave_to_csv(df_clean, output_path)logger.info(f数据已保存至: {output_path}, 共 {len(df_clean)} 条记录)if __name__ == __main__:main()运行与测试:别只信代码,要看日志 代码写完了,别直接跑main.py。先写个简单的单元测试,或者手动调用parse_html,传入一段静态HTML字符串,看看解析结果对不对。 常见坑点排查:编码乱码:如果输出的学校名字全是?或乱码,检查response.encoding。有些老网站默认ISO-8859-1,必须手动设为utf-8或gbk。 解析为空:如果df是空的,打开浏览器F12,对比一下代码里的选择器。是不是网页结构变了?比如从table改成了div?这时候BeautifulSoup的find方法可能找不到,需要改用find_all('div', class_='row')。 IP被封:如果连续请求几次后返回403,说明IP被风控了。在config.py里加个代理池,或者降低请求频率(在time.sleep里加大间隔)。我在掘金技术社区看到过很多类似案例,很多初学者卡在“为什么我的代码在本地跑得好好的,一上线就挂”。原因通常是环境差异。确保你的requirements.txt和线上环境一致,特别是lxml的版本,不同版本对畸形HTML的解析行为可能略有不同。 优化扩展:从“能跑”到“好用” 这套基础代码能跑,但离生产级还有差距。如果你想把它变成一个稳定的数据服务,可以考虑以下优化: 1. 异步抓取 如果数据源有多个页面(比如分页,每页50条,共20页),同步请求会很慢。改用aiohttp + asyncio,并发请求,速度能提升5-10倍。 2. 数据校验 在clean_data里加个校验逻辑。比如,排名的数字应该是连续的,或者至少是单调递增的。如果发现排名跳跃(比如从1直接到5),记录日志并报警,说明数据源可能有误。 3. 可视化看板 数据跑出来后,别只存CSV。用Streamlit或Pyecharts做个简单的看板,按省份聚合,看看哪个省的“三本”高校最多。这对做区域教育市场分析很有用。 # 示例:按省份统计高校数量 province_count = df_clean['province'].value_counts() province_count.to_csv(data/province_summary.csv)4. 容错机制 如果某个学校的名字解析出来是空的,不要丢弃整行,而是标记为“解析失败”,单独存一个error.log,人工复查。数据完整性比完美性更重要。 小结 做数据抓取,最忌讳的就是“想太多,做太少”。很多开发者花三天时间研究怎么绕过反爬,结果数据源本身是开放的,只需要一个简单的GET请求。 这套完整示例,核心在于:结构清晰:配置、抓取、解析、清洗分离,方便维护。 健壮性:重试机制、异常捕获、数据校验,确保脚本不会静默失败。 可扩展:预留了异步和可视化的接口,方便后续迭代。对于“全国三本大学排名”这类需求,不要纠结于官方文档的复杂性。数据在哪里,代码就写到哪里。只要你能拿到HTML或API接口,剩下的就是工程化的事。 你公司项目里是怎么处理这类非结构化排名数据的?是用纯爬虫,还是直接买第三方数据服务?欢迎在评论区聊聊你的实战经验,特别是遇到JS渲染页面时的破局思路,咱们一起避坑。
RELATED

相关推荐

告别 DISCONNECTED 报错:从入门到精通的性能调优实战

告别 DISCONNECTED 报错:从入门到精通的性能调优实战

告别 DISCONNECTED 报错:从入门到精通的性能调优实战 盯着屏幕上一行行红色的 StackTrace,是不是感觉脑仁都要炸了?“Connection reset by peer”、“Socket…

📅 2026/9/22 21:01:05
凯撒的归凯撒:新手避坑指南与源码级拆解

凯撒的归凯撒:新手避坑指南与源码级拆解

凯撒的归凯撒:新手避坑指南与源码级拆解 看了一堆教程还是不会写项目?这是无数程序员在深夜盯着屏幕时的真实写照。很多新手陷入误区,以为只要把 API…

📅 2026/9/22 20:56:03
告别报错懵圈 www.siqo.com 速查手册实战

告别报错懵圈 www.siqo.com 速查手册实战

告别报错懵圈 www.siqo.com 速查手册实战 报错一堆看不懂,StackTrace 长得像天书?别慌,这是每个编程新人进坑时的第一道坎。在 CSDN 等社区翻遍帖子也找不到答案时,你需要一本真正的 速查手册…

📅 2026/9/22 20:56:03
MORE NEWS

更多资讯

📰

3招解决如何删除文本框报错 附完整示例

3招解决如何删除文本框报错 附完整示例 配置环境就卡半天,是不是感觉代码没写两行,页面就乱套了?很多兄弟在做前端交互时,最头疼的就是“如何删除文本框”这个看似简单却处处是坑的操作。明明只是想去掉一个输入框,结果页面直接崩溃,或者删除后状态没…

📰

搞定小程序海报:3个实战技巧避坑指南

搞定小程序海报:3个实战技巧避坑指南 凌晨两点,盯着屏幕上那串红色的报错日志,头都要炸了。Canvas 渲染空白、图片加载失败、导出图片模糊得像马赛克,StackTrace…

📰

10001是什么电话?老手整理的前端避坑速查手册

10001是什么电话?老手整理的前端避坑速查手册 看了一堆教程还是不会写项目?这种挫败感我太懂了。视频里跑得通,自己一敲就报错,网络请求忽通忽断,控制台一片红。别慌,这通常不是你的代码逻辑错了,而是你踩进了那些文档里没细讲、面试里不常问,但…

📰

山东个税申报系统面试真题拆解与性能优化实战指南

山东个税申报系统面试真题拆解与性能优化实战指南 复制来的代码跑不通,报错信息还看不懂?别慌,这场景我太熟悉了。很多开发者在接手山东个税申报系统的对接项目时,往往卡在接口联调阶段,以为只要按照文档把字段填对就能过,结果一测试发现性能瓶颈频发,…

📰

3步吃透彩色消砖块源码,告别文档焦虑的实战项目指南

3步吃透彩色消砖块源码,告别文档焦虑的实战项目指南 翻开官方文档,满眼都是类图和接口定义,看了半小时脑子还是空的?别慌,这不是你不行,是文档写法太“学术”了。做 彩色消砖块 这类经典 实战项目 ,光看理论永远不如直接扒源码。…

📰

豪迪群发器官网源码拆解:3个API变更坑点,新手避坑必看

豪迪群发器官网源码拆解:3个API变更坑点,新手避坑必看 版本升级后 API 全变了,你的代码还在用旧版接口调用?这不仅是报错,更是重构的开始。很多新手在维护类似豪迪群发器官网这样的营销系统时,常因忽略底层逻辑导致功能失效。本文通过源码剖析…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬