R语言爬虫慕课网课程信息(超级详细!)

一、慕课网页与爬取信息

分析步骤

  • 先获取实战课程中的大类标题与链接
  • 进入单个标题链接中,每一页的课程都爬取课程题目、课程等级、价格、播放量、评价数
  • 对所有大类标题链接进行遍历爬取

逐步分析(广告原因不能详细的发图)

  • 首先打开如下慕课网官网https://www.imooc.com/
  • 我们可以看到官网上面的课程有免费课程、实战课程等课程,因为不同类别课程网页结构不一,信息也不同,所有我们分别爬取,本文就先爬取付费的实战课程
    在这里插入图片描述
  • 慕课网上的实战课程都是付费课程,里面包括各种课程的分类,也有课程的价格、播放量、课程等级、课程评价人数等,信息如下图。我们的目标是将前端开发、后端开发等课程分别爬取,例如前端开发目录下的所有课程一并爬取。
    • 第一步要做的是先获取所有大类的标题与其对应的连接。
      在这里插入图片描述
      第二步根据爬取元素对应网页代码的位置进行爬取
      在这里插入图片描述
      第三步根据网页的页数特点进行翻页爬取
      在这里插入图片描述

二、爬取慕课网页实战课程大类与链接

第一步:函数包的准备
这是比较简单的爬虫包

install.packages(rvest)  #已经下载过rvest包的,可以注释这一步
library(xml2)   #载入包
library(rvest)  #载入包(有时候会提醒先载入xml2后才能载入rvest)

第二步:读取解析网站代码

url0 <- 'https://coding.imooc.com/'#链接命名,先把网站网址记录为url0
web <- read_html(url0)  #使用xml2包中的一个函数来解析网站,读取的结果为网页的代码

第三步:爬取标题与链接

查找元素
找到标题和连接对应的位置,进行爬取。先点开网页的代码看看对应在哪。
方法:右击-查看元素/审查元素
在这里插入图片描述很显然标题位置是在类别class='shizhan-header-nav’div中,在这个div里面还有一个class=‘clearfix’a,那么我们就可以轻松定位了。

定位原则:

  • 如果div有一个calss=‘shizhan-header-nav’,那么可以用div.shizhan-header-nav定位
  • 如果div里面有一个子层a就用空格进一步定位div a

使用的函数

html_nodes(解析的代码,定位的节点) #返回的是节点的解析代码
html_text(解析代码) #返回的是解析代码的文本内容
html_attrs(解析代码) #返回的是解析代码中的href内容,即链接

爬取题目!!

# 取得网页主标题
web_title <-html_nodes(web,'div.shizhan-header-nav div.clearfix a')
title <- html_text(web_title)
# 等价于下式,使用了R语言中的管道:将前者通过管道传到函数的第一个参量,后面均使用管道
# title <- web %>% html_nodes('div.shizhan-header-nav div.clearfix a') %>% html_text()
#获取网页主标题链接
link_ <- web %>% html_nodes('div.shizhan-header-nav div.clearfix a') %>% html_attrs()

然鹅事情并不是那么顺利,前端开发的网页是这样的:
在这里插入图片描述我们获取的链接是只有一半:/?c=fe。所以需要在前面拼接https://coding.imooc.com

link <-c(1:length(title))  #先给个初值
s <- 'https://coding.imooc.com' 
for (i in 1:length(title)) {
  link[i] <-link_[[i]][[1]]   #值得注意的是,这里的link是data.frame格式
  link[i] <- paste0(s,link[i])} #每一个都连接好
title <- title[-1];link <- link[-1]  #第一个可以去掉了,因为前端开发前面是全部,没用

第四步:整理全部代码

# install.packages(rvest)  #下载rvest包,下载过的可以跳过
library(xml2)
library(rvest)
url0 <- 'https://coding.imooc.com/'#链接命名
s <- 'https://coding.imooc.com' #
web <- read_html(url0)  #解析网站
#取得网页主标题
title <- web %>% html_nodes('div.shizhan-header-nav div.clearfix a') %>% html_text()
#获取网页主标题链接
link_ <- web %>% html_nodes('div.shizhan-header-nav div.clearfix a') %>% html_attrs()
link <-c(1:length(title))
for (i in 1:length(title)) {
  link[i] <-link_[[i]][[1]]
  link[i] <- paste0(s,link[i])}
title <- title[-1];link <- link[-1]

三、对单个课程类别所有课程爬取

1.爬取单个课程类别的函数代码
先对对单个类别爬取,直接编了一个函数,这个函数的参数是url与data

  • url是链接,就是上面第二大点爬取的课程大类的链接
  • data是data.frame格式的表格,就是拿来装数据的,所以在调用函数的时候需要在前面赋予初值空表格 data <- data.frame()
download <- function(url,data)
{
web <- read_html(url)
#获取标题、等级、价格
title <- web %>% html_nodes('p.shizan-name') %>% html_text()
rank <- web %>% html_nodes('div.shizhan-info span.grade') %>% html_text()
cost <- web %>% html_nodes('div.clearfix div.course-card-price') %>% html_text()
all <- web %>% html_nodes('div.shizhan-info span') %>% html_text()
#有等级的和没等级的要区分,计算没等级的个数,并去掉all中相应的元素
n <- length(title)-length(rank)
if (n>0) {all <- all[-1:-(2*n)]}
#计算有特价活动的个数(已经排除了没等级的特价),并去掉all中相应的元素
m <- length(rank)-length(cost)
if (m>0) {all <- all[-1:-(3*m)]}
#计算真正需要的个数,并去掉title_1不需要的
k <- length(title)-length(cost)
if (k>0) {title <- title[-1:-k]}
#更新相应的标题,等级,播放量,评价量
a <- seq(1,by = 3,length.out = length(cost))
b <- seq(2,by = 3,length.out = length(cost))
c <- seq(3,by = 3,length.out = length(cost))
rank <- all[a]
play <- all[b]
comment <- all[c]
#联立元素成frame,并且与之前爬取的frame再拼接
dat <- data.frame(title,rank,cost,play,comment)
data <- rbind(data,dat)
#页码特点
page <- web %>% html_nodes('div.page a') %>% html_text()
#页码地址
page.attr <- web %>% html_nodes('div.page a') %>% html_attrs()
#递归获取下一页的数据
if (length(page)>1)   #页数大于1的需要递归
  {
  if (page[length(page)-1]=='下一页') 
    {
    next.page <- page.attr[[length(page)-1]][[1]]
    s <- 'https://coding.imooc.com/'
    next.page <- paste0(s,next.page)
    data <-download(next.page,data)
    }
  }
return(data)
}

2.函数解析(适合小白)

A.直接爬取相应信息

当调用函数的时候给定了链接 url 和空表格 data 之后,爬取题目,等级,价格,但是因为播放量不能定位,不好单独爬取,所以直接全部爬取了。看下图:

  • 中级对应的classgrade
  • 评价对应的classr
  • 而播放量没有class,所以不能单独爬取
  • 所以麻烦一点,把div.shizhan-info位置下的全部span全部爬取!!(后期找规律提取)
    在这里插入图片描述
  • 代码
web <- read_html(url)
#获取标题、等级、价格
title <- web %>% html_nodes('p.shizan-name') %>% html_text()
rank <- web %>% html_nodes('div.shizhan-info span.grade') %>% html_text()
cost <- web %>% html_nodes('div.clearfix div.course-card-price') %>% html_text()
all <- web %>% html_nodes('div.shizhan-info span') %>% html_text()
  • 结果(title\rank\cost\all)
    在这里插入图片描述rank
    在这里插入图片描述在这里插入图片描述
  • 问题分析
    – 慕课网一页的课程量最多为40个
    – title爬取了40个,没问题
    – rank爬取了39个,少了一个?
    – cost爬取了38个,少了两个?
    – all爬取了119个,里面分别按着等级-播放量-评价量进行排序,应该得有40x3=120。第一个课程少了一个等级,所以总数只有119
  • 究竟是什么问题呢?原因是有课程在搞特价!所以格式单独拿出来了,如图:
    – rank少了第一个国庆特价的
    – cost少了两个搞活动的
    – all 也是少了国庆特价的那个等级
    在这里插入图片描述
B.问题A的解决

我们干脆只要没有优惠活动的课程信息(有优惠的可单独爬取)按这个思路

特征对应活动
无等级rank国庆活动
无价格cost所有优惠活动

就有以下程序:

#有等级的和没等级的要区分,计算没等级的个数,并去掉all中相应的元素
n <- length(title)-length(rank) 
if (n>0) {all <- all[-1:-(2*n)]}
#计算有其他特价活动的个数(已经排除了没等级的特价),并再去掉all中相应的元素
m <- length(rank)-length(cost)
if (m>0) {all <- all[-1:-(3*m)]}
#计算真正需要的课程标题,并去掉title不需要的
k <- length(title)-length(cost)
if (k>0) {title <- title[-1:-k]}
#从all中分别提取:等级,播放量,评价量
a <- seq(1,by = 3,length.out = length(cost))
b <- seq(2,by = 3,length.out = length(cost))
c <- seq(3,by = 3,length.out = length(cost))
rank <- all[a]
play <- all[b]
comment <- all[c]
#联立元素成frame,并且与之前爬取的frame再拼接
dat <- data.frame(title,rank,cost,play,comment)
data <- rbind(data,dat)

运行完程序之后就把所有题目降价的课程去掉了!并且成功爬取第一页的课程信息
在这里插入图片描述在这里插入图片描述

C.翻页爬取

终于到了函数的最后一段了!还是先放代码

page <- web %>% html_nodes('div.page a') %>% html_text()
#页码地址
page.attr <- web %>% html_nodes('div.page a') %>% html_attrs() 
#递归获取下一页的数据
if (length(page)>1)   #页数大于1的需要递归
  {
  if (page[length(page)-1]=='下一页') 
    {
    next.page <- page.attr[[length(page)-1]][[1]]
    s <- 'https://coding.imooc.com/'
    next.page <- paste0(s,next.page)
    data <-download(next.page,data)
    }
  }
return(data)

下面简单讲讲这段逻辑吧

  • 第一步:爬取页码与页码对应的地址,代码与结果如下(爬取的页码对应地址是不全的,需要后面补全,道理和之前一样)
#页码
page <- web %>% html_nodes('div.page a') %>% html_text()
#页码地址
page.attr <- web %>% html_nodes('div.page a') %>% html_attrs() 

在这里插入图片描述

  • 第二步:只要页码长度大于1的,都需要翻页爬取(最初判断)
  • 第三步:只要页码的倒数第二个是‘下一页’,那么就需要翻页爬取(判断)
  • 第四步:实际上爬取的页码对应地址是不全的,同样需要用paste0函数拼接!
  • 第五步:进行函数递归,最后返回data数据
if (length(page)>1)   #页数大于1的需要递归
  {
  if (page[length(page)-1]=='下一页') 
    {
    next.page <- page.attr[[length(page)-1]][[1]]   #注意page.attr是表格形式
    s <- 'https://coding.imooc.com/'
    next.page <- paste0(s,next.page)
    data <-download(next.page,data)  #将下一页链接next.page
    }
  return(data)
  }

四、对每个课程大类的链接进行遍历爬取,拼接!

把函数编好之后想到一个问题,函数输出的data是没有记录课程大类标题的,只有课程标题。所以在后面循环调用函数的时候补上一列总标题吧
有空补上

data <- data.frame()   #调用函数给初值
title.last <- rep(1,0)  #总标题标题初值,向量长度要与该总标题下课程量一致
for(i in 1:length(link))  #每个链接遍历
{
  #求出每一个标题的实际数量和生成标题向量(做差)
  if (length(data)==0) {
    title.1 <- rep(title[i],length(data))
  }else{
    title.1 <-rep(title[i],length(data[[1]]))}
  
  data <- download(link[i],data)
  title.2 <- rep(title[i],length(data[[1]]))
  a <- length(title.2)-length(title.1)
  title.single <- rep(title[i],a)
  
  title.last <- c(title.last,title.single)
}
data.last <- data.frame(title.last,data)
  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值