[Python Оригинал] Создал демо веб-скрейпера для сайта вакансий

[Python Оригинал] Создал демо веб-скрейпера для сайта вакансий


Цель заключается в сборе вакансий с hh.ru (русская платформа поиска работы), а также сопутствующей информации по предотвращению мошенничества, сбору резюме и других материалов.



Основные Проблемы и Решения



Меры Против Скрапинга

hh.ru внедряет различные меры против скрапинга, чтобы ограничить боты или скрапинг. Некоторые из них включают:

  • Ограничение Запросов: hh.ru накладывает временные ограничения на частоту запросов. После нескольких быстрых запросов может быть наложено ограничение. Это может привести к задержкам между запросами, обычно от нескольких минут до часа, или даже блокировке, если частота слишком высокая.

  • Ограничение на Пагинацию: Нет строгого лимита на количество страниц, которые можно скрапить. Однако, на практике, скрапинг нескольких страниц (например, 3-5) является типичным, чтобы избежать срабатывания мер защиты от скрапинга. Каждая страница обычно содержит до 30 вакансий, поэтому 3-5 страниц обычно достаточно для сбора приличного объема данных.

  • Куки и Заголовки: Если вы вставляете куки для вашей сессии, убедитесь, что не нажимаете “Enter” после вставки. Удаление последней пары ключ-значение может помочь обойти проблемы, которые могут возникнуть из-за недействительных куки.




Пояснение Ключевых Моментов



API Вакансий

hh.ru предоставляет API, которое можно использовать для поиска вакансий по ключевым словам (например, “IT”, “Кибербезопасность” и т. д.) и местоположению. API не накладывает строгих ограничений на количество страниц, однако слишком быстрое скрапирование многих страниц может привести к блокировке или CAPTCHам.



API Вакансий:

https://api.hh.ru/vacancies
Enter fullscreen mode

Exit fullscreen mode

Анализ Ссылки на Вакансии:

https://hh.ru/search/vacancy?text=IT+%D1%82%D0%B5%D1%85%D0%BD%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D0%B8&area=1&experience=between_1_and_3&salary=100000&items_on_page=20
Enter fullscreen mode

Exit fullscreen mode

Анализ Параметров:

keywords = "разработчик, кибербезопасность, IT"
city_name = "Москва"  # Можно указать 'Москва' или 'Москва и МО'
Enter fullscreen mode

Exit fullscreen mode

Код Города:

city_code = get_citycode(city_name)
Enter fullscreen mode

Exit fullscreen mode

def get_citycode(city_name):
    response = requests.get('https://api.hh.ru/areas')
    city_data = response.json()

    # Ищем в каждом регионе города
    for region in city_data:
        # Если город найден в регионе, возвращаем его ID
        for area in region.get('areas', []):
            if area['name'] == city_name:
                return area['id']
    return None
Enter fullscreen mode

Exit fullscreen mode

Структура Конкатенации JSON API:

for region in city_data:
    for area in region.get('areas', []):
        if area['name'] == city_name:
            return area['id']
Enter fullscreen mode

Exit fullscreen mode

for region in city_data:
    for area in region.get('areas', []):
        if area['name'] == city_name:
            return area['id']
Enter fullscreen mode

Exit fullscreen mode

for job in job_listings:
    job_name = job['name']
    salary = job['salary']
    employer_name = job['employer']['name']
    area_name = job['area']['name']
    job_url = job['alternate_url']
Enter fullscreen mode

Exit fullscreen mode

Цикл и Извлечение:

job_listings = get_job_list(keywords, city_name)

# Выводим информацию о найденных вакансиях
if job_listings:
    for job in job_listings:  # This is the loop that iterates through job listings
        job_name = job['name']
        salary = job['salary']
        employer_name = job['employer']['name']
        area_name = job['area']['name']
        job_url = job['alternate_url']  # URL вакансии

        # Зарплата (если указана)
        salary_from = salary.get('from', 'Не указано') if salary else 'Не указано'
        salary_to = salary.get('to', 'Не указано') if salary else 'Не указано'
        salary_currency = salary.get('currency', 'Не указана') if salary else 'Не указана'

        # Другие дополнительные данные
        employment_type = job['employment']['name'] if 'employment' in job else 'Не указано'
        experience_required = job['experience']['name'] if 'experience' in job else 'Не указано'
        skills=", ".join(job['key_skills']) if 'key_skills' in job else 'Не указаны'

        # Выводим все найденные детали вакансии
        print(f"Вакансия: {job_name}")
        print(f"Зарплата: от {salary_from} до {salary_to} {salary_currency}")
        print(f"Компания: {employer_name}")
        print(f"Город: {area_name}")
        print(f"Тип занятости: {employment_type}")
        print(f"Требуемый опыт: {experience_required}")
        print(f"Навыки: {skills}")
        print(f"Ссылка на вакансию: {job_url}")
        print("-" * 40)
Enter fullscreen mode

Exit fullscreen mode

Включённый Исходный Код:
https://github.com/Excalibra/scripts/blob/main/d-python/hh.ru_demo.py

import os
import requests
import json
from openpyxl import Workbook
from datetime import datetime

# Your existing get_citycode and get_job_list functions should already be defined in your script.
# Make sure they are present in the script or imported from another module.

# For example, let's assume this is part of your script:
def get_citycode(city_name):
    response = requests.get('https://api.hh.ru/areas')
    city_data = response.json()

    # Ищем в каждом регионе города
    for region in city_data:
        # Если город найден в регионе, возвращаем его ID
        for area in region.get('areas', []):
            if area['name'] == city_name:
                return area['id']
    return None

def get_job_list(keywords, city_name):
    city_code = get_citycode(city_name)
    if city_code is None:
        print(f"Город '{city_name}' не найден.")
        return []

    url = "https://api.hh.ru/vacancies"
    params = {
        'text': keywords,  # Ключевые слова для поиска вакансий
        'area': city_code,  # ID города
        'page': 0,  # Стартовая страница
        'per_page': 10,  # Количество вакансий на странице
    }

    response = requests.get(url, params=params)
    data = response.json()

    return data['items']

# Your DataToExcel class remains the same.

class DataToExcel:
    @staticmethod
    def save_to_excel(workbook, hhru_json):
        # Load the hh.ru JSON data
        with open(hhru_json, 'r', encoding='utf-8') as f:
            hhru_json = json.load(f)

        worksheet = workbook.create_sheet(title="Job Listings")

        # Define the column titles
        titles = [
            'Job Title', 'Skills', 'Experience', 'Salary From', 'Salary To', 'Currency', 
            'Company', 'Employment Type', 'Experience Required', 'City', 'Job URL'
        ]

        # Write the titles in the first row
        for col, title in enumerate(titles, start=1):
            worksheet.cell(row=1, column=col, value=title)

        # Extract job listings from the JSON data
        job_data_list = hhru_json.get('items', [])
        row = 2  # Start from the second row for data

        for job in job_data_list:
            worksheet.cell(row=row, column=1, value=job.get('name', 'N/A'))
            worksheet.cell(row=row, column=2, value=", ".join(job.get('key_skills', [])))
            worksheet.cell(row=row, column=3, value=job.get('experience', {}).get('name', 'N/A'))

            # Handle salary data
            salary = job.get('salary', {})
            salary_from = salary.get('from', 'N/A') if salary else 'N/A'
            salary_to = salary.get('to', 'N/A') if salary else 'N/A'
            salary_currency = salary.get('currency', 'N/A') if salary else 'N/A'

            worksheet.cell(row=row, column=4, value=salary_from)
            worksheet.cell(row=row, column=5, value=salary_to)
            worksheet.cell(row=row, column=6, value=salary_currency)

            worksheet.cell(row=row, column=7, value=job.get('employer', {}).get('name', 'N/A'))
            worksheet.cell(row=row, column=8, value=job.get('employment', {}).get('name', 'N/A'))
            worksheet.cell(row=row, column=9, value=job.get('experience', {}).get('name', 'N/A'))
            worksheet.cell(row=row, column=10, value=job.get('area', {}).get('name', 'N/A'))
            worksheet.cell(row=row, column=11, value=job.get('alternate_url', 'N/A'))

            row += 1  # Move to the next row

        # Save the workbook to a file
        save_xlsx = os.path.join(
            os.path.expanduser("~"), "Desktop", f"hhru_jobs_{datetime.now().strftime('%Y-%m-%d')}.xlsx"
        )
        workbook.save(save_xlsx)
        print(f"Job listings have been saved to: {save_xlsx}")


# Example function that saves the job data and calls the Excel export function
def save_hhru_data_to_excel():
    # Ensure get_job_list is available here.
    job_listings = get_job_list("разработчик, кибербезопасность, IT", "Москва")

    # Save the job listings to a JSON file
    hhru_json_path = os.path.join(os.path.expanduser("~"), "Desktop", f"hhru_jobs_{datetime.now().strftime('%Y-%m-%d')}.json")
    with open(hhru_json_path, 'w', encoding='utf-8') as f:
        json.dump({"items": job_listings}, f, ensure_ascii=False, indent=4)

    # Create a new workbook and save the data to Excel
    workbook = Workbook()
    workbook.remove(workbook.active)  # Remove the default sheet
    DataToExcel.save_to_excel(workbook, hhru_json_path)


# Call the function to save the job listings to Excel
save_hhru_data_to_excel()
Enter fullscreen mode

Exit fullscreen mode



Source link
lol

By stp2y

Leave a Reply

Your email address will not be published. Required fields are marked *

No widgets found. Go to Widget page and add the widget in Offcanvas Sidebar Widget Area.