CoderCastrov logo
CoderCastrov
R

Как парсить информацию о вакансиях с помощью R

Как парсить информацию о вакансиях с помощью R
просмотров
9 мин чтение
#R

Есть множество учебников на Python, которые показывают, как создать скрипт с использованием Beautiful Soup, который извлекает вакансии с Indeed на LinkedIn, но не так много для R. Поэтому я решил продемонстрировать, что R имеет такую же возможность, как и Python (и, на мой взгляд, немного более интуитивную). Я выбрал парсинг вакансий с веб-сайта https://www.reed.co.uk/ на основе этой статьи Towards Data Science, которая показывает, как сделать это на Python (Вы можете найти скрипт здесь). Reed.co.uk - это сайт вакансий, подобный Indeed.

С чего начать

Когда я впервые начал парсить веб-сайты, я просто бесцельно бродил, собирая то ту, то другую информацию, пока не получил нужные данные. Это был ужасно неэффективный способ парсинга веб-сайтов с точки зрения времени и ресурсов. Лучший способ, и я уверен, что многие согласятся со мной, - начать с составления плана. Я начинаю с минимального исследования и затем, в зависимости от содержимого сайта, придумываю идеи для сбора нужных мне данных.

EDA

Давайте сделаем самую базовую вещь и посмотрим на интересующий нас веб-сайт. Вот ссылка: https://www.reed.co.uk/jobs. Я использовал поле поиска "what", чтобы ввести "data scientist", и поле поиска "where", чтобы ввести "London". Теперь URL имеет два параметра (но в URL будет отображаться только один) и выглядит так: "https://www.reed.co.uk/jobs/data-scientist-jobs-in-london".

Кроме того, я также нажал на "полная занятость" и "в радиусе 50 миль", это добавило еще несколько параметров и преобразовало URL в "https://www.reed.co.uk/jobs/data-scientist-jobs-in-london?fulltime=True&proximity=50".

Теперь, когда у нас есть URL, с которого мы собираемся собирать информацию, давайте разработаем план того, что у нас есть на странице и что мы хотим собрать.

Планирование

В конечном итоге я хочу проанализировать позиции и определить, какие навыки требуются для позиции Data Scientist в Великобритании, а также узнать, какие позиции оплачиваются лучше всего. Я составил список того, что мне нужно, и добавил причины, почему я хочу эти элементы:

Тестирование

Я сразу заметил, что у меня возникнет проблема с моим списком желаний; на главной странице, где перечислены все вакансии, описания обрезаны. Чтобы получить полное описание, нужно перейти на каждую отдельную страницу с вакансией. Но это довольно просто, первая задача, которую нам нужно выполнить, - это спарсить URL-адреса всех отдельных страниц с вакансиями из списка вакансий.

We will have to pull all the information from the jobs page. This is what each individual job page looks like.

Получение URL-адресов

К счастью, Reed.co.uk использует шаблон URL, который легко можно спарсить. Как видно на скриншоте выше, каждая страница вакансии идентифицируется уникальным номером. На странице списка вакансий есть ссылка на все эти страницы, поэтому мы можем просто спарсить URL из каждого списка.

Первое, что нужно сделать, это открыть инструменты разработчика вашего браузера, они отличаются для каждого браузера. Лично я использую Chrome. В Chrome есть инструмент "Инспектор элементов", который позволяет вам осмотреть элемент. Когда я использую его и нажимаю на заголовок, он выглядит так:

Слева (выделено синим) предоставляется информация о том, что вы видите, а справа (выделено серым) предоставляется код. В задаче по получению URL мы видим, что есть элемент с именем "data-id". Это параметр URL для каждой вакансии. Нам просто нужно спарсить эту часть кода. Однако, как мы узнаем, сколько вакансий/страниц нужно спарсить?

После некоторого исследования я обнаружил две части кода, которые покажут нам, сколько вакансий есть и как их спарсить. Во-первых, номер страницы определяется параметром URL и в противном случае остается неизменным. Во-вторых, номер вакансии указан на веб-странице (см. скриншот ниже).

Вы можете спарсить номер вакансии.

Итак, нам нужно извлечь эту информацию и создать вектор значений для текущей вакансии и общего числа вакансий.

Сначала нам нужно загрузить наши пакеты, нам понадобится только пакет Tidyverse, так как rvest входит в этот пакет.

library("tidyverse")

Затем мы хотим загрузить HTML-страницу в R.

reed_data <- read_html("[https://www.reed.co.uk/jobs/data-scientist-jobs-in-london?fulltime=True&proximity=5](https://www.reed.co.uk/jobs/data-scientist-jobs-in-london?fulltime=True&proximity=1000)0")

Если вы хотите увидеть, как выглядит веб-сайт в R, просто используйте функцию html_text().

reed_data %>% html_text()

Теперь мы собираемся получить количество вакансий и общее число вакансий. В основном, мы будем использовать html_nodes(), чтобы определить текст, который нам нужен, затем разделить его, чтобы он был в виде списка. Затем из этого списка мы извлечем два элемента, которые нам нужны. Я получил эти числа, играясь и печатая список.

job <- reed_data %>% 
  html_nodes("div") %>% 
  html_nodes(xpath = '//*[[@class](http://twitter.com/class)="page-counter"]')%>% 
  html_text() %>%
  strsplit(" ")current_job <- as.numeric(job[[1]][27])
total_job <- as.numeric(job[[1]][29])
paste('На этой странице есть', current_job, 'вакансий из общего числа', total_job, "вакансий")

После выполнения кода он вернет "На этой странице есть 25 вакансий из общего числа 581 вакансий" (Общее число вакансий будет отличаться в зависимости от того, сколько их есть в данный день).

Далее нам нужно создать цикл, который будет проходить через каждую страницу и извлекать 'data-id', который мы определили выше. Для этого мы запустим цикл, который будет проверять, есть ли у нас все вакансии, и если нет, перейти на следующую страницу.

n_page=1while (current_job < total_job){
    # Это будет объединять URL в зависимости от страницы
    p = str_c('[https://www.reed.co.uk/jobs/data-scientist-jobs-in-london?pageno=',n_page,'&fulltime=True&proximity=50'](https://www.reed.co.uk/jobs/data-scientist-jobs-in-london?pageno=%27%2Cn_page%2C%27&fulltime=True&proximity=50%27), sep="")
    URL_p = read_html(p)
    
    # Это получит URL
    url <- URL_p %>% 
      html_nodes("div") %>% 
      html_nodes(xpath = 'a')%>% 
      html_attr('data-id')
    url <- url[!is.na(url)]
    
    # Это добавляет данные вместе
    job_url <- append(job_url, url)
    
    # Это получает новое количество вакансий и изменяет текущую вакансию на это число
    job <- URL_p %>% html_nodes("div") %>%  html_nodes(xpath = '//*[[@class](http://twitter.com/class)="page-counter"]')%>% html_text() %>% strsplit(" ")
    current_job <- as.numeric(job[[1]][27])# Это говорит нам перейти на следующую страницу
    n_page <- n_page + 1
    
}
paste("Теперь есть", current_job, "вакансий из общего числа", total_job, "вакансий")

После выполнения кода он сообщит вам, что "Теперь есть 581 вакансий из общего числа 581 вакансий". И 'job_url' будет списком всех параметров URL. И этот шаг завершен, следующая задача - спарсить информацию, которая нам нужна.

Сбор информации

Прежде всего, нам нужно посмотреть код страницы с вакансиями, чтобы узнать, что можно извлечь. В качестве примера я покажу процесс, который я использовал, чтобы найти то, что мне нужно было извлечь из описания.

Когда я открыл инструменты разработчика, я использовал инструмент "Инспектировать элемент", чтобы щелкнуть на самом большом разделе описания, если вы следуете за мной, это должно выглядеть так:

Но мне не нужна вся эта информация, мне нужна вся информация ниже блока, где указано "Data Scientist". Поэтому в режиме разработчика я щелкнул на классах "div", пока не нашел тот, который находится в области, которую я хотел. В данном случае это было легко, это был 'div class="description"'.

Затем нам просто нужно протестировать его на URL-адресе одной из страниц вакансий (этой страницы может уже не существовать, когда вы будете запускать код).

URL_test = read_html('[https://www.reed.co.uk/jobs/data-scientist/42066794'](https://www.reed.co.uk/jobs/data-scientist/42066794'))
  
  
# Давайте получим описание
Desc <- URL_test %>% html_nodes("[itemprop='description']") %>%
            html_text()
Desc

Результаты будут выглядеть так:

"Data Scientist £45,000 — £70,000 Лондон/ Основано в Великобритании Удаленно Вы консультант по науке о данных с увлечением здравоохранением и позитивным влиянием? Хотите работать в компании, основанной на данных, которая консультирует NHS по стратегии в различных аспектах пандемии COVID-19? КОМПАНИЯ: В качестве Data Scientist вы будете работать в установленной консалтинговой компании в области здравоохранения. Они используют передовые технологии искусственного интеллекта для понимания требований клиента и создания моделей для предоставления решений, способствующих устойчивым изменениям. Команда ученых-исследователей и инженеров по данным планирует крупное расширение. РОЛЬ: Роль Data Scientist будет включать разработку прогностических моделей и программных инструментов для консультаций по стратегии. В частности, вы можете ожидать участия в следующем: Вы будете создавать прогностические модели, чтобы помочь клиентам понять и решить большие проблемы в здравоохранении. Вы будете работать с большими наборами данных для обучения моделей и разработки действенных идей. Вы будете взаимодействовать с заинтересованными сторонами и клиентами с разными техническими навыками, чтобы объяснить идеи и анализ. Вы будете создавать алгоритмы машинного обучения и глубокого обучения. ВАШИ НАВЫКИ И ОПЫТ: Успешный Data Scientist должен обладать следующими навыками и опытом: Образование на уровне доктора философии/ магистра наук в соответствующей области (статистика, информатика, математика и т. д.) Коммерческий опыт работы в качестве инженера машинного обучения/ ученого-исследователя данных в консалтинговой компании Опыт работы в области здравоохранения или биоинформатики или истинный интерес к этим областям является плюсом Python, AWS, Azure ПРЕИМУЩЕСТВА: Успешный Data Scientist получит зарплату, зависящую от опыта, до £70,000 и дополнительные льготы. КАК ПОДАТЬ ЗАЯВКУ: Пожалуйста, зарегистрируйте свой интерес, отправив свое резюме Франческе Кертис по ссылке "Подать заявку" на этой странице."

Работает! Следующий шаг - определить другие данные, которые мы хотим извлечь. Я покажу вам только еще один пример, потому что остальные довольно легко понять. Я покажу вам, как получить "Тип компании", потому что он находится в JavaScript и не так легко получить с помощью инструментов rvest. Вам потребуется использовать регулярные выражения, чтобы получить его.

Чтобы найти скрытые элементы в JavaScript, вам нужно знать немного о разработке серверной части, все, что вам нужно знать, заключается в том, что для некоторых веб-сайтов они будут использовать JavaScript для передачи информации из базы данных в браузер. Это упрощает автоматическое создание страниц, если у вас есть один шаблон для всех информаций, которые должны быть отправлены.

В этом конкретном случае вы можете видеть, что информация находится в JavaScript (на самом деле она передается на веб-страницу, но для этого учебного пособия я хотел показать, как получить JavaScript).

Выделенная желтым цветом информация, которую мы хотим

Код будет выглядеть так:

URL_test = read_html('[https://www.reed.co.uk/jobs/data-scientist/42066794'](https://www.reed.co.uk/jobs/data-scientist/42066794'))
  
  
# Давайте получим тип компании. Поскольку он находится в JavaScript, нам нужно использовать регулярные выражения, чтобы извлечь значение
  Compt <- URL_test %>% str_extract("(jobRecruiterType: )'(\\w+\\s\\w+\\s\\w+|\\w+\\s\\w+|\\w+|\\s)") %>%
      str_extract("(?<=\\')\\D+")
compt

Результаты будут выглядеть так:

"Консалтинг по найму"

Теперь, когда вы узнали, как получить и JavaScript, и html, я покажу вам, как выглядит мой код для парсинга всех страниц. По сути, мы создаем цикл, который будет проходить по списку URL-адресов для каждого сайта с вакансиями (идентификаторы данных, которые мы извлекли выше), затем, на каждой из этих страниц, он будет извлекать информацию, которую мы хотим, и добавлять ее в dataframe.

На некоторых компьютерах это может занять более 10 минут. Я бы рекомендовал убедиться, что вы проверяете его на одном URL-адресе, прежде чем запускать цикл на всех страницах.

for (i in unique(job_url)) {
  p = str_c('[https://www.reed.co.uk/jobs/data-scientist/',i](https://www.reed.co.uk/jobs/data-scientist/',i), sep="")
  URL_p = read_html(p)
  
  
 # Давайте получим описание
  Desc <- URL_p %>% html_nodes("[itemprop='description']") %>%
            html_text()
  Desc <- str_trim(Desc, side = "left")# Давайте получим должность
  Pos <- URL_p %>% html_node("title") %>%
            html_text()
  
  # Давайте получим дату публикации
  Post <- URL_p %>% html_nodes("[itemprop='datePosted']") %>%
            html_attr('content')
  
  # Давайте получим зарплату
  Sal <- URL_p %>% html_nodes("[data-qa='salaryLbl']") %>%
            html_text()
  Sal <- str_trim(Sal, side = "left")
  
  # Давайте получим местоположение
  Loc <- URL_p %>% html_nodes("[data-qa='regionLbl']") %>%
            html_text()
  
  # Давайте получим тип контракта
  Cont <- URL_p %>% html_nodes("[data-qa='jobTypeMobileLbl']") %>%
            html_text()
  
  # Давайте получим название компании
  Comp <- URL_p %>% html_nodes(css ="[itemprop='hiringOrganization']") %>%
            html_nodes(css ="[itemprop='name']") %>%
            html_text() 
  Comp <- str_trim(Comp, side = "left")
  
  # Давайте получим тип компании. Поскольку он находится в JavaScript, нам нужно использовать регулярные выражения, чтобы извлечь значение
  Compt <- URL_p %>% str_extract("(jobRecruiterType: )'(\\w+\\s\\w+\\s\\w+|\\w+\\s\\w+|\\w+|\\s)") %>%
      str_extract("(?<=\\')\\D+") 
  
  # Давайте получим отрасль. Поскольку он находится в JavaScript, нам нужно использовать регулярные выражения, чтобы извлечь значение
  Ind <- URL_p %>% str_extract("(jobKnowledgeDomain: )'(\\w+\\s\\w+\\s\\w+|\\w+\\s\\w+|\\w+|\\s)") %>%
      str_extract("(?<=\\')\\D+") 
  
  url <- p
  
  temp <- c(Desc, Pos, Post, Sal, Loc, Cont, Comp, Compt, Ind, url)
  
  all_jobs <- rbind(temp, all_jobs)
}
paste("Ваша таблица данных создана")

После завершения работы вам нужно будет добавить названия столбцов, но в остальном все готово!

P.S. Есть проблема с получением вакансий, которые являются "рекомендованными", которую я исправил при анализе данных. Вы можете попробовать сделать так, чтобы не получать рекомендованные страницы, или просто сделать то, что я сделал. В любом случае, удачи в парсинге!

-Джош