Python实战构建中国大学MOOC课程数据爬虫与34万条评论数据集分析最近在分析在线教育平台数据时我发现中国大学MOOC平台上的课程评价数据特别有价值。这些真实用户反馈不仅能反映课程质量还能揭示学习者的偏好和行为模式。今天就来分享一个完整的Python爬虫解决方案从API分析到数据清洗最终生成可直接用于研究的结构化数据集。1. 环境准备与工具选择在开始爬取数据前我们需要搭建合适的开发环境。不同于简单的静态网页抓取MOOC平台的数据大多通过API接口返回JSON格式这对我们的工具选择提出了特定要求。核心工具栈配置# 基础环境安装 pip install requests pandas numpy tqdm fake-useragent推荐配置Python 3.8环境VS Code或PyCharm作为IDE配合Jupyter Notebook进行数据探索。关键库的作用requests处理HTTP请求的核心库pandas数据清洗和结构化存储tqdm显示爬取进度条fake-useragent生成随机请求头注意实际操作中建议配置代理IP池虽然MOOC平台反爬机制相对宽松但高频请求仍可能触发限制。我通常会创建一个独立的虚拟环境来管理项目依赖python -m venv mooc_scraper source mooc_scraper/bin/activate # Linux/Mac mooc_scraper\Scripts\activate # Windows2. API分析与请求策略中国大学MOOC平台采用前后端分离架构所有课程数据都通过API接口动态加载。通过浏览器开发者工具F12我们可以轻松找到这些关键接口。主要API端点分析接口类型URL示例请求方式关键参数课程分类.../listChannelCategoryDetail.rpcPOSTcsrfKey课程列表.../searchCourseCardByChannelAndCategoryId.rpcPOSTcategoryId, pageIndex课程评价.../getCourseEvaluatePaginationByCourseIdOrTermId.rpcPOSTcourseId, pageSize请求头定制技巧headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: https://www.icourse163.org/channel/, Origin: https://www.icourse163.org, Content-Type: application/x-www-form-urlencoded }实际请求时需要注意几个关键点csrfKey参数需要从首页或登录后的Cookie中提取分页参数pageIndex从1开始计数评价接口的orderBy3表示按最新排序3. 数据爬取实战代码下面展示完整的爬虫实现采用模块化设计便于维护和扩展。我们将分三个步骤获取数据课程分类→课程详情→课程评价。3.1 课程分类爬取def get_course_categories(): base_url https://www.icourse163.org/web/j/channelBean.listChannelCategoryDetail.rpc params { csrfKey: get_csrf_key() # 需要提前实现的函数 } payload includeALLChannelstrueincludeDefaultChannelsfalse response requests.post(base_url, paramsparams, datapayload, headersheaders) data response.json() # 数据清洗示例 categories [] for category in data[result][channelCategoryDetails]: for channel in category[channels]: clean_data { id: channel[id], name: channel[name], desc: channel.get(shortDesc, ) } categories.append(clean_data) return categories3.2 课程详情爬取采用分页爬取策略每类课程单独处理def get_courses_by_category(category_id, max_pages50): courses [] url https://www.icourse163.org/web/j/mocSearchBean.searchCourseCardByChannelAndCategoryId.rpc for page in range(1, max_pages1): payload { mocCourseQueryVo: json.dumps({ categoryId: -1, categoryChannelId: category_id, pageIndex: page, pageSize: 20 }) } try: response requests.post(url, datapayload, headersheaders) page_data response.json() for item in page_data[result][list]: course item[mocCourseBaseCardVo] courses.append({ course_id: course[id], name: course[name], school: course[schoolName], teacher: course[teacherName], enroll_count: course[enrollCount] }) if page page_data[result][query][totlePageCount]: break except Exception as e: print(fError on page {page}: {str(e)}) return courses3.3 课程评价爬取评价数据量最大需要特别注意性能和异常处理def get_course_reviews(course_id): reviews [] url https://www.icourse163.org/web/j/mocCourseV2RpcBean.getCourseEvaluatePaginationByCourseIdOrTermId.rpc page 1 while True: payload { courseId: str(course_id), pageIndex: str(page), pageSize: 20, orderBy: 3 } try: response requests.post(url, datapayload, headersheaders) data response.json() for review in data[result][list]: reviews.append({ id: review[id], content: review[content], user: review[userNickName], rating: review.get(mark, 0), date: review[gmtModified] }) if page data[result][query][totlePageCount]: break page 1 time.sleep(0.5) # 礼貌性延迟 except Exception as e: print(fFailed to get page {page}: {str(e)}) break return reviews4. 数据存储与清洗获取原始数据后我们需要进行结构化处理和持久化存储。这里推荐使用Pandas进行数据清洗然后保存为多种格式。数据清洗关键步骤处理缺失值df[rating] df[rating].fillna(0)统一日期格式df[date] pd.to_datetime(df[date], unitms)文本清洗import re df[content] df[content].apply(lambda x: re.sub(r\s, , x).strip())多格式存储方案格式优点适用场景代码示例CSV通用性强数据交换df.to_csv(reviews.csv)Parquet列式存储大数据分析df.to_parquet(reviews.parquet)SQLite关系型本地查询df.to_sql(reviews, conengine)完整的数据处理流水线示例def process_data(raw_data): # 转换为DataFrame df pd.DataFrame(raw_data) # 类型转换 df[date] pd.to_datetime(df[date], unitms) df[rating] pd.to_numeric(df[rating]) # 文本处理 df[content] df[content].str.strip() # 去重 df df.drop_duplicates(id) return df5. 数据分析与可视化获得清洗后的数据后我们可以进行一些基础分析挖掘数据价值。以下是几个典型分析方向课程评价词云生成from wordcloud import WordCloud import jieba text .join(df[content].dropna()) wordlist .join(jieba.cut(text)) wc WordCloud( font_pathsimhei.ttf, background_colorwhite, max_words200 ).generate(wordlist) plt.imshow(wc) plt.axis(off) plt.show()课程评分分布分析plt.figure(figsize(10,6)) sns.countplot(xrating, datadf) plt.title(评分分布) plt.xlabel(星级) plt.ylabel(数量) plt.show()热门课程识别top_courses df.groupby(course_name)[rating] \ .agg([count, mean]) \ .sort_values(count, ascendingFalse) print(top_courses.head(10))6. 项目优化与扩展基础爬虫完成后我们可以从以下几个方向进行优化性能优化方案使用aiohttp实现异步请求采用Redis作为请求队列实现断点续爬功能反反爬策略动态User-Agent轮换请求频率随机化重要参数加密处理数据分析扩展情感分析使用SnowNLP或BERT用户行为模式挖掘课程推荐系统构建一个简单的异步爬虫改造示例import aiohttp import asyncio async def fetch(session, url, params): async with session.post(url, dataparams) as response: return await response.json() async def main(): async with aiohttp.ClientSession() as session: tasks [] for course_id in course_ids: task fetch(session, API_URL, {courseId: course_id}) tasks.append(task) results await asyncio.gather(*tasks) # 处理结果...7. 完整数据集分享经过两周的爬取和清洗最终获得的数据集包含23个课程分类29,196门课程基本信息343,525条课程评价数据集字段说明数据表主要字段记录数课程分类id, name, desc23课程信息id, name, school, teacher29,196课程评价id, content, rating, date343,525数据集下载链接已整理在项目仓库中包含原始JSON数据清洗后的CSV文件数据分析示例Notebook使用建议教育研究者分析课程评价与教学质量关系产品经理了解用户真实需求和痛点数据科学学习者作为文本分析练习素材在真实项目中这套数据帮助我们发现了几个有趣的现象评分在4.2-4.5之间的课程最受欢迎用户更关注教师授课风格而非课程内容难度周末的评价情感倾向更为积极
用Python爬取中国大学MOOC课程数据,34万条评论数据集免费分享(附完整代码)
Python实战构建中国大学MOOC课程数据爬虫与34万条评论数据集分析最近在分析在线教育平台数据时我发现中国大学MOOC平台上的课程评价数据特别有价值。这些真实用户反馈不仅能反映课程质量还能揭示学习者的偏好和行为模式。今天就来分享一个完整的Python爬虫解决方案从API分析到数据清洗最终生成可直接用于研究的结构化数据集。1. 环境准备与工具选择在开始爬取数据前我们需要搭建合适的开发环境。不同于简单的静态网页抓取MOOC平台的数据大多通过API接口返回JSON格式这对我们的工具选择提出了特定要求。核心工具栈配置# 基础环境安装 pip install requests pandas numpy tqdm fake-useragent推荐配置Python 3.8环境VS Code或PyCharm作为IDE配合Jupyter Notebook进行数据探索。关键库的作用requests处理HTTP请求的核心库pandas数据清洗和结构化存储tqdm显示爬取进度条fake-useragent生成随机请求头注意实际操作中建议配置代理IP池虽然MOOC平台反爬机制相对宽松但高频请求仍可能触发限制。我通常会创建一个独立的虚拟环境来管理项目依赖python -m venv mooc_scraper source mooc_scraper/bin/activate # Linux/Mac mooc_scraper\Scripts\activate # Windows2. API分析与请求策略中国大学MOOC平台采用前后端分离架构所有课程数据都通过API接口动态加载。通过浏览器开发者工具F12我们可以轻松找到这些关键接口。主要API端点分析接口类型URL示例请求方式关键参数课程分类.../listChannelCategoryDetail.rpcPOSTcsrfKey课程列表.../searchCourseCardByChannelAndCategoryId.rpcPOSTcategoryId, pageIndex课程评价.../getCourseEvaluatePaginationByCourseIdOrTermId.rpcPOSTcourseId, pageSize请求头定制技巧headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: https://www.icourse163.org/channel/, Origin: https://www.icourse163.org, Content-Type: application/x-www-form-urlencoded }实际请求时需要注意几个关键点csrfKey参数需要从首页或登录后的Cookie中提取分页参数pageIndex从1开始计数评价接口的orderBy3表示按最新排序3. 数据爬取实战代码下面展示完整的爬虫实现采用模块化设计便于维护和扩展。我们将分三个步骤获取数据课程分类→课程详情→课程评价。3.1 课程分类爬取def get_course_categories(): base_url https://www.icourse163.org/web/j/channelBean.listChannelCategoryDetail.rpc params { csrfKey: get_csrf_key() # 需要提前实现的函数 } payload includeALLChannelstrueincludeDefaultChannelsfalse response requests.post(base_url, paramsparams, datapayload, headersheaders) data response.json() # 数据清洗示例 categories [] for category in data[result][channelCategoryDetails]: for channel in category[channels]: clean_data { id: channel[id], name: channel[name], desc: channel.get(shortDesc, ) } categories.append(clean_data) return categories3.2 课程详情爬取采用分页爬取策略每类课程单独处理def get_courses_by_category(category_id, max_pages50): courses [] url https://www.icourse163.org/web/j/mocSearchBean.searchCourseCardByChannelAndCategoryId.rpc for page in range(1, max_pages1): payload { mocCourseQueryVo: json.dumps({ categoryId: -1, categoryChannelId: category_id, pageIndex: page, pageSize: 20 }) } try: response requests.post(url, datapayload, headersheaders) page_data response.json() for item in page_data[result][list]: course item[mocCourseBaseCardVo] courses.append({ course_id: course[id], name: course[name], school: course[schoolName], teacher: course[teacherName], enroll_count: course[enrollCount] }) if page page_data[result][query][totlePageCount]: break except Exception as e: print(fError on page {page}: {str(e)}) return courses3.3 课程评价爬取评价数据量最大需要特别注意性能和异常处理def get_course_reviews(course_id): reviews [] url https://www.icourse163.org/web/j/mocCourseV2RpcBean.getCourseEvaluatePaginationByCourseIdOrTermId.rpc page 1 while True: payload { courseId: str(course_id), pageIndex: str(page), pageSize: 20, orderBy: 3 } try: response requests.post(url, datapayload, headersheaders) data response.json() for review in data[result][list]: reviews.append({ id: review[id], content: review[content], user: review[userNickName], rating: review.get(mark, 0), date: review[gmtModified] }) if page data[result][query][totlePageCount]: break page 1 time.sleep(0.5) # 礼貌性延迟 except Exception as e: print(fFailed to get page {page}: {str(e)}) break return reviews4. 数据存储与清洗获取原始数据后我们需要进行结构化处理和持久化存储。这里推荐使用Pandas进行数据清洗然后保存为多种格式。数据清洗关键步骤处理缺失值df[rating] df[rating].fillna(0)统一日期格式df[date] pd.to_datetime(df[date], unitms)文本清洗import re df[content] df[content].apply(lambda x: re.sub(r\s, , x).strip())多格式存储方案格式优点适用场景代码示例CSV通用性强数据交换df.to_csv(reviews.csv)Parquet列式存储大数据分析df.to_parquet(reviews.parquet)SQLite关系型本地查询df.to_sql(reviews, conengine)完整的数据处理流水线示例def process_data(raw_data): # 转换为DataFrame df pd.DataFrame(raw_data) # 类型转换 df[date] pd.to_datetime(df[date], unitms) df[rating] pd.to_numeric(df[rating]) # 文本处理 df[content] df[content].str.strip() # 去重 df df.drop_duplicates(id) return df5. 数据分析与可视化获得清洗后的数据后我们可以进行一些基础分析挖掘数据价值。以下是几个典型分析方向课程评价词云生成from wordcloud import WordCloud import jieba text .join(df[content].dropna()) wordlist .join(jieba.cut(text)) wc WordCloud( font_pathsimhei.ttf, background_colorwhite, max_words200 ).generate(wordlist) plt.imshow(wc) plt.axis(off) plt.show()课程评分分布分析plt.figure(figsize(10,6)) sns.countplot(xrating, datadf) plt.title(评分分布) plt.xlabel(星级) plt.ylabel(数量) plt.show()热门课程识别top_courses df.groupby(course_name)[rating] \ .agg([count, mean]) \ .sort_values(count, ascendingFalse) print(top_courses.head(10))6. 项目优化与扩展基础爬虫完成后我们可以从以下几个方向进行优化性能优化方案使用aiohttp实现异步请求采用Redis作为请求队列实现断点续爬功能反反爬策略动态User-Agent轮换请求频率随机化重要参数加密处理数据分析扩展情感分析使用SnowNLP或BERT用户行为模式挖掘课程推荐系统构建一个简单的异步爬虫改造示例import aiohttp import asyncio async def fetch(session, url, params): async with session.post(url, dataparams) as response: return await response.json() async def main(): async with aiohttp.ClientSession() as session: tasks [] for course_id in course_ids: task fetch(session, API_URL, {courseId: course_id}) tasks.append(task) results await asyncio.gather(*tasks) # 处理结果...7. 完整数据集分享经过两周的爬取和清洗最终获得的数据集包含23个课程分类29,196门课程基本信息343,525条课程评价数据集字段说明数据表主要字段记录数课程分类id, name, desc23课程信息id, name, school, teacher29,196课程评价id, content, rating, date343,525数据集下载链接已整理在项目仓库中包含原始JSON数据清洗后的CSV文件数据分析示例Notebook使用建议教育研究者分析课程评价与教学质量关系产品经理了解用户真实需求和痛点数据科学学习者作为文本分析练习素材在真实项目中这套数据帮助我们发现了几个有趣的现象评分在4.2-4.5之间的课程最受欢迎用户更关注教师授课风格而非课程内容难度周末的评价情感倾向更为积极