2025 年全国高考投档线数据批量爬取实战:从 31 省教育考试院提取原始 PDF/Excel

2025 年全国高考投档线数据批量爬取实战:从 31 省教育考试院提取原始 PDF/Excel

项目背景 :2025 年是全国新高考改革的落地之年,各省投档线数据格式、公开政策差异巨大。本文记录了一次完整的批量爬取过程,最终成功下载 64 份原始投档线文件 ,覆盖 12 个省份,并总结出一套可复制的工作流。


附:爬取技能下载链接:https://pan.quark.cn/s/03d7ee1a08f8

一、为什么需要批量爬取?

每年 7-8 月,全国 31 个省级教育考试院会陆续发布当年高考各批次的投档线/录取数据。这些数据对于以下场景至关重要:

  • 高考志愿填报工具开发:需要结构化历史数据做推荐算法
  • 教育数据分析:研究各省录取趋势、热门专业冷热变化
  • 自媒体/升学规划:整理各省分数线对比文章

但问题是:数据极其分散。每个省有自己的考试院官网、不同的文件格式(PDF/XLS/XLSX)、不同的发布方式(直接下载/在线查询/仅考生可查)。手动逐个下载耗时巨大,且容易遗漏。


二、数据源分析:从"入口页"到"各省详情页"

2.1 核心入口:中国教育在线

经过多次搜索验证,发现中国教育在线eol.cn)每年会汇总各省投档线发布页面,是最佳的爬取入口:

复制代码
https://www.eol.cn/e_html/gk/gktoudang/index.shtml

这个页面包含 31 个省份的导航锚点,以及每个省对应的详情页链接,格式高度规律:

复制代码
https://gaokao.eol.cn/{省份拼音}/dongtai/202507/t202507{日}_{编号}.shtml

提取方法

bash 复制代码
# 一步提取所有 2025 年 7 月的省份详情页链接
curl -s "https://www.eol.cn/e_html/gk/gktoudang/index.shtml" -o /tmp/eol.html
grep -oP 'href="https://gaokao.eol.cn/[^"]+/dongtai/202507/t202507[^"]+\.shtml"' /tmp/eol.html \
  | sed 's/href="//;s/"$//' | sort -u > eol_links.txt

实测一次提取到 100 条 2025 年 7 月各省投档线相关页面。

2.2 各省附件链接的 5 种形态

进入每个省份的详情页后,需要解析出指向原始数据文件<a> 标签。各省链接形态差异很大,总结如下:

类型 示例 URL 特点
直接 PDF https://www.bjeea.cn/uploads/soft/250719/178-250G9223234.pdf 最友好,直接下载
带参数 PDF https://www.cqksy.cn/.../xxx.pdf?fileName=...&fileSize=... 扩展名提取易出错
直接 XLS https://www.zjzs.net/attach/0/xxxx/xxxx.xls 旧版 Excel 格式
直接 XLSX http://file.hebeea.edu.cn/files/article/2025/07/xxxx.xlsx 新版 Excel 格式
下载系统跳转 https://www.hljea.org.cn/system/_content/download.jsp?... 需要 session,常失败

三、技术难点与解决方案

难点 1:URL 参数污染导致扩展名提取错误

重庆的链接如下:

复制代码
https://www.cqksy.cn/.../xxx.pdf?fileName=2025xxb.pdf&fileSize=1033364

如果直接用 url.split('.')[-1],会得到 pdf&fileName=2025xxb,脚本判断不是标准扩展名,会 fallback 成 .bin

解决方案:用正则先截断查询参数:

python 复制代码
# 安全提取扩展名
ext = url.split('.')[-1].split('?')[0].split('&')[0][:4].lower()
if ext not in ['pdf', 'xls', 'xlsx']:
    ext = 'bin'  # 先存为 bin,后续用文件头修复

难点 2:SSL 握手失败

湖南的 hneeb.cn 域名使用较老的 SSL 配置,直接用 requests.get() 会报错:

复制代码
SSLError: SSLV3_ALERT_HANDSHAKE_FAILURE

解决方案

python 复制代码
import urllib3
urllib3.disable_warnings()

# 关闭 SSL 验证
resp = requests.get(url, headers=headers, verify=False, timeout=30)

或者将 https:// 改为 http://(如果服务器支持)。

难点 3:下载到 HTML 伪装页

黑龙江的 download.jsp 链接,如果直接请求,返回的不是 Excel,而是** HTML 登录页面**(约 3.8 KB)。

解决方案:双重验证------HTTP 状态码 + 文件头 + 文件大小:

python 复制代码
# 验证不是 HTML 伪装
is_html = b'<html' in resp.content[:200].lower()

# 验证文件大小(真实 PDF/Excel 通常 > 10KB)
if resp.status_code == 200 and not is_html and len(resp.content) > 1000:
    with open(filepath, 'wb') as f:
        f.write(resp.content)

难点 4:.bin 文件扩展名修复

由于上述参数污染问题,下载后会残留 .bin 文件。必须根据**文件头魔数(Magic Number)**修复:

python 复制代码
def get_true_extension(filepath):
    with open(filepath, 'rb') as f:
        header = f.read(20)
    
    if header[:4] == b'%PDF':
        return 'pdf'
    elif header[:4] == b'\xd0\xcf\x11\xe0':  # OLE2 旧版 Excel
        return 'xls'
    elif b'PK\x03\x04' in header[:10]:  # ZIP 压缩包 = 新版 XLSX
        return 'xlsx'
    else:
        return None

# 扫描并重命名
for f in os.listdir(pdf_dir):
    if f.endswith('.bin'):
        ext = get_true_extension(os.path.join(pdf_dir, f))
        if ext:
            new_name = f.replace('.bin', f'.{ext}')
            os.rename(old_path, new_path)

四、核心代码:从 URL 发现到文件落地

阶段 1:批量提取各省下载链接

python 复制代码
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin, urlparse
import time

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    'Accept-Language': 'zh-CN,zh;q=0.9',
}

province_map = {
    'an_hui': '安徽', 'bei_jing': '北京', 'chong_qing': '重庆',
    'guang_dong': '广东', 'jiang_su': '江苏', 'he_bei': '河北',
    # ... 其他省份映射
}

results = {}
for url in province_page_links:  # 从 eol.cn 提取的 100 个页面
    try:
        parts = urlparse(url).path.split('/')
        prov_key = parts[2]
        province = province_map.get(prov_key, prov_key)
        
        resp = requests.get(url, headers=headers, timeout=20)
        resp.encoding = resp.apparent_encoding
        soup = BeautifulSoup(resp.text, 'html.parser')
        
        downloads = []
        for a in soup.find_all('a', href=True):
            href = a['href']
            full = urljoin(url, href)
            lower = full.lower()
            # 捕获直接文件链接 + 附件/下载链接
            if any(ext in lower for ext in ['.pdf', '.xls', '.xlsx']):
                downloads.append({'url': full, 'text': a.get_text(strip=True)})
            elif 'attachment' in lower or 'download' in lower:
                downloads.append({'url': full, 'text': a.get_text(strip=True)})
        
        if downloads:
            results[province] = {'page_url': url, 'downloads': downloads}
        
        time.sleep(0.8)  # 防限流
    except Exception as e:
        print(f"Error {url}: {e}")

阶段 2:批量下载 + 实时验证

python 复制代码
import urllib3
urllib3.disable_warnings()

for prov, info in results.items():
    for dl in info['downloads']:
        url = dl['url']
        
        # 安全提取扩展名
        ext = url.split('.')[-1].split('?')[0].split('&')[0][:4].lower()
        if ext not in ['pdf', 'xls', 'xlsx']:
            ext = 'bin'
        
        filename = f"{prov}_2025_{dl['text'][:20]}.{ext}"
        filepath = os.path.join(output_dir, filename)
        
        # 跳过已存在的有效文件
        if os.path.exists(filepath) and os.path.getsize(filepath) > 1000:
            continue
        
        resp = requests.get(url, headers=headers, timeout=30, verify=False)
        
        content_type = resp.headers.get('Content-Type', '').lower()
        is_html = b'<html' in resp.content[:200].lower() or 'text/html' in content_type
        
        if resp.status_code == 200 and not is_html and len(resp.content) > 1000:
            with open(filepath, 'wb') as f:
                f.write(resp.content)
            print(f"✅ Downloaded: {filename} ({len(resp.content)} bytes)")
        else:
            print(f"❌ Failed: {filename} (html={is_html}, size={len(resp.content)})")

五、各省数据公开政策差异(核心干货)

经过实际爬取验证,2025 年各省投档线数据的公开政策可分为 3 类

类型 A:完全公开,可直接下载(12 省)

省份 格式 批次覆盖 文件数
广东 PDF 历史/物理/体育/美术/音乐/舞蹈/书法/播音/表导演 9
北京 PDF 提前批 A/B 段 + 普通批 4
江苏 PDF/XLS/XLSX 提前批 7 批次 + 普通批 15
山东 XLS 常规批/艺术类/体育类/春季高考 8
河北 XLSX 提前批 B 段 + 普通批 4
浙江 XLS 普通类第一段/第二段 + 体育类 3
江西 PDF 历史物理/体育/三校生 3
湖南 XLSX 体育类 + 普通批物理 2
辽宁 XLSX 历史/物理类 2
贵州 PDF 历史/物理类 2
上海 PDF 本科普通批 1
重庆 PDF 本科普通批 1

类型 B:仅在线查询/网页展示,无静态文件(9 省)

省份 公开方式 能否批量爬取
安徽 网页长图片 ❌ 无法提取结构化数据
广西 官方网页表格 ❌ 需解析 HTML 表格
海南 官方网页表格 ❌ 需解析 HTML 表格
福建 数字服务大厅在线查询 ❌ 无静态文件链接
天津 系统查询 ❌ 无公开文件
内蒙古 考生服务平台查询 ❌ 无公开文件
吉林 考生服务平台查询 ❌ 无公开文件
陕西 个人查询渠道 ❌ 无公开文件
西藏 未检索到完整文件 ❌ 无数据

类型 C:仅考生本人可查(5 省)------2025 年政策收紧

⚠️ 这是 2025 年最大的变化 :多个省份不再向社会公开完整投档线 PDF,仅支持考生登录系统查询自己填报志愿的院校投档结果。

省份 查询入口 备注
河南 河南省普通高校招生考生服务平台 2025 年起不公开完整投档线
四川 四川省教育考试院高考数字服务大厅 同上
云南 云南省普通高等学校招生考生服务平台 同上
甘肃 甘肃阳光高考信息平台 同上
青海 青海省普通高校招生考试考生综合信息平台 同上

类型 D:需特殊渠道获取(5 省)

省份 障碍 解决方案
湖北 需微信公众号/二维码扫描下载 无法自动化
黑龙江 部分批次需 session 登录下载系统 可寻找替代直接链接
宁夏 PDF 链接常返回 404 需通过官方系统
新疆 以图片/网页形式发布 需 OCR 或手动整理
山西 需通过下载系统获取 无直接链接

六、成果统计

复制代码
📊 最终交付
├── 有效文件总数:64 个
├── 覆盖省份:12 个(广东、北京、江苏、山东、河北、浙江、江西、湖南、辽宁、贵州、上海、重庆)
├── 文件格式分布:
│   ├── PDF:32 个
│   ├── XLS(旧版 Excel):24 个
│   └── XLSX(新版 Excel):8 个
├── 总数据量:约 25 MB
├── 无法下载省份:19 个(政策限制或技术障碍)
└── 输出目录:{workspace}/output/2025_toudang/pdf/

文件命名示例

复制代码
广东_2025_本科普通类历史.pdf        (421 KB)
江苏_2025_本科普通批历史PDF.pdf     (652 KB)
山东_2025_普通类常规批第1次.xls     (1.9 MB)
河北_2025_本科普通批物理.xlsx       (1.3 MB)
浙江_2025_普通类第一段.xls          (2.0 MB)
贵州_2025_本科物理类.pdf            (6.8 MB)  ← 最大的文件

七、踩坑记录

  1. 广东附件编号重复eea.gd.gov.cn 的 9 个附件 PDF 文件名都是 4746781.pdf,只有 URL 路径中的 585885585893 编号不同,容易误判为重复文件。

  2. 江苏文件数量爆炸:江苏按"历史/物理 × 提前批/普通批 × 多次征集"拆分,一次产出 15 个文件,需做好文件命名区分。

  3. 贵州 PDF 体积巨大:贵州物理类 PDF 达 6.8 MB,原因是该省包含所有院校专业组的完整投档数据,包含大量表格。

  4. 黑龙江 .xlsx 链接返回 HTML :直接请求 .xlsx 链接时,服务器会返回 3.8 KB 的 HTML 页面(可能是登录态校验或防盗链),最终放弃该省部分批次。

  5. 文件命名中的乱码:由于 eol.cn 页面编码为 GBK/GB2312,BeautifulSoup 解析后的中文文件名可能乱码,建议用 Unicode 规范化处理。


八、总结与建议

这套流程的复用价值

如果你需要爬取 2026 年及以后的投档线数据,只需做以下调整:

  1. 修改 URL 时间路径 :将 202507 改为 202607
  2. 更新各省页面编号eol.cn 的页面编号每年变化,需重新提取
  3. 关注政策变化:预计更多省份会跟进"仅考生可查"模式,可下载的省份可能逐年减少

对开发者的建议

  • 不要硬编码 URL:各省考试院每年会改版,建议每年重新跑一遍 URL 发现流程
  • 建立文件头验证机制:无论什么扩展名,下载后必须验证 Magic Number
  • 做好省份政策白名单:建议维护一个"可下载省份清单",每年更新
  • 考虑购买商业数据:如果项目需要全部 31 省数据,咕咕数据等商业 API 提供结构化接口(需付费),比自己爬取更稳定

文件已存档

本项目生成的 64 份原始文件 + 下载清单 已永久保存,同时输出了一份 SKILL_batch_download_gaokao_toudang.md 作为标准化操作手册,供后续快速复用。


附:下载链接:https://pan.quark.cn/s/03d7ee1a08f8

数据年份 :2025 年全国高考投档线

代码环境:Python 3.12 + requests + BeautifulSoup4

如果对你有帮助,欢迎点赞收藏!如有问题可在评论区交流,或关注后续数据解析文章(将 PDF/XLS 提取为结构化 Excel 表格)。

相关推荐
2601_9516457819 小时前
如何优雅地使用c语言编写爬虫
c语言·爬虫·网络请求·字符串处理·cspider
daly52021 小时前
人工智能专业有哪些?2026高考报考指南(专业分类 + 课程 + 就业全解析)
人工智能·分类·高考
在放️1 天前
Python 爬虫 · 模拟浏览器跳转 - 防盗链处理
爬虫·python
数据知道1 天前
指纹浏览器:DNS 泄漏防范与 WebRTC 本地 IP 屏蔽的底层实现
爬虫·网络协议·tcp/ip·安全·webrtc·数据采集·指纹浏览器
在放️2 天前
Python 爬虫 · PyQuery 模块基础
爬虫·python
数据知道2 天前
指纹浏览器本地存储“孤岛化”:IndexedDB、LocalStorage、SessionStorage 的安全隔离
爬虫·安全·数据采集·指纹浏览器
小白学大数据3 天前
线上故障急救:依托 OpenClaw 日志排查 403 和 503 问题
爬虫·python·selenium·数据分析
有味道的男人3 天前
利用爬虫获取中国制造网商品详情:高效采集完整方案
爬虫·制造
anew___3 天前
2026年Python爬虫技术完全指南:从入门到实战
开发语言·爬虫·python