1. 项目背景与核心价值
研究生招生信息采集一直是考研学子面临的重要痛点。每年各高校发布的招生简章分散在不同网站,格式不统一,关键信息(如招生人数、考试科目、参考书目)提取困难。传统人工收集方式效率低下,且难以进行横向对比分析。
这个Python爬虫项目正是为解决这一痛点而生。通过自动化采集多所高校研究生院的招生简章,将非结构化的网页数据转化为结构化的CSV表格,并持久化存储到SQLite数据库,实现三个核心价值:
- 信息聚合:一键获取多所目标院校的最新招生政策,避免反复访问不同网站
- 智能分析:结构化存储支持按专业、考试科目等维度快速筛选对比
- 历史存档:SQLite数据库保留历年数据,方便分析招生趋势变化
提示:系统设计时特别注意了robots.txt协议合规性,通过设置合理的爬取间隔(建议≥30秒/次)和User-Agent标识,避免对目标网站造成访问压力。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计
2.1 整体工作流程
mermaid复制graph TD
A[目标URL列表] --> B[网页下载器]
B --> C[HTML解析器]
C --> D[数据清洗模块]
D --> E[CSV导出模块]
D --> F[SQLite存储模块]
2.2 核心组件选型
| 组件类型 | 技术选型 | 选择理由 |
|---|---|---|
| 网页下载 | requests + retrying | 支持自动重试机制,应对网络波动 |
| HTML解析 | BeautifulSoup4 | 对复杂HTML结构的容错性强 |
| 数据存储 | csv模块 + sqlite3 | 轻量级方案,无需额外服务,适合个人使用 |
| 任务调度 | schedule | 简单易用的定时任务库 |
| 反爬应对 | fake-useragent | 随机生成主流浏览器UA头 |
3. 关键实现细节
3.1 网页内容解析策略
以典型的研究生院招生页面为例,需要处理三种常见结构:
- 表格型数据:
python复制def parse_table(soup):
results = []
for row in soup.select('table.zsjh tr')[1:]: # 跳过表头
cells = [td.get_text(strip=True) for td in row.find_all('td')]
results.append({
'专业代码': cells[0],
'专业名称': cells[1],
'拟招生人数': int(cells[2])
})
return results
- 段落型说明:
python复制def parse_paragraphs(soup):
content = '\n'.join([p.get_text(strip=True)
for p in soup.select('#content p')])
return {'招生说明': content}
- 文件附件:
python复制def parse_attachments(soup):
return {
'参考书目': [a['href']
for a in soup.select('a[href$=".pdf"]')]
}
3.2 数据持久化实现
CSV导出模块
python复制import csv
def save_to_csv(data, filename):
with open(filename, 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.DictWriter(f, fieldnames=data[0].keys())
writer.writeheader()
writer.writerows(data)
SQLite存储模块
python复制import sqlite3
def init_db(db_path='admissions.db'):
conn = sqlite3.connect(db_path)
conn.execute('''CREATE TABLE IF NOT EXISTS programs
(id INTEGER PRIMARY KEY AUTOINCREMENT,
school TEXT NOT NULL,
major_code TEXT,
major_name TEXT,
quota INTEGER,
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')
return conn
4. 反爬应对策略
4.1 基础防护措施
python复制from fake_useragent import UserAgent
import time
import random
headers = {
'User-Agent': UserAgent().random,
'Accept-Language': 'zh-CN,zh;q=0.9'
}
def safe_request(url):
time.sleep(random.uniform(1, 3)) # 随机延迟
return requests.get(url, headers=headers, timeout=10)
4.2 验证码处理方案
遇到验证码时提供三种应对策略:
- 自动识别(简单数字验证码)
python复制import pytesseract
from PIL import Image
def solve_captcha(image_url):
img = Image.open(requests.get(image_url, stream=True).raw)
return pytesseract.image_to_string(img)
- 人工介入(复杂验证码)
python复制def manual_captcha(image_url):
img = Image.open(requests.get(image_url, stream=True).raw)
img.show()
return input("请输入验证码:")
- 会话保持(需要登录的情况)
python复制session = requests.Session()
session.post(login_url, data=credentials)
5. 系统扩展建议
5.1 数据可视化分析
python复制import pandas as pd
import matplotlib.pyplot as plt
def analyze_quota_trends(db_path):
df = pd.read_sql('SELECT * FROM programs', sqlite3.connect(db_path))
df.groupby('school')['quota'].sum().plot(kind='bar')
plt.title('各院校招生人数对比')
plt.savefig('quota_comparison.png')
5.2 智能提醒功能
python复制from datetime import datetime
def check_updates(db_path):
conn = sqlite3.connect(db_path)
last_update = conn.execute('SELECT MAX(update_time) FROM programs').fetchone()[0]
if (datetime.now() - datetime.strptime(last_update, '%Y-%m-%d %H:%M:%S')).days > 7:
send_email_notification()
6. 常见问题解决方案
6.1 编码问题处理
python复制# 强制指定响应编码
response.encoding = response.apparent_encoding
# 或使用chardet自动检测
import chardet
encoding = chardet.detect(response.content)['encoding']
6.2 数据去重策略
python复制# 使用数据库唯一约束
conn.execute('''
CREATE UNIQUE INDEX idx_major
ON programs (school, major_code)
''')
# 或内存去重
seen = set()
unique_data = [x for x in raw_data
if (x['school'],x['major_code']) not in seen
and not seen.add((x['school'],x['major_code']))]
重要提示:实际部署时应将爬取间隔设置为30分钟以上,避免触发网站防护机制。建议在凌晨1:00-6:00时段运行采集任务。
