Essa é a história de um programador mediano que precisava automatizar a busca por freelas no terminal

Há um tempo atrás comecei a trabalhar com os famosos “freelas” e uma das plataformas que eu encontrei onde posso encontrar ofertas de projetos é a 99freelas. É uma plataforma simples e objetiva que junta o profissional com quem precisa.

Pra mim, o problema começou quando comecei a passar mais tempo no site da plataforma garimpando projetos ou iniciativas onde eu poderia atuar. As vezes o que a gente precisa é apenas a informação na hora. Seria legal se eu pudesse buscar projetos direto pelo terminal né? Já que eu estou sempre nele, uma ferramenta CLI que listasse os projetos viria a calhar. Decidi então dedicar algum tempo pra abordar esse problema.

A 99freelas não tem uma api pública (no momento em que este post está sendo escrito) então uma alternativa seria web scrapping: acessar a página, baixar o conteúdo, tratar as informações e organizá-las de uma forma otimizada e acessível, pra que eu pudesse ter a informação que seria relevante pra tomar a decisão se vou pegar o projeto ou não.

É uma tarefa relativamente simples e, analisando minhas opções, escolhi por fazer via shell scripting e um pouco de PHP. Isso vem da minha própria experiência como desenvolvedor mas existem milhares de opções pra fazer o scrapping.

A divisão de responsabilidades ficou: bash faz o fetch (é o que ele faz melhor), PHP faz o parsing do HTML (tem `preg_match_all`, `html_entity_decode` e as funções `mb_*` para UTF-8 nativamente).

As decisões de implementação

**Verificar dependências cedo.** O script checa `curl` e `php` no início com `command -v`. Parece óbvio, mas sem isso qualquer erro posterior vira uma mensagem genérica de “comando não encontrado” no meio da execução que ninguém vê.

**PHP como arquivo temporário, não pipe.** Embutir 100 linhas de PHP como string de argumento é ilegível e dificulta o debug. Com um arquivo em `$TMPDIR`, dá pra inspecionar o parser se algo der errado.

**`mktemp` com o padrão `XXXXXX`.** Esses seis X servem pra deixar o nome aleatório. Sem isso, dois processos simultâneos poderiam usar o mesmo nome de arquivo e pisariam um no output do outro.

**`trap` para limpeza.** Os arquivos temporários são removidos via `trap ‘rm -f …’ EXIT INT TERM`. O motivo de usar `trap` e não um `rm` no final do script: ele roda mesmo se o script for interrompido com Ctrl+C ou morrer por erro. Sem isso, cada execução deixa lixo em `/tmp`.

**Três validações do curl, em sequência.** O curl pode falhar de algumas formas diferentes: erro de rede (exit code diferente de 0), resposta de erro do servidor (código HTTP diferente 200), ou resposta vazia mesmo com HTTP 200. São casos distintos e cada um descarta a página por razões diferentes. Validar só o exit code deixaria passar respostas 404 com HTML válido então apliquei esse tratamento adicional.

**`–nome` aplicado depois da ordenação.** O filtro por título é aplicado *após* ordenar e *antes* de aplicar o limite. A ordem importa: se você pede os 10 com mais propostas que contêm “landing page”, o filtro precisa acontecer sobre o conjunto já ordenado, não antes.

**`–nome` sem palavra-chave.** O script aceita `./freelas.sh –nome “e-commerce”` sem um termo de busca principal. A URL vai com `q=` vazio, trazendo todos os projetos da categoria, e o filtro é aplicado no parsing. Útil quando você não sabe qual tecnologia vai estar no projeto mas sabe o tipo do serviço.

** Configuração das cores via ANSI direto, sem `tput`.** `tput` consulta o banco de dados de terminais e pode falhar ou dar output errado em ambientes não-interativos. Os códigos ANSI (`\033[0;36m`) funcionam em qualquer terminal que os suporte sem dependência externa.

## Resultado

“`bash

./freelas.sh wordpress 5 propostas

./freelas.sh nodejs 20 data:desc

./freelas.sh –nome “e-commerce”

./freelas.sh php –nome “landing page”

“`

Funciona em qualquer Linux com `curl` e `php`. Sem setup adicional.

https://github.com/Tromineo/scripts/blob/9e82f3459dfeb5398c2db96e104ead9051ec3a8e/freelas.sh

Por enquanto, esse script está me atendendo, mas ele não “nasceu” assim. Esse produto atual é o resultado de várias iterações e pequenas melhorias que eram descobertas conforme o uso da ferramenta no dia a dia. Algumas mudanças surgiram de incômodos reais e outras de uma vontade de tornar a aplicação mais robusta e objetiva. O resultado foi uma evolução gradual até chegar em algo que me atendesse minimamente naquele problema que eu tinha.

Leave a Reply

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