Python爬虫实战从高校网站公告抓取到反爬策略解析引言为什么选择高校网站作为爬虫学习起点高校网站公告系统是爬虫初学者绝佳的练手对象。这类网站通常具备几个特点结构相对规范但又不失复杂度数据更新频繁且内容公开反爬机制适中既不会过于简单也不会像商业网站那样严防死守。通过爬取高校公告我们不仅能掌握基础爬虫技能还能在实践中理解网页结构分析、分页处理等核心概念。记得我第一次尝试爬取学校新闻公告时花了整整一个下午才搞明白如何正确解析那些层层嵌套的div标签。但正是这种踩坑经历让我对HTML文档对象模型(DOM)有了更直观的认识。本文将带你完整走一遍这个学习过程从最基础的页面请求到应对常见的反爬措施。1. 环境准备与工具选择1.1 必备工具清单在开始爬虫项目前我们需要准备以下工具和环境Python 3.7建议使用最新稳定版Requests库用于发送HTTP请求BeautifulSoup4HTML解析利器开发环境推荐VS Code或PyCharm浏览器开发者工具Chrome DevTools是必备安装基础依赖只需几行命令pip install requests beautifulsoup41.2 理解网页结构分析方法现代网页通常由三部分组成HTML网页的骨架和内容CSS样式和布局JavaScript动态行为和交互对于爬虫而言我们主要关注HTML结构。以重庆交通大学新闻网站为例在Chrome中按F12打开开发者工具可以看到这样的典型结构div classnews-list ul li div classtime2023-07-15/div div classright-title a target_blank hrefnews_detail.php?id1234关于暑假安排的通知/a /div /li !-- 更多列表项 -- /ul /div提示在Elements面板中右键点击元素选择Copy Copy selector可以快速获取CSS选择器路径。2. 基础爬虫实现单页内容抓取2.1 发送第一个HTTP请求让我们从最简单的单页请求开始。使用Requests库获取页面内容import requests url http://news.cqjtu.edu.cn/xxtz.htm headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 } response requests.get(url, headersheaders) print(response.status_code) # 应该输出200关键点解析User-Agent头模拟浏览器访问status_code检查请求是否成功默认超时为30秒可通过timeout参数调整2.2 解析HTML内容获得HTML响应后用BeautifulSoup提取我们需要的信息from bs4 import BeautifulSoup soup BeautifulSoup(response.text, html.parser) news_items soup.select(.news-list ul li) for item in news_items: time item.select_one(.time).text.strip() title item.select_one(.right-title a).text.strip() print(f{time} - {title})选择器使用技巧select()返回所有匹配元素列表select_one()返回第一个匹配元素类选择器用.classnameID选择器用#id3. 进阶技巧分页处理与数据存储3.1 分页逻辑分析高校网站通常采用两种分页方式URL参数分页如page2动态加载通过AJAX请求获取观察重庆交通大学网站的URL模式http://news.cqjtu.edu.cn/xxtz/1.htm http://news.cqjtu.edu.cn/xxtz/2.htm ...这种规律性让分页处理变得简单base_url http://news.cqjtu.edu.cn/xxtz/{}.htm for page in range(1, 10): # 假设爬取前10页 url base_url.format(page) # 发送请求和解析逻辑...3.2 数据存储方案爬取的数据通常需要持久化存储。以下是几种常见方案对比存储方式优点缺点适用场景CSV简单易用无需额外依赖不适合复杂数据结构中小规模结构化数据JSON保留数据结构可读性好文件体积较大复杂嵌套数据数据库查询方便支持大规模数据需要数据库服务长期存储和频繁查询以CSV存储为例import csv with open(news.csv, w, newline, encodingutf-8) as f: writer csv.writer(f) writer.writerow([时间, 标题]) for item in news_items: writer.writerow([item[time], item[title]])4. 反爬机制与应对策略4.1 常见反爬手段识别高校网站虽然反爬相对宽松但仍可能遇到以下情况User-Agent检测拒绝非浏览器请求访问频率限制单位时间内过多请求会被封禁IP封禁同一IP频繁访问会被暂时屏蔽验证码特别是登录后的操作4.2 实用应对方案1. 请求头伪装除了User-Agent完整的请求头更能模拟真实浏览器headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64), Accept: text/html,application/xhtmlxml, Accept-Language: zh-CN,zh;q0.9, Referer: http://news.cqjtu.edu.cn/ }2. 请求间隔控制使用time.sleep()避免请求过于密集import time import random for page in range(1, 10): time.sleep(random.uniform(1, 3)) # 随机间隔1-3秒 # 发送请求...3. 代理IP使用当遇到IP限制时可以考虑使用代理proxies { http: http://proxy.example.com:8080, https: https://proxy.example.com:8080 } response requests.get(url, headersheaders, proxiesproxies)注意免费代理往往不稳定生产环境建议使用可靠的商业代理服务。5. 项目实战ACM题目爬取案例5.1 分析ACM题目网站结构以南阳理工学院ACM题目网站为例题目列表分页显示每页题目包含题号、标题、难度等信息数据直接渲染在HTML中无需处理JavaScript关键HTML结构table classproblems tr td1001/td td简单/td tda hrefproblem.php?id1001AB Problem/a/td td80%/td td1200/1500/td /tr /table5.2 完整爬虫实现import requests from bs4 import BeautifulSoup import csv from tqdm import tqdm base_url http://www.51mxd.cn/problemset.php?page{} headers {User-Agent: Mozilla/5.0} def get_problems(page): url base_url.format(page) response requests.get(url, headersheaders) soup BeautifulSoup(response.text, html.parser) problems [] for row in soup.select(.problems tr)[1:]: # 跳过表头 cols row.find_all(td) problems.append([ cols[0].text.strip(), cols[1].text.strip(), cols[2].text.strip(), cols[3].text.strip(), cols[4].text.strip() ]) return problems all_problems [] for page in tqdm(range(1, 11)): # 爬取前10页 all_problems.extend(get_problems(page)) # 保存到CSV with open(acm_problems.csv, w, newline, encodingutf-8) as f: writer csv.writer(f) writer.writerow([题号, 难度, 标题, 通过率, 提交统计]) writer.writerows(all_problems)代码优化点使用tqdm显示进度条异常处理增强鲁棒性支持断点续爬6. 爬虫伦理与最佳实践6.1 合法合规爬取原则尊重robots.txt检查目标网站的爬虫政策控制请求频率避免对服务器造成负担仅爬取公开数据不获取需要授权的内容遵守数据使用条款注意版权和隐私问题6.2 性能优化技巧并发请求使用aiohttp或Scrapy框架提高效率缓存机制避免重复请求相同内容增量爬取只获取新增或更新的数据# 简单的缓存实现示例 import os from hashlib import md5 def get_cache(url): filename md5(url.encode()).hexdigest() .html if os.path.exists(filename): with open(filename, r, encodingutf-8) as f: return f.read() return None def save_cache(url, content): filename md5(url.encode()).hexdigest() .html with open(filename, w, encodingutf-8) as f: f.write(content)在实际项目中我发现最常遇到的问题不是技术实现而是如何平衡爬取效率和目标网站的承受能力。有一次因为没控制好请求频率导致短时间内发送了太多请求结果IP被暂时封禁。这个教训让我明白编写友好的爬虫同样重要。
Python爬虫新手必看:用BeautifulSoup+Requests爬取高校网站公告(含反爬应对)
发布时间:2026/5/25 20:10:04
Python爬虫实战从高校网站公告抓取到反爬策略解析引言为什么选择高校网站作为爬虫学习起点高校网站公告系统是爬虫初学者绝佳的练手对象。这类网站通常具备几个特点结构相对规范但又不失复杂度数据更新频繁且内容公开反爬机制适中既不会过于简单也不会像商业网站那样严防死守。通过爬取高校公告我们不仅能掌握基础爬虫技能还能在实践中理解网页结构分析、分页处理等核心概念。记得我第一次尝试爬取学校新闻公告时花了整整一个下午才搞明白如何正确解析那些层层嵌套的div标签。但正是这种踩坑经历让我对HTML文档对象模型(DOM)有了更直观的认识。本文将带你完整走一遍这个学习过程从最基础的页面请求到应对常见的反爬措施。1. 环境准备与工具选择1.1 必备工具清单在开始爬虫项目前我们需要准备以下工具和环境Python 3.7建议使用最新稳定版Requests库用于发送HTTP请求BeautifulSoup4HTML解析利器开发环境推荐VS Code或PyCharm浏览器开发者工具Chrome DevTools是必备安装基础依赖只需几行命令pip install requests beautifulsoup41.2 理解网页结构分析方法现代网页通常由三部分组成HTML网页的骨架和内容CSS样式和布局JavaScript动态行为和交互对于爬虫而言我们主要关注HTML结构。以重庆交通大学新闻网站为例在Chrome中按F12打开开发者工具可以看到这样的典型结构div classnews-list ul li div classtime2023-07-15/div div classright-title a target_blank hrefnews_detail.php?id1234关于暑假安排的通知/a /div /li !-- 更多列表项 -- /ul /div提示在Elements面板中右键点击元素选择Copy Copy selector可以快速获取CSS选择器路径。2. 基础爬虫实现单页内容抓取2.1 发送第一个HTTP请求让我们从最简单的单页请求开始。使用Requests库获取页面内容import requests url http://news.cqjtu.edu.cn/xxtz.htm headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 } response requests.get(url, headersheaders) print(response.status_code) # 应该输出200关键点解析User-Agent头模拟浏览器访问status_code检查请求是否成功默认超时为30秒可通过timeout参数调整2.2 解析HTML内容获得HTML响应后用BeautifulSoup提取我们需要的信息from bs4 import BeautifulSoup soup BeautifulSoup(response.text, html.parser) news_items soup.select(.news-list ul li) for item in news_items: time item.select_one(.time).text.strip() title item.select_one(.right-title a).text.strip() print(f{time} - {title})选择器使用技巧select()返回所有匹配元素列表select_one()返回第一个匹配元素类选择器用.classnameID选择器用#id3. 进阶技巧分页处理与数据存储3.1 分页逻辑分析高校网站通常采用两种分页方式URL参数分页如page2动态加载通过AJAX请求获取观察重庆交通大学网站的URL模式http://news.cqjtu.edu.cn/xxtz/1.htm http://news.cqjtu.edu.cn/xxtz/2.htm ...这种规律性让分页处理变得简单base_url http://news.cqjtu.edu.cn/xxtz/{}.htm for page in range(1, 10): # 假设爬取前10页 url base_url.format(page) # 发送请求和解析逻辑...3.2 数据存储方案爬取的数据通常需要持久化存储。以下是几种常见方案对比存储方式优点缺点适用场景CSV简单易用无需额外依赖不适合复杂数据结构中小规模结构化数据JSON保留数据结构可读性好文件体积较大复杂嵌套数据数据库查询方便支持大规模数据需要数据库服务长期存储和频繁查询以CSV存储为例import csv with open(news.csv, w, newline, encodingutf-8) as f: writer csv.writer(f) writer.writerow([时间, 标题]) for item in news_items: writer.writerow([item[time], item[title]])4. 反爬机制与应对策略4.1 常见反爬手段识别高校网站虽然反爬相对宽松但仍可能遇到以下情况User-Agent检测拒绝非浏览器请求访问频率限制单位时间内过多请求会被封禁IP封禁同一IP频繁访问会被暂时屏蔽验证码特别是登录后的操作4.2 实用应对方案1. 请求头伪装除了User-Agent完整的请求头更能模拟真实浏览器headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64), Accept: text/html,application/xhtmlxml, Accept-Language: zh-CN,zh;q0.9, Referer: http://news.cqjtu.edu.cn/ }2. 请求间隔控制使用time.sleep()避免请求过于密集import time import random for page in range(1, 10): time.sleep(random.uniform(1, 3)) # 随机间隔1-3秒 # 发送请求...3. 代理IP使用当遇到IP限制时可以考虑使用代理proxies { http: http://proxy.example.com:8080, https: https://proxy.example.com:8080 } response requests.get(url, headersheaders, proxiesproxies)注意免费代理往往不稳定生产环境建议使用可靠的商业代理服务。5. 项目实战ACM题目爬取案例5.1 分析ACM题目网站结构以南阳理工学院ACM题目网站为例题目列表分页显示每页题目包含题号、标题、难度等信息数据直接渲染在HTML中无需处理JavaScript关键HTML结构table classproblems tr td1001/td td简单/td tda hrefproblem.php?id1001AB Problem/a/td td80%/td td1200/1500/td /tr /table5.2 完整爬虫实现import requests from bs4 import BeautifulSoup import csv from tqdm import tqdm base_url http://www.51mxd.cn/problemset.php?page{} headers {User-Agent: Mozilla/5.0} def get_problems(page): url base_url.format(page) response requests.get(url, headersheaders) soup BeautifulSoup(response.text, html.parser) problems [] for row in soup.select(.problems tr)[1:]: # 跳过表头 cols row.find_all(td) problems.append([ cols[0].text.strip(), cols[1].text.strip(), cols[2].text.strip(), cols[3].text.strip(), cols[4].text.strip() ]) return problems all_problems [] for page in tqdm(range(1, 11)): # 爬取前10页 all_problems.extend(get_problems(page)) # 保存到CSV with open(acm_problems.csv, w, newline, encodingutf-8) as f: writer csv.writer(f) writer.writerow([题号, 难度, 标题, 通过率, 提交统计]) writer.writerows(all_problems)代码优化点使用tqdm显示进度条异常处理增强鲁棒性支持断点续爬6. 爬虫伦理与最佳实践6.1 合法合规爬取原则尊重robots.txt检查目标网站的爬虫政策控制请求频率避免对服务器造成负担仅爬取公开数据不获取需要授权的内容遵守数据使用条款注意版权和隐私问题6.2 性能优化技巧并发请求使用aiohttp或Scrapy框架提高效率缓存机制避免重复请求相同内容增量爬取只获取新增或更新的数据# 简单的缓存实现示例 import os from hashlib import md5 def get_cache(url): filename md5(url.encode()).hexdigest() .html if os.path.exists(filename): with open(filename, r, encodingutf-8) as f: return f.read() return None def save_cache(url, content): filename md5(url.encode()).hexdigest() .html with open(filename, w, encodingutf-8) as f: f.write(content)在实际项目中我发现最常遇到的问题不是技术实现而是如何平衡爬取效率和目标网站的承受能力。有一次因为没控制好请求频率导致短时间内发送了太多请求结果IP被暂时封禁。这个教训让我明白编写友好的爬虫同样重要。