Витяг даних про вакансії з Indeed з використанням Python

Коментарі: 0

Для тих, хто досліджує тенденції на ринку праці або збирає інформацію для найму, скрапінг вакансій на Indeed є важливим інструментом. У цьому посібнику описується, як використовувати Playwright для веб-скрапінгу та lxml для парсингу HTML, щоб витягувати дані про вакансії, як-от назва посади, ім'я роботодавця, місцезнаходження, опис посади та посилання на вакансії. Завершальним етапом є збереження зібраної інформації у форматі CSV.

Налаштування середовища для парсингу

Для успішного виконання скрапінгу потрібне встановлення таких бібліотек Python:

Playwright: необхідний для автоматизації браузера. Встановіть, використовуючи команду:


pip install playwright

lxml: використовується для парсингу HTML. Встановіть, використовуючи команду:


pip install lxml

pandas: полегшує збереження даних у форматі CSV. Встановіть, використовуючи команду:


pip install pandas

Встановлення браузерів через Playwright:

Після встановлення Playwright, запустіть таку команду для встановлення необхідних бінарних файлів браузера:


playwright install

Крок 1: Налаштування Playwright для веб-скрапінгу

Для початку налаштуємо Playwright на запуск браузера Chromium, перехід на цільову веб-сторінку і витяг її вмісту. Важливим елементом цього налаштування є використання проксі.

Чому варто використовувати проксі?

Використання проксі має низку переваг, включно з:

  • Уникнення блокування IP: розподіл запитів через різні IP-адреси допомагає уникнути виявлення та блокування.
  • Обхід географічних обмежень: доступ до вмісту, який може бути обмежений у певних регіонах.
  • Забезпечення анонімності: приховування вашої реальної IP-адреси та забезпечення анонімності під час скрапінгу.

import asyncio
from playwright.async_api import async_playwright

async def get_page_content(url):
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=False,
            proxy = {
                'server': '',
                'username': '<логін>',
                'password': '<пароль>'
            }
        )  # Запуск браузера з відображенням інтерфейсу
        page = await browser.new_page()
        await page.goto(url)
        
        # Витяг вмісту сторінки
        content = await page.content()
        
        await browser.close()  # Закриття браузера після завершення
        return content

У цьому прикладі async_playwright ініціює запуск браузера з призначеним для користувача інтерфейсом, здійснює перехід за вказаним URL і витягує HTML-вміст сторінки.

Парсинг HTML-вмісту з використанням lxml

Після отримання HTML-вмісту сторінки слідує його детальний аналіз для вилучення необхідних даних. У цьому процесі ключову роль відіграє бібліотека lxml, яка надає потужні інструменти для аналізу HTML. Lxml підтримує використання XPath, що дає змогу точно й ефективно локалізувати та витягувати елементи даних зі складних веб-сторінок.


from lxml import html

def parse_job_listings(content):
    # Парсинг HTML-вмісту
    parser = html.fromstring(content)
    
    # Витяг кожної вакансії з використанням XPath
    job_posting = parser.xpath('//ul[@class="css-zu9cdh eu4oa1w0"]/li')
    
    jobs_data = []
    for element in job_posting[:-1]:  # Виключення останнього елемента, якщо це реклама або не належить до цільової інформації для скрапінгу
        title = ''.join(element.xpath('.//h2/a/span/@title'))
        if title:
            link = ''.join(element.xpath('.//h2/a/@href'))
            location = ''.join(element.xpath('.//div[@data-testid="text-location"]/text()'))
            description = ', '.join(element.xpath('.//div[@class="css-9446fg eu4oa1w0"]/ul//li/text()'))
            company_name = ''.join(element.xpath('.//span[@data-testid="company-name"]/text()'))

            # Додавання витягнутих даних у список jobs_data
            jobs_data.append({
                'Title': title,
                'Link': f"https://www.indeed.com{link}",
                'Location': location,
                'Description': description,
                'Company': company_name
            })
    
    return jobs_data

Крок 2: Скрапінг вакансій

Після того як автоматизація браузера і парсинг були успішно налаштовані, переходимо до основного завдання - скрапінгу списку вакансій з Indeed.

Опис:

  • get_page_content(url): Отримує вміст сторінки за допомогою Playwright.
  • parse_job_listings(content): Аналізує вміст за допомогою lxml і витягує дані про вакансії.
  • main(): Організовує процес скрапінгу, отримуючи дані та зберігаючи їх у файл CSV.

import pandas as pd

async def scrape_indeed_jobs(url):
    # Крок 1: Отримання вмісту сторінки за допомогою Playwright
    content = await get_page_content(url)
    
    # Крок 2: Аналіз HTML і вилучення інформації про вакансії
    jobs_data = parse_job_listings(content)
    
    return jobs_data

# URL для скрапінгу
url = 'https ссылка'

# Скрапінг і збереження даних
async def main():
    # Скрапінг даних про вакансії із зазначеного URL
    jobs = await scrape_indeed_jobs(url)
    
    # Крок 3: Збереження даних у CSV за допомогою pandas
    df = pd.DataFrame(jobs)
    df.to_csv('indeed_jobs.csv', index=False)
    
    print("Data saved to indeed_jobs.csv")

# Запуск головної функції
asyncio.run(main())

Крок 3: Обробка пагінації

Сайт Indeed використовує пагінацію для розбиття списку вакансій на безліч сторінок. Це зручно, оскільки дає змогу розподілити інформацію та знизити навантаження на сервери, але вимагає додаткової логіки в скрапері для переходу сторінками. Кожна нова сторінка в списку вакансій доступна через зміну параметра start в URL, який збільшується на 10 з кожною новою сторінкою.

Щоб адаптувати скрапер до цього механізму, можна створити функцію scrape_multiple_pages, яка модифікуватиме базовий URL, збільшуючи параметр start для доступу до кожної наступної сторінки. Цей підхід дає змогу систематично збирати дані з усіх сторінок, збільшуючи охоплення і кількість зібраних вакансій.


async def scrape_multiple_pages(base_url, pages=3):
    all_jobs = []
    
    for page_num in range(pages):
        # Оновлення URL для пагінації
        url = f"{base_url}&start={page_num * 10}"
        print(f"Scraping page: {url}")
        
        # Скрапінг даних про вакансії з кожної сторінки
        jobs = await scrape_indeed_jobs(url)
        all_jobs.extend(jobs)
    
    # Збереження всіх вакансій у CSV
    df = pd.DataFrame(all_jobs)
    df.to_csv('indeed_jobs_all_pages.csv', index=False)
    print("Data saved to indeed_jobs_all_pages.csv")

# Скрапінг декількох сторінок списку вакансій
asyncio.run(scrape_multiple_pages('https ссылка', pages=3))

Крок 4: Конфігурація пошукових запитів для вакансій

Для того щоб скрапити інформацію за конкретними посадами або ключовими словами, необхідно налаштувати параметр пошуку query в URL сайту Indeed. Це дає змогу цілеспрямовано витягувати дані за професіями або секторами, що цікавлять. Наприклад, для пошуку вакансій Python-розробника на сайті www.indeed.com.


query = "python+developer"
base_url = f"https://www.indeed.com/jobs?q={query}"
asyncio.run(scrape_multiple_pages(base_url, pages=3))

Змінюючи значення параметра query на бажані назви посад або ключові слова, можна адаптувати скрапер до різних завдань зі збору даних. Це дає гнучкість у виборі цільових вакансій і дозволяє ефективно збирати інформацію з Indeed, адаптуючись до мінливих вимог ринку праці.

Фінальна версія коду


import asyncio
from playwright.async_api import async_playwright
from lxml import html
import pandas as pd

# Крок 1: Отримання вмісту сторінки за допомогою Playwright
async def get_page_content(url):
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=False
            proxy = {
                'server': '',
                'username': '<логін>',
                'password': '<пароль>'
            }
        )  # Запуск браузера з інтерфейсом
        page = await browser.new_page()
        await page.goto(url, wait_until='networkidle')
        
        # Витяг вмісту сторінки
        content = await page.content()
        await browser.close()  # Закриття браузера після використання
        return content

# Крок 2: Розбір HTML-вмісту за допомогою lxml
def parse_job_listings(content):
    # Розбір HTML за допомогою lxml
    parser = html.fromstring(content)
    
    # Вибір окремих оголошень про роботу за допомогою XPath
    job_posting = parser.xpath('//ul[@class="css-zu9cdh eu4oa1w0"]/li')
    
    # Витяг даних про роботу
    jobs_data = []
    for element in job_posting[:-1]:
        title = ''.join(element.xpath('.//h2/a/span/@title'))
        if title:
            link = ''.join(element.xpath('.//h2/a/@href'))
            location = ''.join(element.xpath('.//div[@data-testid="text-location"]/text()'))
            description = ', '.join(element.xpath('.//div[@class="css-9446fg eu4oa1w0"]/ul//li/text()'))
            company_name = ''.join(element.xpath('.//span[@data-testid="company-name"]/text()'))

            # Додавання витягнутих даних у список jobs_data
            jobs_data.append({
                'Title': title,
                'Link': f"https://www.indeed.com{link}",
                'Location': location,
                'Description': description,
                'Company': company_name
            })
    
    return jobs_data

# Крок 3: Скрапінг вакансій Indeed для однієї сторінки
async def scrape_indeed_jobs(url):
    # Отримання вмісту сторінки за допомогою Playwright
    content = await get_page_content(url)
    
    # Розбір HTML і витяг даних про роботу
    jobs_data = parse_job_listings(content)
    
    return jobs_data

# Крок 4: Керування пагінацією і скрапінг безлічі сторінок
async def scrape_multiple_pages(base_url, query, pages=3):
    all_jobs = []
    
    for page_num in range(pages):
        # Оновлення URL для управління пагінацією та додавання пошукового запиту
        url = f"{base_url}?q={query}&start={page_num * 10}"
        print(f"Scraping page: {url}")
        
        # Скрапінг вакансій для поточної сторінки
        jobs = await scrape_indeed_jobs(url)
        all_jobs.extend(jobs)
    
    # Збереження всіх вакансій у CSV-файл
    df = pd.DataFrame(all_jobs)
    df.to_csv(f'indeed_jobs_{query}.csv', index=False)
    print(f"Data saved to indeed_jobs_{query}.csv")

#  Функція для запуску скрапера з динамічним введенням запиту користувача
async def run_scraper():
    # Крок 5: Запит у користувача введення пошукового запиту і кількості сторінок для скрапінгу
    query = input("Введіть назву посади або ключові слова для пошуку (наприклад, python+developer): ")
    pages = int(input("Введіть кількість сторінок для скрапінгу: "))
    
    # Скрапінг вакансій на кількох сторінках відповідно до запиту
    base_url = 'https://www.indeed.com/jobs'
    await scrape_multiple_pages(base_url, query, pages)

# Запуск скрапера
asyncio.run(run_scraper())

Щоб забезпечити безперебійний процес скрапінгу та зменшити ризик блокувань і появи капчі, необхідно вибрати правильний проксі-сервер. Найоптимальнішим варіантом для скрапінгу є ISP проксі, які забезпечують високу швидкість і стабільність з'єднання, а також мають високий траст-фактор, завдяки чому рідко блокуються платформами. Цей тип проксі є статичним, тому для масштабного скрапінгу необхідно сформувати пул ISP проксі та налаштувати ротацію IP-адрес для їхньої регулярної зміни. Альтернативним варіантом стануть резидентські проксі, які є динамічними та мають найбільше географічне покриття порівняно з іншими типами проксі-серверів.

Коментарії:

0 Коментаріїв