用R语言(rvest包)爬取猎聘网招聘信息(保证可重复性)

前言

 最近一直在思考动手做自己的第一个R语言数据分析项目,在R语言中文社区公众号上看了许多爬取招聘网站的案例后,发现做招聘信息分析是个不错的选择:

 1. 整合并分析招聘信息可以深入了解各个岗位的整体收入情况、学历要求、经验要求等,相信这是许多人都感兴趣的; 

 2. 招聘网站的信息结构化强,非常有利于爬取(但也有个别信息是特例)。

因此,我萌生了做一个较灵活、完整的招聘信息分析项目的想法。“R语言中文社区”公众号上的文章是非常好的借鉴,让我受益颇多,但是有些许瑕疵导致初学者在动手做时发现无法重复文章结果,作为初学者的自己力求通过本篇文章解决可重复性的问题,希望每行代码都是初学者可成功执行的。

准备工作

目的:从猎聘网获取某一行业的整体收入分布情况

加载包:

library(rvest)
library(tidyverse)
library(stringr)
library(readr)

setwd("F:/...") #设定自己的文件路径


第一步:构建URL(重点!)

在猎聘网搜索某一岗位的招聘信息后,通过观察分析网页URL,可以发现主要有两个参数对我们有用:

  • key —— 代表搜索关键词,我们以“数据分析”为例;
  • curPage —— 代表当前页数(注意curPage=0时实际指向第1页)。

另外,经过试验还需要保留fromSearchBtn=2这一参数,才能使curPage参数有效。

接着我们就开心的构建URL文本了:https://www.liepin.com/zhaopin/?&fromSearchBtn=2&key=数据分析&curPage=0。而实际上,当我们直接从浏览器中将网址复制到Rstudio时,发现原来的中文字符变成了一串看不懂的字符:https://www.liepin.com/zhaopin/?&fromSearchBtn=2&key=%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90&curPage=0。 而且当我们尝试硬将中文字符喂给read_html()时会返回错误,而喂上面一串字符时则不会。也就是说我们应该将中文字符转换为这些字符,如何转呢?

通过百度和回忆之前学Python的一点经验,我理解当我们向网站服务器发请求时,URL是需要经过加码(encoding)的,而在浏览器看到的带中文的URL是经过浏览器解码的(decoding)的,所以我们在发送URL前应该进行加码。utils包中的·URLencode()函数就可以实现。


第二步:构建可爬取n页招聘信息的Function(核心!)

代码如下:

# 首先,构建仅爬取一页的Function:
crawl_one_page <- function(key="data analyst", i = 1) {
    # key 为爬取岗位关键词, i 为页码
    base_url <- "https://www.liepin.com/zhaopin/?&fromSearchBtn=2"
    key <- iconv(key, to = "UTF-8") # 保证关键词文本为UTF-8编码
    # 构建URL并加码。注意:别忘了curPage是从0开始的。
    liepin_url <- str_c(base_url, "&key=", key, "&curPage=", (i-1)) %>% URLencode()
    # 由于网站信息可能随时更新,所以下载网页方便验证数据准确性。
    file_name <- str_c("data/", key, i, ".html") #构建文件路径,要事先建一个data文件夹
    download_html(liepin_url, file_name) 
    #下面就是真正从网页上抓取数据了,建议使用SelectorGadget定位信息节点,非常方便。
    lp_html <- read_html(file_name)
    position <- lp_html %>%     #岗位名称
        html_nodes(".job-info h3 a") %>%
        html_text() %>%
        str_trim() # 删除多余的空白
    company <- lp_html %>%      #公司名称
        html_nodes(".company-name a") %>%
        html_text()
    req_info <- lp_html %>%     #岗位要求,例如:12-18万_北京_大专及以上_5年以上
        html_nodes(".condition") %>%
        html_attr("title") # get title attribute
    req_tb<- str_split(req_info, "_", simplify = TRUE) %>% as_tibble()
    colnames(req_tb) <- c("salary", "location", "education", "experience")
    pos_tb <- tibble(position, company) %>% bind_cols(req_tb)
    return(pos_tb)
}
# 本来还想抓取行业信息,但发现有些公司对应两个行业,导致爬取时长度(length)与其他信息不同,
# 无法合并,规划以后想办法解决。

# 之后,构建爬取n个网页的function:
crawl_n_page <- function(key = "data analyst", n = 1){
    pos_lt <- vector("list", n) #事先分配存储空间,有利于提高效率——Hadley大神
    for (i in seq_len(n)) {
        pos_lt[[i]] <- crawl_one_page(key, i) 
        cat("Crawling page:", i, "\tProgress:", (i/n)*100, "%\n") # 显示进度
        Sys.sleep(5)
    }
    pos_tb <- bind_rows(pos_lt) #将list转换为tibble
    return(pos_tb)
}

这就构建好了爬取function,最终返回的结果应该为一张有position,company等信息的tibble。同时,也可以在data文件夹内看到下载的网页HTML。


第三步:爬取招聘信息数据

#爬取10页数据分析岗位招聘信息
position <- "数据分析"
#首先尝试爬取1页是否成功: pos_tb <- crawl_one_page(position, 4)
#然后爬取10页内容
pos_tb <- crawl_n_page(position, 10)
## Crawling page: 1     Progress: 10 %
## Crawling page: 2     Progress: 20 %
## Crawling page: 3     Progress: 30 %
## Crawling page: 4     Progress: 40 %
## Crawling page: 5     Progress: 50 %
## Crawling page: 6     Progress: 60 %
## Crawling page: 7     Progress: 70 %
## Crawling page: 8     Progress: 80 %
## Crawling page: 9     Progress: 90 %
## Crawling page: 10    Progress: 100 %
# 验证表内容
head(pos_tb)
## # A tibble: 6 x 6
##   position            company       salary location education   experience
##                                             
## 1 数据分析担当(劳务派遣)~ 欧珀莱官方网站~ 10-14~ 北京     本科及以上  2年以上   
## 2 数据统计综合岗      恒天财富      面议   北京     统招本科    经验不限  
## 3 安全大数据分析岗(信息安全方向)J1~ 陆金所        面议   上海     统招本科    经验不限  
## 4 数据分析岗(审计方向)~ 上海东昌汽车管理有限公司~ 16-20~ 上海     统招本科    经验不限  
## 5 数据分析专家        小红书        面议   上海     本科及以上  经验不限  
## 6 数据分析员          浙江曦彩服饰有限公司~ 6-7万  杭州     中专/中技及以上~ 经验不限
#存储数据到RDS备用:
rds_path <- str_c("data/", position, ".RDS")
write_rds(pos_tb, rds_path)


第四步:构建作图function,并做简单的可视化分析

# (1) 做简单的收入区间分析 --下面的代码比较啰嗦,有待优化
plot_income <- function (pos_tb) {
    
    salary1 <- pos_tb %>%
        filter(salary != "面议") %>%
        select(salary) %>%
        str_match_all("(\\d+)-(\\d+)") %>%
        .[[1]]
    colnames(salary1) <- c("range", "low", "high")
    
    salary2 <- salary1 %>%
        as.tibble() %>%
        mutate(
            low = parse_number(low),
            high = parse_number(high),
            avg = (low + high)/2,
            cut = cut_interval(avg, length = 10)
        )
    
    plot1 <- salary2 %>%
        mutate(cut = cut_interval(avg, length = 10)) %>%
        ggplot(aes(cut)) +
        geom_bar() 
    return(plot1)
}

# 可视化
title <- str_c(position, "岗位收入分布")
plot_income(pos_tb) + ggtitle(title)

用R语言(rvest包)爬取猎聘网招聘信息(保证可重复性)_第1张图片

你可能感兴趣的:(R语言)