R爬虫必备——httr+GET请求类爬虫(解螺旋课程)

前期R爬虫必备—httr+ POST请求类爬虫(网易云课堂)这篇推文主要介绍了httr包如何进行POST请求类爬虫,POST请求往往和异步加载组合出现,有关于异步加载在推文R爬虫必备基础—动态异步加载中也做过介绍。今天呢,主要来讲讲GET请求类爬虫。对于这类请求,往往用rvest、httr或RCurl包都可以,但我们主要还是推荐httr和RCurl。上一期 R爬虫必备基础—rvest为什么不用于动态网页?里已经提过,对于网络请求有限制的网页,尽可能不要使用rvest,因为存在风险。除了极少数静态网页对网络请求完全没有限制外,目前基本上接触的大部分网页或多或少对网络请求都设置。当然在很多情况下,对于这类GET请求类的网页,用rvest包其实也可以成功抓取少量内容,但很容易被封。所以呢,保险点,还是用httr/RCurl吧!

今天呢,主要就httr包如何开展GET请求类爬虫做简单介绍!首先,先看下httr这个R包中GET函数的大致用法:GET(url = NULL, config = list(), ..., handle = NULL),这里面比较重要的是config参数(设置请求头、cookies和query)。具体参数解释如下:

  • url :the url of the page to retrieve
  • config:Additional configuration settings such as http authentication (authenticate()), additional headers (add_headers()), cookies (set_cookies()) etc. See config() for full details and list of helpers. Further named parameters, such as query, path, etc, passed on to modify_url(). Unnamed parameters will be combined with config().
  • handle:The handle to use with this request. If not supplied, will be retrieved and reused from the handle_pool() based on the scheme, hostname and port of the url. By default httr requests to the same scheme/host/port combo. This substantially reduces connection time, and ensures that cookies are maintained over multiple requests to the same host. See handle_pool() for more details.

接下来,为了更好理解httr包如何完成一项GET请求类爬虫,下面以解螺旋课程为例做简单介绍!

解螺旋课程案例说明

首先进入解螺旋官网(https://www.helixlife.cn/),点击精品课程,然后右击-检查打开浏览器开发工具,点击Network面板,然后ctrl+R刷新,点击第一条信息,发现该网页是个GET请求类。想获取这页信息,对https://www.helixlife.cn/courses/boutique网址走GET请求即可!

image

但我们发现精品课程共计4页,想要获取所有的课程信息应该怎么办? 首先,需要分析每个页面的网址,有没有规律,当我们逐条点击不同页面时,发现浏览器开发后台的General中Request URL的变化规律如下:

https://www.helixlife.cn/courses/boutique?page=1
https://www.helixlife.cn/courses/boutique?page=2
https://www.helixlife.cn/courses/boutique?page=3
https://www.helixlife.cn/courses/boutique?page=4

同时,Query String Parameters的变化规律如下:

page: 1
page: 2
page: 3
page: 4

在正式爬取之前,需要对下面爬虫主要涉及的参数做下介绍:General里面的Request URL、Request Method、Status Code;Response Headers里面的Content-Type;Request Headers 里面的 Accept、Content-Type、Cookie、Referer、User-Agent等以及最后Query String Parameters里面的所有参数。

  • General里面的Request URL和Request Method方法即是即决定访问的资源对象和使用的技术手段。
  • Response Headers里面的Content-Type决定着你获得的数据以什么样的编码格式返回。
  • Request Headers 里面的 Accept、Content-Type、Cookie、Referer、User-Agent等是你客户端的浏览器信息,其中Cookie是你浏览器登录后缓存在本地的登录状态信息,使用Cookie登入可以避免爬虫程序被频繁拒绝。这其中的参数不一定全部需要提交。
  • Query String Parameters也很重要,是GET请求必备的定位信息,该到哪一页了。
如何实际操作?

1. 加载所需要的R包,没安装的提前安装。

rm(list=ls())
library("httr") 
library("magrittr")
library("rvest")
library("xml2")
library("stringr")

2. 首先构造第一页的url。

url <- c('https://www.helixlife.cn/courses/boutique?page=1')

3. 构造请求提交信息,根据Request headers的内容填写,如下图所示。

mycookie <- 'Hm_lvt_4b46c1065cade82ef3fa0c6e05cb0f7a=1592799906; XSRF-TOKEN=eyJpdiI6IkEzcWcwZWlhWkJtOGlIWTZWSzZ3V3c9PSIsInZhbHVlIjoiMkxXV3pLbEx3R3lwY2x0SW1tdEh2VGxpSXNjejdDVTVGeFMwV1NrdHpZbkMxSlowcXlnc1J6cVFJdUV2V3dpQiIsIm1hYyI6ImEwZjhjOGZlNTBiMGZmNzdkNmViYTNkNzc4OTM3YzBmZWZlNmFhOTQ0OTAwN2JlNzYzNDQzNjY3MmMzODJmY2YifQ%3D%3D; _session=eyJpdiI6IktaMzFDYTRaOHh6UWM4RmFHYU9yM2c9PSIsInZhbHVlIjoielEzVmRzK0toVzE2Q1dWVjFwSWZZTXRKUEszd3Y5UU9vWFFxV0xUTXNPNk56WkNFcEZ5SHpHTFN0Zk9SNnFGTCIsIm1hYyI6ImU2Mjc2YWI2MGMxY2FkZDA2N2E4NGMwYmRiOTUzOGYwZjQ3NWY1MTg1ZjMyMzk0Zjg0Mjk5OGY1NGU5NTVkODMifQ%3D%3D; SERVERID=3f56386521b609ab6e34c0e5ca694901|1592802688|1592802016; Hm_lpvt_4b46c1065cade82ef3fa0c6e05cb0f7a=1592802695'
myheaders <- c('accept' ='text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
               'accept-encoding' = 'gzip, deflate, br',
               'accept-language' = 'zh-CN,zh;q=0.9',
               'user-agent' = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
               'cookie' = mycookie)
image

4. 构造请求头参数信息,根据Query String Parameters内容填写。以下代码是第一页的Query String Parameters参数。

mypayload <- list("page"= 1)
image.gif

5. 执行第一页,httr的GET函数,这里用什么函数是由General里的Request Method参数决定的。

GET(url , add_headers(.headers = 待爬取网页的头部信息),
    set_cookies(.cookies =自己的cookie,
    query = Query String Parameters(构建成特定格式),
    timeout(最大请求时长/秒),
    use_proxy(代理IP)...)

根据GET函数用法,正式进行网络请求,服务器响应返回包含有json格式课程的数据。

response <- GET(url = url, add_headers(.headers = myheaders), timeout(10), query = mypayload)

这时候通过httr包的GET函数成功请求并获取到网页信息,接下来,交给rvest包进行下游的解析和提取,这方面rvest包更强大。

url <- c('https://www.helixlife.cn/courses/boutique?page=1')
  mycookie <- 'Hm_lvt_4b46c1065cade82ef3fa0c6e05cb0f7a=1592799906; XSRF-TOKEN=eyJpdiI6IkEzcWcwZWlhWkJtOGlIWTZWSzZ3V3c9PSIsInZhbHVlIjoiMkxXV3pLbEx3R3lwY2x0SW1tdEh2VGxpSXNjejdDVTVGeFMwV1NrdHpZbkMxSlowcXlnc1J6cVFJdUV2V3dpQiIsIm1hYyI6ImEwZjhjOGZlNTBiMGZmNzdkNmViYTNkNzc4OTM3YzBmZWZlNmFhOTQ0OTAwN2JlNzYzNDQzNjY3MmMzODJmY2YifQ%3D%3D; _session=eyJpdiI6IktaMzFDYTRaOHh6UWM4RmFHYU9yM2c9PSIsInZhbHVlIjoielEzVmRzK0toVzE2Q1dWVjFwSWZZTXRKUEszd3Y5UU9vWFFxV0xUTXNPNk56WkNFcEZ5SHpHTFN0Zk9SNnFGTCIsIm1hYyI6ImU2Mjc2YWI2MGMxY2FkZDA2N2E4NGMwYmRiOTUzOGYwZjQ3NWY1MTg1ZjMyMzk0Zjg0Mjk5OGY1NGU5NTVkODMifQ%3D%3D; SERVERID=3f56386521b609ab6e34c0e5ca694901|1592802688|1592802016; Hm_lpvt_4b46c1065cade82ef3fa0c6e05cb0f7a=1592802695'
  myheaders <- c('accept' ='text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
                 'accept-encoding' = 'gzip, deflate, br',
                 'accept-language' = 'zh-CN,zh;q=0.9',
                 'user-agent' = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
                 'cookie' = mycookie)
  mypayload <- list("page"= 1)
  response <- GET(url = url, add_headers(.headers = myheaders),query = mypayload, encode="raw")
  #read_html()函数读入并解析网页内容
  web <- read_html(response, encoding ="utf-8")
  #提取课程名称
  course_names <- web %>% html_nodes("div.course-info-container a") %>% html_text()
  #提取课程级别
  course_class <- web %>% html_nodes("span.course-rank") %>% html_text() %>% str_replace_all(" ","") %>% str_replace_all("\n","")
  #提取观看人数
  course_people <- web %>% html_nodes("div.lean-num img") %>% html_attr("alt") 
  #提取课程评分
  course_grade <- web %>% html_nodes("div.course-info-text span.f-l") %>% html_text() %>% str_replace_all(" ","") %>% str_replace_all("\n","") %>% str_replace_all("评分:","")
  course_grade <- course_grade[seq(2,length(course_grade),2)]
  #提取课程价格
  course_price <- web %>% html_nodes("div.course-price") %>% html_text() %>% str_replace_all("¥","")
  #创建数据框存储以上信息
  course <- data.frame(course_names,course_class,course_people,course_grade,course_price)
  course_inf <- rbind(course_inf,course)
  1. 执行获取所有页面信息,共4页,利用循环抓取。
i=1
course_inf <- data.frame()
for (i in 1:4){
  url <- c(paste0('https://www.helixlife.cn/courses/boutique?page=',i))
  mycookie <- 'Hm_lvt_4b46c1065cade82ef3fa0c6e05cb0f7a=1592799906; XSRF-TOKEN=eyJpdiI6IkEzcWcwZWlhWkJtOGlIWTZWSzZ3V3c9PSIsInZhbHVlIjoiMkxXV3pLbEx3R3lwY2x0SW1tdEh2VGxpSXNjejdDVTVGeFMwV1NrdHpZbkMxSlowcXlnc1J6cVFJdUV2V3dpQiIsIm1hYyI6ImEwZjhjOGZlNTBiMGZmNzdkNmViYTNkNzc4OTM3YzBmZWZlNmFhOTQ0OTAwN2JlNzYzNDQzNjY3MmMzODJmY2YifQ%3D%3D; _session=eyJpdiI6IktaMzFDYTRaOHh6UWM4RmFHYU9yM2c9PSIsInZhbHVlIjoielEzVmRzK0toVzE2Q1dWVjFwSWZZTXRKUEszd3Y5UU9vWFFxV0xUTXNPNk56WkNFcEZ5SHpHTFN0Zk9SNnFGTCIsIm1hYyI6ImU2Mjc2YWI2MGMxY2FkZDA2N2E4NGMwYmRiOTUzOGYwZjQ3NWY1MTg1ZjMyMzk0Zjg0Mjk5OGY1NGU5NTVkODMifQ%3D%3D; SERVERID=3f56386521b609ab6e34c0e5ca694901|1592802688|1592802016; Hm_lpvt_4b46c1065cade82ef3fa0c6e05cb0f7a=1592802695'
  myheaders <- c('accept' ='text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
                 'accept-encoding' = 'gzip, deflate, br',
                 'accept-language' = 'zh-CN,zh;q=0.9',
                 'user-agent' = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
                 'cookie' = mycookie)
  mypayload <- list("page"= i)
  response <- GET(url = url, add_headers(.headers = myheaders),query = mypayload, )
  #读入并解析网页内容
  web <- read_html(response, encoding ="utf-8")
  #提取课程名称
  course_names <- web %>% html_nodes("div.course-info-container a") %>% html_text()
  #提取课程级别
  course_class <- web %>% html_nodes("span.course-rank") %>% html_text() %>% str_replace_all(" ","") %>% str_replace_all("\n","")
  #提取观看人数
  course_people <- web %>% html_nodes("div.lean-num img") %>% html_attr("alt") 
  #提取课程评分
  course_grade <- web %>% html_nodes("div.course-info-text span.f-l") %>% html_text() %>% str_replace_all(" ","") %>% str_replace_all("\n","") %>% str_replace_all("评分:","")
  course_grade <- course_grade[seq(2,length(course_grade),2)]
  #提取课程价格
  course_price <- web %>% html_nodes("div.course-price") %>% html_text() %>% str_replace_all("¥","")
  #创建数据框存储以上信息
  course <- data.frame(course_names,course_class,course_people,course_grade,course_price)
  course_inf <- rbind(course_inf,course)
}
#将数据写入csv文档
write.csv(course_inf, file="course_inf.csv")

最终爬取结果如下,解螺旋官网上的精品课程共计52门。

image.png

下面简单对这部分课程信息做进一步分析,比如想知道这些课程在不同级别上的分布?经分析发现,共计四种课程分级:入门、初级、中级和高级,其中初级类课程最多,高级类课程最少。可见解螺旋的课程设置偏向小白用户,致力于入门和打基础。

rm(list=ls())
library("readx")
course_inf <- read.csv("course_inf.csv", header = T,stringsAsFactors = F)

##整理数据,修改数据格式
course_inf$course_people <- as.numeric(as.character(course_inf$course_people))
course_inf$course_grade <- as.numeric(as.character(course_inf$course_grade))
course_inf$course_price <- as.numeric(as.character(course_inf$course_price))
str(course_inf)

#课程在不同级别上的分布
course_class <- as.data.frame(sort(table(course_inf$course_class),decreasing = T))
library(ggplot2)
ggplot(course_class,aes(Var1,Freq)) + geom_bar(stat = "identity") + 
  labs(x = "课程分类", y = "课程数量") +
  theme(panel.background=element_rect(fill='transparent')) + 
  geom_text(mapping = aes(label = Freq),size=4,vjust=-1,color = "black")
image

往往官网的课程设置也是有讲究的,一般适用群体范围较大的课程会花更多时间和精力去打造,从上述分析中偏基础入门类的课程多达41门,占所有课程的80%。那是不是这部分课程的确受用户偏爱呢?如下图,入门类课程的观看人数多达26000多人,占据份额的一大半。从这些数据不难看出,解螺旋的精品课程中入门类课程设置最多,且也是用户最偏爱的一类课程。

rumen <- sum(course_inf[course_inf$course_class=="入门","course_people"])
chuji <- sum(course_inf[course_inf$course_class=="初级","course_people"])
zhongji <- sum(course_inf[course_inf$course_class=="中级","course_people"])
gaoji <- sum(course_inf[course_inf$course_class=="高级","course_people"])
tmp1 <- data.frame("入门"=rumen,"初级"= chuji,"中级" = zhongji, "高级" = gaoji)
tmp1 <- as.data.frame(t(tmp1))
tmp1$V2 <- factor(rownames(tmp1),levels = c("入门", "初级" , "中级",   "高级"))
  
ggplot(tmp1,aes(V2,V1)) + geom_bar(stat = "identity") + 
  labs(x = "课程分类", y = "观看人数") +
  theme(panel.background=element_rect(fill='transparent')) + 
  geom_text(mapping = aes(label = V1),size=4,vjust=-1,color = "black")
image

以上只是做了些简单分析,有兴趣的小伙伴,可以根据自己需求,个性化的进行分析。此外,若有小伙伴想重复此代码,需要更新自己的cookies,否则容易运行失败。

往期回顾
R爬虫在工作中的一点妙用
R爬虫必备基础——HTML和CSS初识
R爬虫必备基础——静态网页+动态网页
R爬虫必备——rvest包的使用
R爬虫必备基础——CSS+SelectorGadget
R爬虫必备基础—Chrome开发者工具(F12)
R爬虫必备基础—HTTP协议
R爬虫必备—httr+POST请求类爬虫(网易云课堂)
R爬虫必备基础—rvest为什么不用于动态网页?

你可能感兴趣的:(R爬虫必备——httr+GET请求类爬虫(解螺旋课程))