Парсинг сайта вакансии на Python

Парсинг сайта вакансии на Python

Парсинг сайта вакансии на Python

Одно из самых популярных направлений использования языка Python является парсинг данных
с веб-сайтов
. Под парсингом понимают процесс разбора веб-страницы с целью извлечь
из нее данные и придать им некий структурированный вид.

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

Также учтите, что существуют рекомендации, которых стоит придерживаться, при использовании парсинга:

  • Извлекаемое содержимое не должно быть защищен авторским правом
  • Парсинг не должен замедлять или иным образом мешать работе сайта
  • Парсинг не должен нарушать условия использования сайта
  • Нельзя извлекать персональный данные пользователя
  • Проект создается в PyCharm Community.

    Итак, для получения и извлечения данных мы будем использовать следующие библиотеки, которые Вам нужно будет установить:

    Комманда установки


    $ pip install -r requirements.txt

    Файл requirements.txt


    beautifulsoup4==4.10.0
    certifi==2021.10.8
    charset-normalizer==2.0.12
    idna==3.3
    lxml==4.8.0
    pkg_resources==0.0.0
    requests==2.27.1
    soupsieve==2.3.1
    urllib3==1.26.8

    После того как зависимости установятся, перейдем непосредственно к коду:


    import json
    import time
    import requests
    from bs4 import BeautifulSoup

    # config

    URL = 'https://{ВАШ_САЙТ}/vacancies/middle_php_developer'

    # заголовки запроса
    headers = {
        'User-Agent': 'Firefox/99.0'
    }

    # возвращает содержимое страницы в виде текста
    def get_page_content(url):
        text = ''

        res = requests.get(url, headers=headers)

        if res.status_code != 404:
            return res.text

        return text

    # класс представляет одну вакансию
    # аттрибуты класса - части вакансии из разметки
    class Vacancy:
        url: str
        company: str
        companyAbout: str
        title: str
        salary: str
        requiredSkills: str
        locationAndTypeOfEmployment: str
        description: str

        # преобразование объекта данного класса в строку возвращает отформатированный json
        def __str__(self) -> str:
            return json.dumps(self.__dict__, ensure_ascii=False, indent=4)

    # извлечение вакансии из текстового содержимого страницы
    def parse_vacancy(url: str) -> Vacancy:
        vacancyObj = Vacancy()

        try:
            text = get_page_content(url)
            bs = BeautifulSoup(text, 'lxml')

            # интересующие нас данные извлекаем с помощью CSS селекторов - возможность библиотеки BeautifulSoup
            company = bs.select_one('.company_name')
            companyAbout = bs.select_one('.company_about')
            title = bs.select_one('.page-title__title')
            salary = bs.select_one(
                'body > div.page-container > div > div > div > div > article > section:nth-child(1) > div '
                '> div > div > div:nth-child(3)')
            description = bs.select_one('.job_show_description__vacancy_description')
            requiredSkills = bs.select_one('body > div.page-container > div > div > div > div > article > '
                                           'section:nth-child(1) > div > div > div > div:nth-child(4)')
            locationAndTypeOfEmployment = bs.select_one('body > div.page-container > div > div > div > div > article > '
                                                        'section:nth-child(1) > div > div > div > div:nth-child(5)')

            # собираем данные в объект
            vacancyObj.url = url
            vacancyObj.company = company.text
            vacancyObj.companyAbout = companyAbout.text if companyAbout is not None else ''
            vacancyObj.title = title.text
            vacancyObj.description = str(description.contents[0])
            vacancyObj.salary = salary.text.replace('Зарплата', '')
            vacancyObj.requiredSkills = requiredSkills.text.replace('Требуемые навыки', '')
            vacancyObj.locationAndTypeOfEmployment = locationAndTypeOfEmployment.text.replace('Местоположение и тип '
                                                                                              'занятости', '')
        # обработка ошибок
        except AttributeError as ae:
            print(url)
            print(ae)

        except requests.RequestException as e:
            print(e)

        return vacancyObj

    # извлечение всех ссылок на вакансии со страницы
    def get_all_page_links(text):
        bs = BeautifulSoup(text, 'lxml')
        links = bs.select('.vacancy-card__title-link')
        return [link.get('href') for link in links]

    # Циклично обходит все страницы собирая данные и записывает их в файл
    def process_page():
        vacancies = []
        out_file = open(f'parsed/parsed_vacancies.json', 'a')
        out_file.write('[')
        out_string = ''
        counter = 1

        for page in range(1, 7):

            try:
                url = URL + '?page=' + str(page)
                res = requests.get(url, headers=headers)

                if res.status_code != 404:
                    links = get_all_page_links(res.text)
                    # print(links)
                    # останавливаем запрос на 400 мс, чтобы не нагружать сайт
                    time.sleep(0.4)

                    for link in links:
                        vacancyUrl = f'https://{ВАШ_САЙТ}{link}'
                        vacancy = parse_vacancy(vacancyUrl)
                        vacancyStr = str(vacancy)

                        out_string += vacancyStr
                        out_string += ',n'

                        print(f'{counter}: {vacancyUrl}')
                        counter += 1
                        # vacancies.append(str(vacancy))

                        # останавливаем запрос на 500 мс
                        time.sleep(0.5)
                        # print(vacancyUrl)

            except requests.RequestException as e:
                print(e)
                continue

        # print(vacancies)

        out_file.write(out_string)
        out_file.write(']')
        out_file.close()

    # запускает скрипт
    if __name__ == '__main__':
        process_page()

    Таким образом, после окончания работы данного скрипта в папке parsed Вы должны увидеть файл parsed_vacancies.json
    со структурированными данными о вакансиях.

    Источник