Como extrair anúncios de emprego do Indeed usando Python

Comentários: 0

Para caçadores de empregos, empregadores ou qualquer pessoa que esteja monitorando as tendências do mercado de trabalho, raspar a lista de empregos disponíveis do Indeed pode fornecer informações úteis. Neste tutorial em particular, combinaremos o Playwright para raspagem da Web e o lxml para análise de conteúdo HTML, a fim de coletar os detalhes do trabalho, incluindo o título, o nome da empresa de recrutamento, o local, a descrição do trabalho, o link de publicação do trabalho e, finalmente, apresentar as descobertas salvando as informações em um arquivo CSV.

Pré-requisitos

Para realizar o scraping com sucesso, as seguintes bibliotecas Python precisam ser instaladas.

Playwright para automação do navegador:


pip install playwright

lxml para análise de HTML:


pip install lxml

pandas para guardar dados num ficheiro CSV:


pip install pandas

Instalar os navegadores do Playwright:

Depois de instalar o Playwright, execute este comando para instalar os binários do navegador necessários:


playwright install

Passo 1: Configurando o Playwright para raspagem da web

O Playwright permite automatizar e interagir com navegadores da Web. Começamos configurando o Playwright para iniciar um navegador Chromium, visitar uma página da Web e extrair seu conteúdo. Aqui também podemos passar proxies através do playwright.

Por que usar proxies?

Os sites geralmente têm medidas de limitação de taxa ou anti-raspagem em vigor para bloquear solicitações repetidas do mesmo endereço IP. Os proxies permitem-lhe:

  • Evitar o bloqueio de IP: distribuir seus pedidos através de diferentes IPs para evitar a deteção.
  • Passagem de geolocalização: acesse listas de empregos que podem ser restritas com base em localizações geográficas.
  • Anonimato: oculte seu IP real e permaneça anônimo durante o processo de raspagem.

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': ''
            }
        )  # Navegador de cabeça
        page = await browser.new_page()
        await page.goto(url)
        
        # Extrair o conteúdo da página
        content = await page.content()
        
        await browser.close()  # Fechar o navegador quando terminar
        return content

Neste código, async_playwright inicia um browser com cabeçalho, navega para o URL especificado e vai buscar o conteúdo da página.

Compactando conteúdo HTML usando lxml

Em seguida, analisaremos o conteúdo da página para extrair dados significativos. O lxml é usado para essa finalidade porque fornece suporte robusto para analisar e consultar o conteúdo HTML usando XPath.


from lxml import html

def parse_job_listings(content):
    # Analisar conteúdo HTML
    parser = html.fromstring(content)
    
    # Extrair cada anúncio de emprego utilizando XPath
    job_posting = parser.xpath('//ul[@class="css-zu9cdh eu4oa1w0"]/li')
    
    jobs_data = []
    for element in job_posting[:-1]:  # Saltar o último elemento se for um anúncio ou irrelevante
        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()'))

            # Anexar os dados extraídos à lista jobs_data
            jobs_data.append({
                'Title': title,
                'Link': f"https://www.indeed.com{link}",
                'Location': location,
                'Description': description,
                'Company': company_name
            })
    
    return jobs_data

Passo 2: Raspagem de anúncios de emprego

Agora que temos as etapas de automação do navegador e de análise configuradas, vamos combiná-las para extrair as listas de vagas da página do Indeed.

Explicação:

  • get_page_content(url): Vai buscar o conteúdo da página utilizando o Playwright.
  • parse_job_listings(content): Analisa o conteúdo utilizando lxml e extrai os dados do trabalho.
  • main(): Orquestra o processo de recolha de dados, obtendo-os e guardando-os num ficheiro CSV.

import pandas as pd

async def scrape_indeed_jobs(url):
    # Passo 1: Obter o conteúdo da página utilizando o Playwright
    content = await get_page_content(url)
    
    # Passo 2: Analisar o HTML e extrair os detalhes do trabalho
    jobs_data = parse_job_listings(content)
    
    return jobs_data

# URL para recolha de dados
url = 'https://www.indeed.com/q-usa-jobs.html'

# Extrair e guardar dados
async def main():
    # Extrair dados do trabalho a partir do URL especificado
    jobs = await scrape_indeed_jobs(url)
    
    # Passo 3: Guardar dados em CSV utilizando pandas
    df = pd.DataFrame(jobs)
    df.to_csv('indeed_jobs.csv', index=False)
    
    print("Data saved to indeed_jobs.csv")

# Executar a função principal
asyncio.run(main())

Passo 3: Adicionando suporte à paginação

O Indeed pagina suas listagens de empregos, e você pode facilmente estender o scraper para lidar com várias páginas. A URL da página é ajustada usando um parâmetro de consulta start, que aumenta em 10 para cada nova página.

Para melhorar a funcionalidade do seu raspador para coletar dados de várias páginas, você pode implementar uma função chamada scrape_multiple_pages. Essa função modificará o URL de base ajustando gradualmente o parâmetro de início, permitindo o acesso às páginas subsequentes. Ao progredir sistematicamente através de cada página, pode expandir o âmbito e a quantidade de dados recolhidos, tais como vagas, garantindo um conjunto de dados mais abrangente.


async def scrape_multiple_pages(base_url, pages=3):
    all_jobs = []
    
    for page_num in range(pages):
        # Atualizar URL para paginação
        url = f"{base_url}&start={page_num * 10}"
        print(f"Scraping page: {url}")
        
        # Extrair dados de trabalho de cada página
        jobs = await scrape_indeed_jobs(url)
        all_jobs.extend(jobs)
    
    # Guardar todos os trabalhos em 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")

# Extrair várias páginas de anúncios de emprego
asyncio.run(scrape_multiple_pages('https://www.indeed.com/jobs?q=usa', pages=3))

Passo 4: Personalizando as consultas de busca de emprego

Para segmentar cargos ou palavras-chave específicas nos seus esforços de coleta de dados, é necessário configurar o parâmetro de pesquisa de consulta no URL usado pelo Indeed. Essa personalização permite que o scraper colete dados específicos de determinados empregos ou setores. Por exemplo, se você estiver procurando por vagas de desenvolvedor Python em http://www.indeed.com, você ajustaria o parâmetro de consulta para incluir "Python+developer" ou palavras-chave relevantes.


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

Ao modificar este parâmetro de acordo com as suas necessidades de recolha de dados, pode concentrar a sua recolha de dados em empregos específicos, aumentando a flexibilidade e a eficiência do seu processo de recolha de dados. Esta abordagem é especialmente útil para se adaptar às exigências dinâmicas do mercado de trabalho.

Código completo


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

# Passo 1: Obter o conteúdo da página utilizando o Playwright
async def get_page_content(url):
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=False
            proxy = {
                'server': '',
                'username': '',
                'password': ''
            }
        )  # Executar o browser em modo de cabeça
        page = await browser.new_page()
        await page.goto(url, wait_until='networkidle')
        
        # Extrair o conteúdo da página
        content = await page.content()
        await browser.close()  # Fechar o browser após a utilização
        return content

# Passo 2: Analisar o conteúdo HTML utilizando lxml
def parse_job_listings(content):
    # Analisar o HTML usando lxml
    parser = html.fromstring(content)
    
    # Selecionar anúncios de emprego individuais utilizando XPath
    job_posting = parser.xpath('//ul[@class="css-zu9cdh eu4oa1w0"]/li')
    
    # Extract job data
    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()'))

            # Anexar os dados extraídos à lista jobs_data
            jobs_data.append({
                'Title': title,
                'Link': f"https://www.indeed.com{link}",
                'Location': location,
                'Description': description,
                'Company': company_name
            })
    
    return jobs_data

# Passo 3: Extrair as ofertas de emprego do Indeed para uma única página
async def scrape_indeed_jobs(url):
    # Obter o conteúdo da página utilizando o Playwright
    content = await get_page_content(url)
    
    # Analisar HTML e extrair dados de trabalho
    jobs_data = parse_job_listings(content)
    
    return jobs_data

# Passo 4: Tratar a paginação e recolher várias páginas
async def scrape_multiple_pages(base_url, query, pages=3):
    all_jobs = []
    
    for page_num in range(pages):
        # Atualizar o URL para tratar a paginação e adicionar a consulta de pesquisa
        url = f"{base_url}?q={query}&start={page_num * 10}"
        print(f"Scraping page: {url}")
        
        # Trabalhos de recolha de dados para a página atual
        jobs = await scrape_indeed_jobs(url)
        all_jobs.extend(jobs)
    
    # Guardar todos os trabalhos num ficheiro 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")

# Função para executar o raspador com entrada de consulta dinâmica
async def run_scraper():
    # Etapa 5: Pedir ao utilizador que introduza a consulta e o número de páginas a extrair
    query = input("Enter the job title or keywords to search (e.g., python+developer): ")
    pages = int(input("Enter the number of pages to scrape: "))
    
    # Extrair trabalhos em várias páginas com base na consulta
    base_url = 'https://www.indeed.com/jobs'
    await scrape_multiple_pages(base_url, query, pages)

# Utilizar o raspador
asyncio.run(run_scraper())

Para garantir um processo de recolha de dados sem problemas e reduzir o risco de bloqueios e aparições de CAPTCHA, é crucial escolher o servidor proxy correto. A melhor opção para a recolha de dados são os proxies ISP, que proporcionam alta velocidade e estabilidade de ligação, bem como um elevado fator de confiança, o que faz com que raramente sejam bloqueados pelas plataformas. Este tipo de proxy é estático, pelo que, para a recolha de dados em grande escala, é necessário criar um conjunto de proxies ISP e configurar a rotação de IP para a sua mudança regular. Uma opção alternativa seriam os proxies residenciais, que são dinâmicos e têm a cobertura geográfica mais alargada em comparação com outros tipos de servidores proxy.

Comentários:

0 Comentários