Jak zeskrobać oferty pracy Indeed za pomocą Pythona

Komentarze: 0

Dla osób poszukujących pracy, pracodawców lub innych osób monitorujących trendy na rynku pracy, skrobanie listy dostępnych ofert pracy Indeed może dostarczyć pomocnych informacji. W tym konkretnym samouczku połączymy Playwright do skrobania stron internetowych i lxml do analizowania treści HTML w celu zebrania szczegółów oferty pracy, w tym jej tytułu, nazwy firmy rekrutującej, lokalizacji, opisu stanowiska, linku do oferty pracy, a na koniec przedstawimy wyniki, zapisując informacje w pliku CSV.

Wymagania wstępne

Aby pomyślnie wykonać scraping, należy zainstalować następujące biblioteki Python.

Playwright do automatyzacji przeglądarki:


pip install playwright

lxml do parsowania HTML:


pip install lxml

pandas do zapisywania danych do pliku CSV:


pip install pandas

Zainstaluj przeglądarki Playwright:

Po zainstalowaniu Playwright, uruchom to polecenie, aby zainstalować niezbędne pliki binarne przeglądarki:


playwright install

Krok 1: Konfiguracja Playwright do skrobania stron internetowych

Playwright umożliwia automatyzację i interakcję z przeglądarkami internetowymi. Zaczynamy od skonfigurowania Playwright, aby uruchomić przeglądarkę Chromium, odwiedzić stronę internetową i wyodrębnić jej zawartość. Tutaj możemy również przekazywać proxy przez Playwright.

Dlaczego warto korzystać z serwerów proxy?

Strony internetowe często stosują środki ograniczające szybkość lub zapobiegające skrobaniu, aby zablokować powtarzające się żądania z tego samego adresu IP. Serwery proxy pozwalają na:

  • Unikaj blokowania adresów IP: rozdzielaj żądania przez różne adresy IP, aby uniknąć wykrycia.
  • Omijanie geolokalizacji: dostęp do ofert pracy, które mogą być ograniczone na podstawie lokalizacji geograficznych.
  • Anonimowość: ukryj swoje rzeczywiste IP i pozostań anonimowy podczas procesu scrapingu.

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': ''
            }
        )  # Przeglądarka z nagłówkiem
        page = await browser.new_page()
        await page.goto(url)
        
        # Wyodrębnij zawartość strony
        content = await page.content()
        
        await browser.close()  # Po zakończeniu zamknij przeglądarkę
        return content

W tym kodzie async_playwright uruchamia przeglądarkę z nagłówkiem, nawiguje do określonego adresu URL i pobiera zawartość strony.

Parsowanie zawartości HTML przy użyciu lxml

Następnie przeanalizujemy zawartość strony, aby wyodrębnić znaczące dane. lxml jest używany do tego celu, ponieważ zapewnia solidne wsparcie dla analizowania i odpytywania treści HTML za pomocą XPath.


from lxml import html

def parse_job_listings(content):
    # Analizowanie zawartości HTML
    parser = html.fromstring(content)
    
    # Wyodrębnij każdą ofertę pracy za pomocą XPath
    job_posting = parser.xpath('//ul[@class="css-zu9cdh eu4oa1w0"]/li')
    
    jobs_data = []
    for element in job_posting[:-1]:  # Pomiń ostatni element, jeśli jest to reklama lub nie ma znaczenia.
        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()'))

            # Dodanie wyodrębnionych danych do listy jobs_data
            jobs_data.append({
                'Title': title,
                'Link': f"https://www.indeed.com{link}",
                'Location': location,
                'Description': description,
                'Company': company_name
            })
    
    return jobs_data

Krok 2: Skrobanie ofert pracy

Teraz, gdy mamy już skonfigurowane zarówno kroki automatyzacji przeglądarki, jak i parsowania, połączmy je, aby zeskrobać oferty pracy ze strony Indeed.

Wyjaśnienie:

  • get_page_content(url): Pobiera zawartość strony za pomocą Playwright.
  • parse_job_listings(content): Parsuje zawartość przy użyciu lxml i wyodrębnia dane zadania.
  • main(): Orkiestruje proces scrapingu, pobierając dane i zapisując je w pliku CSV.

import pandas as pd

async def scrape_indeed_jobs(url):
    # Krok 1: Pobierz zawartość strony za pomocą Playwright
    content = await get_page_content(url)
    
    # Krok 2: Analiza kodu HTML i wyodrębnienie szczegółów zadania
    jobs_data = parse_job_listings(content)
    
    return jobs_data

# Adres URL do zeskrobania
url = 'https://www.indeed.com/q-usa-jobs.html'

# Skrobanie i zapisywanie danych
async def main():
    # Skrobanie danych zadania z określonego adresu URL
    jobs = await scrape_indeed_jobs(url)
    
    # Krok 3: Zapisywanie danych do CSV przy użyciu pandas
    df = pd.DataFrame(jobs)
    df.to_csv('indeed_jobs.csv', index=False)
    
    print("Data saved to indeed_jobs.csv")

# Uruchom główną funkcję
asyncio.run(main())

Krok 3: Dodanie obsługi paginacji

Indeed paginuje swoje oferty pracy i można łatwo rozszerzyć scraper, aby obsługiwał wiele stron. Adres URL strony jest dostosowywany za pomocą parametru zapytania start, który zwiększa się o 10 dla każdej nowej strony.

Aby rozszerzyć funkcjonalność scrapera do zbierania danych z wielu stron, można zaimplementować funkcję o nazwie scrape_multiple_pages. Funkcja ta zmodyfikuje podstawowy adres URL poprzez stopniowe dostosowywanie parametru start, umożliwiając dostęp do kolejnych stron. Systematycznie przechodząc przez każdą stronę, można rozszerzyć zakres i ilość gromadzonych danych, takich jak oferty pracy, zapewniając bardziej kompleksowy zestaw danych.


async def scrape_multiple_pages(base_url, pages=3):
    all_jobs = []
    
    for page_num in range(pages):
        # Aktualizacja adresu URL dla paginacji
        url = f"{base_url}&start={page_num * 10}"
        print(f"Scraping page: {url}")
        
        # Skrobanie danych zadań z każdej strony
        jobs = await scrape_indeed_jobs(url)
        all_jobs.extend(jobs)
    
    # Zapisz wszystkie zadania do pliku 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")

# Skrobanie wielu stron z ofertami pracy
asyncio.run(scrape_multiple_pages('https://www.indeed.com/jobs?q=usa', pages=3))

Krok 4: Dostosowywanie zapytań o pracę

Aby ukierunkować swoje działania na określone stanowiska lub słowa kluczowe, należy skonfigurować parametr wyszukiwania zapytań w adresie URL używanym przez Indeed. To dostosowanie pozwala scraperowi zbierać dane specyficzne dla określonych stanowisk lub sektorów. Na przykład, jeśli szukasz stanowisk programisty Python na http://www.indeed.com, dostosuj parametr zapytania, aby zawierał "Python+developer" lub odpowiednie słowa kluczowe.


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

Modyfikując ten parametr zgodnie z potrzebami gromadzenia danych, można skupić się na skrobaniu konkretnych ofert pracy, zwiększając elastyczność i wydajność procesu gromadzenia danych. Takie podejście jest szczególnie przydatne w przypadku dostosowywania się do dynamicznych wymagań rynku pracy.

Kompletny kod


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

# Krok 1: Pobieranie zawartości strony za pomocą Playwright
async def get_page_content(url):
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=False
            proxy = {
                'server': '',
                'username': '',
                'password': ''
            }
        )  # Uruchom przeglądarkę w trybie nagłówkowym
        page = await browser.new_page()
        await page.goto(url, wait_until='networkidle')
        
        # Wyodrębnianie zawartości strony
        content = await page.content()
        await browser.close()  # Zamknij przeglądarkę po użyciu
        return content

# Krok 2: Parsowanie zawartości HTML przy użyciu lxml
def parse_job_listings(content):
    # Parsowanie HTML przy użyciu lxml
    parser = html.fromstring(content)
    
    # Wybieranie poszczególnych ofert pracy za pomocą XPath
    job_posting = parser.xpath('//ul[@class="css-zu9cdh eu4oa1w0"]/li')
    
    # Wyodrębnianie danych zadania
    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()'))

            # Dodanie wyodrębnionych danych do listy jobs_data
            jobs_data.append({
                'Title': title,
                'Link': f"https://www.indeed.com{link}",
                'Location': location,
                'Description': description,
                'Company': company_name
            })
    
    return jobs_data

# Krok 3: Skrobanie ofert pracy Indeed dla pojedynczej strony
async def scrape_indeed_jobs(url):
    # Pobierz zawartość strony za pomocą Playwright
    content = await get_page_content(url)
    
    # Analizowanie HTML i wyodrębnianie danych zadań
    jobs_data = parse_job_listings(content)
    
    return jobs_data

# Krok 4: Obsługa paginacji i skrobanie wielu stron
async def scrape_multiple_pages(base_url, query, pages=3):
    all_jobs = []
    
    for page_num in range(pages):
        # Zaktualizuj adres URL, aby obsługiwał paginację i dodaj zapytanie wyszukiwania
        url = f"{base_url}?q={query}&start={page_num * 10}"
        print(f"Scraping page: {url}")
        
        # Zadania scrape dla bieżącej strony
        jobs = await scrape_indeed_jobs(url)
        all_jobs.extend(jobs)
    
    # Zapisywanie wszystkich zadań w pliku 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")

# Funkcja uruchamiająca scrapera z dynamicznym zapytaniem wejściowym
async def run_scraper():
    # Krok 5: Poproś użytkownika o podanie zapytania wejściowego i liczby stron do zeskrobania
    query = input("Enter the job title or keywords to search (e.g., python+developer): ")
    pages = int(input("Enter the number of pages to scrape: "))
    
    # Skrobanie zadań na wielu stronach na podstawie zapytania
    base_url = 'https://www.indeed.com/jobs'
    await scrape_multiple_pages(base_url, query, pages)

# Uruchom skrobak
asyncio.run(run_scraper())

Aby zapewnić płynny proces scrapingu i zmniejszyć ryzyko blokad i pojawienia się CAPTCHA, kluczowy jest wybór odpowiedniego serwera proxy. Najbardziej optymalną opcją do scrapingu są serwery proxy ISP, które zapewniają wysoką prędkość i stabilność połączenia, a także wysoki współczynnik zaufania, dzięki czemu rzadko są blokowane przez platformy. Ten typ serwera proxy jest statyczny, więc w przypadku skrobania na dużą skalę konieczne jest utworzenie puli serwerów proxy ISP i skonfigurowanie rotacji adresów IP w celu ich regularnej zmiany. Alternatywną opcją są rezydencjalne serwery proxy, które są dynamiczne i mają najszerszy zasięg geograficzny w porównaniu do innych typów serwerów proxy.

Komentarze:

0 komentarze