CoderCastrov logo
CoderCastrov
Парсер

Парсинг вакансий на Stack Overflow

Парсинг вакансий на Stack Overflow
просмотров
7 мин чтение
#Парсер
Table Of Content

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

Парсер создан на языке Python и упакован в контейнер Docker. Парсер ищет на сайте Stack Overflow конкретные вакансии и отправляет уведомления в Slack. Пользователь, связанный с учетной записью Slack и каналом, получит уведомление по электронной почте с ссылками на вакансии и кратким описанием.

Пользователь может выполнить скрипт по требованию, в определенное время, используя crontab, или развернуть приложение Docker.


Технологический стек:

  • Python 3.8.5
  • conda 4.8.5
  • slack 4.9.1
  • Docker 19.03.13

Что такое Slack

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

Виртуализация Python

Обычной практикой является наличие нескольких версий Python с установленными различными библиотеками на одном хосте. Причина в том, что вы сохраняете все аккуратно и компактно для проекта. Вы устанавливаете только необходимые пакеты, не затрагивая другие виртуальные среды. Еще одно преимущество заключается в том, что среду можно экспортировать и легко установить на других носителях. Для этого я использую conda и pip. Conda - это система управления пакетами с открытым исходным кодом и система управления средой для установки нескольких версий программных пакетов и их зависимостей и переключения между ними. Pip - это инструмент для установки пакетов для Python.

Варианты использования скрипта

python web_scraper.py -r yes -t "python django" -e Junior
Отчет о вакансиях сгенерирован: Четверг, 15 октября 2020 г. 17:53
-r yes
-t python django
-e Junior
https://stackoverflow.com/jobs/165665/python-developer-backend-energyworx
https://stackoverflow.com/jobs/443603/backend-developer-python-django-5-monkeys-agency-ab
https://stackoverflow.com/jobs/443604/backend-developer-python-django-5-monkeys-agency-ab
https://stackoverflow.com/jobs/361172/python-django-software-developer-m-f-d-climatepartner
  1. Создание cron-задачи

Cron - это утилита Linux, которая чаще всего используется для запуска запланированных задач.

# Например, вы можете выполнить резервное копирование всех учетных записей пользователей
# в 5 часов утра каждую неделю:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
# 
# Для получения дополнительной информации см. страницы руководства crontab(5) и cron(8)
# 
# m h  dom mon dow   command

Cron выполняет парсер задач

### скрипт парсера вакансий

#SLACK_BOT_TOKEN="slack_api_token"
#home_dir="/script_home_location"
#py="python_env_exec_path"
#53 * * * * conda activate "env"; $py  $home_dir/web_scraper.py -r yes -t "python docker" -e Junior >>$home_d>

С помощью cron-задач вы можете определить конкретное время выполнения скрипта или настроить несколько задач для конкретных поисков.

  1. Приложение может быть упаковано внутри контейнера Docker с cron-задачей и выполняться через определенные интервалы времени.

Создайте и запустите контейнер с помощью спецификаций из Dockerfile. Существуют некоторые соглашения о наименовании, но они не являются строго обязательными. Контейнер может работать в интерактивном режиме с помощью ключа -it или в фоновом режиме с помощью -d.

docker build --rm -f Dockerfile_python -t {user_name}/image_name:{version}
docker run -it {user_name}/image_name:{version}

Dockerfile

FROM python:3.8

# Создание директории приложения
WORKDIR /code

# Установка зависимостей приложения

ENV SLACK_BOT_TOKEN="slack_api_token"
COPY requirements.txt requirements.txt
COPY web_scraper.py .
RUN chmod a+x web_scraper.py
RUN pip install -r requirements.txt

RUN apt-get update && apt-get -y install cron
ADD crontab .
RUN chmod a+x web_scraper.py

RUN crontab crontab
ENTRYPOINT cron -f

Установка окружения

conda create -n "название_окружения" python=3.8

# Установка пакетов Python
pip install mechanicalsoup
pip install slack_sdk

# Экспорт окружения
pip freeze >> requirements.txt

Python поставляется с базовыми библиотеками, но для этого конкретного проекта нам необходимо загрузить дополнительные.

import mechanicalsoup
from datetime import datetime
import argparse

import os
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError

Скрипт содержит несколько функций, которые решают конкретные задачи. Функция jobsearch_options принимает параметры работы от пользователя и использует их в качестве аргументов для поиска работы:

  • является ли работа удаленной {да/нет}
  • технологии/ключевые слова (Python; Docker; AWS)
  • уровень опыта (Junior, Mid-Level)

Получить параметры поиска

# Создать парсер и добавить аргументы
    parser = argparse.ArgumentParser()
    parser.add_argument('-r', help="Удаленная работа {да/нет}", choices=['да', 'нет'])
    parser.add_argument('-t', help="Технологии, связанные с работой", type=str)
    parser.add_argument('-e', help="Опыт", choices=['Младший', 'Старший', 'Средний уровень', 'Лидер'])

    args = parser.parse_args()
    r, t, e = args.r, args.t, args.e
    query=""
    for opt, val in zip(["-r", "-t", "-e"], [r, t, e]):
        print(opt, val)
    if None not in [r, t, e]:
        query = "?q=" + t.replace(" ", "+") + "&r=" + r + "&mxs=" + e

    return query

Функция get_joblinks извлекает ссылки на конкретные вакансии. Ссылка на вакансию формируется путем добавления к базовому base_url = "https://stackoverflow.com/jobs/" + ссылке, специфичной для вакансии. Необходимо иметь представление, по крайней мере в общих чертах, о элементах, составляющих веб-страницу. Это важно для понимания работы скрипта.

Веб-страница состоит из элементов, которые можно найти:

HTML описывает структуру веб-страницы. Веб-страница содержит элементы, называемые тегами, которые указывают браузеру, как отображать содержимое. Элементы веб-страницы вложены друг в друга. С помощью CSS вы можете контролировать стиль и макет страницы.

Иерархию элемента на веб-странице можно узнать, щелкнув правой кнопкой мыши по элементу и выбрав "Исследовать элемент". Требования к работе находятся в структурах, как показано ниже:

<h2>
    <a>
        <href> ссылка </href>
    <a/>
<h2/>
def get_jobslinks(start, url):
    browser = mechanicalsoup.StatefulBrowser()
    try:
        browser.open(url)
    except:
        exit("не удалось открыть {}".format(url))

    job_info = browser.get_current_page().find_all("h2")
    jobs = []
    for elem in job_info:
        links = elem.find_all("a")
        for item in links:
            job = item.get("href")
            job = job.replace("/jobs", "")
            jobs.append(start + job)

    browser.close()
    return jobs

Функция get_jobmeta извлекает информацию о конкретной вакансии. Информация доступна в элементе div с классом mb8. Мы можем использовать тот же принцип и исследовать элемент в браузере. Из этих элементов извлекается текст и отправляется боту Slack в следующей функции.

def get_jobmeta(job_lists):
    browser = mechanicalsoup.StatefulBrowser()
    job_req = ""

    time = datetime.now().strftime("%A, %d. %B %Y %I:%M%p")
    job_req = job_req+"Отчет о вакансиях сгенерирован в: " + time + "\n\n"

    for job in job_lists:
        print(job)
        job_req = job_req + job
        try:
            browser.open(job)
        except:
            exit("не удалось открыть {}". format(job))

        job_info = browser.get_current_page().find_all("div", class_="mb8")
        # job_tech = browser.get_current_page().find_all("div", class_="mb16")

        for i in range(1, len(job_info)):
            job_req = job_req + job_info[i].text

        job_req += "#"*50 + " СЛЕДУЮЩАЯ ВАКАНСИЯ " + "#"*50 + "\n"

    browser.close()
    return job_req

Пример требований к работе

def send_jobinfo(job):
    try:
        response = client.chat_postMessage(
            channel="job_search",
            text=job,
            user="bot_job"
        )
    except SlackApiError as e:
        # Если "ok" равно False, возникнет ошибка SlackApiError
        assert e.response["error"]

Данная функция отправляет собранные данные о работе в канал Slack. Необходимо указать канал Slack, а также бота, который будет размещать описание работы в чате.

Основная функция, хотя и необязательна, помогает вызывать функции во время выполнения программы или при ее запуске.

if __name__ == "__main__":
    time_cli = datetime.now().strftime("%A, %d. %B %Y %I:%M%p")
    print("Отчет о работе сгенерирован в: {}".format(time_cli))
    # определить поиск работы
    q = jobsearch_options()

    # общий URL
    base_url = "https://stackoverflow.com/jobs"
    start_url = base_url + q

    job_links = get_jobslinks(base_url, start_url)
    jobs_specs = get_jobmeta(job_links)
    send_jobinfo(jobs_specs)

Ссылки:


Управление окружениями - документация conda 4.8.5.post112+56bf24b2

С помощью conda вы можете создавать, экспортировать, перечислять, удалять и обновлять окружения, в которых могут быть разные версии Python и/или...

docs.conda.io

pip - Установщик пакетов Python - документация pip 20.2.3

pip - это установщик пакетов для Python. Вы можете использовать pip для установки пакетов из индекса пакетов Python и других...

pip.pypa.io

Руководство по использованию argparse - документация Python 3.9.0

Это руководство предназначено для того, чтобы быть простым введением в argparse, рекомендуемый модуль для разбора командной строки в Python...

docs.python.org

Примеры использования argparse в Python

Создание гибких скриптов с аргументами командной строки

medium.com

MechanicalSoup/MechanicalSoup

Библиотека на языке Python для автоматизации взаимодействия с веб-сайтами. - MechanicalSoup/MechanicalSoup

github.com

Какой способ наиболее питоничен для проверки, что несколько переменных не равны None?

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

stackoverflow.com

Обзор Docker

Docker - это открытая платформа для разработки, доставки и запуска приложений. Docker позволяет разделить...

docs.docker.com

Опубликовано на https://mpruna.github.io.