Neste tutorial, vamos aprender a criar um Service
que utiliza HttpClient
para capturar a contagem de seguidores de um perfil público do Instagram.
1. Criando a Interface
Primeiro, criamos a interface do Service
. Isso permite que o Service
seja adicionado ao container de injeção de dependência.
public interface IInstagramScraper
{
Task<string> GetFollowerCountAsync(string instagramHandle);
}
Essa interface define um método GetFollowerCountAsync
, que recebe o instagramHandle
(nome de usuário do Instagram) e retorna uma string
contendo a quantidade de seguidores.
2. Implementando o Service
Seguindo o padrão da arquitetura limpa, implementamos serviços externos na camada de infraestrutura. Primeiro, criamos a classe InstagramScraper
que implementa a interface IInstagramScraper
.
public class InstagramScraper : IInstagramScraper
{
private readonly HttpClient _httpClient;
public InstagramScraper(HttpClient httpClient)
{
_httpClient = httpClient;
ConfigureHttpClient();
}
}
Injeção de Dependência do HttpClient
A classe InstagramScraper
tem uma variável readonly
do tipo HttpClient
para gerenciar as requisições. Recebemos a instância do HttpClient
no construtor, facilitando a injeção de dependência.
3. Configurando o HttpClient
Configuramos o HttpClient
para enviar cabeçalhos específicos que ajudam a imitar um navegador, garantindo que o Instagram não bloqueie a requisição.
private void ConfigureHttpClient()
{
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3");
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/html"));
_httpClient.DefaultRequestHeaders.AcceptLanguage.ParseAdd("en-US,en;q=0.5");
}
Essa configuração adiciona cabeçalhos User-Agent
, Accept
e Accept-Language
, simulando um navegador comum para evitar bloqueios do site.
4. Implementando o Método de Scraping
Agora, implementamos o método GetFollowerCountAsync
na classe InstagramScraper
. Esse método é responsável por acessar a página do perfil, buscar o HTML e extrair a contagem de seguidores.
Passo 1: Construindo a URL do Perfil do Instagram
public async Task<string> GetFollowerCountAsync(string instagramHandle)
{
var url = $"https://www.instagram.com/{instagramHandle}/";
Usamos interpolação de strings para construir a URL do perfil a partir do instagramHandle
fornecido.
Passo 2: Fazendo a Requisição HTTP
var response = await _httpClient.GetStringAsync(url);
Usando o HttpClient
, enviamos uma requisição HTTP para a página do perfil e aguardamos o HTML da resposta. Esse método é assíncrono (await
) para não bloquear a execução enquanto a resposta é carregada.
Passo 3: Verificando a Resposta
if (string.IsNullOrEmpty(response))
throw new Exception("The page response is empty or null.");
Caso a response
seja nula ou vazia, lançamos uma exceção indicando que a página não foi carregada corretamente. Isso ajuda a evitar erros ao tentar processar um HTML inexistente.
Passo 4: Capturando a Contagem de Seguidores com Expressão Regular
Para extrair a contagem de seguidores, usamos uma expressão regular que busca no HTML o valor esperado no meta tag og:description
.
var followersRegex = new Regex(@"<meta property=""og:description"" content=""(\d+(?:[,.]\d+)?[KM]?) Followers");
var match = followersRegex.Match(response);
A expressão regular captura um padrão específico, permitindo números formatados como 5K
, 10.5M
ou 1000
. O grupo de captura (\d+(?:[,.]\d+)?[KM]?)
lida com vírgulas, pontos e as letras K
e M
para representar milhares e milhões.
Passo 5: Verificando se a Contagem foi Encontrada
if (!match.Success)
throw new Exception("Unable to find the follower count.");
Se não houver correspondência (match.Success
é false
), lançamos uma exceção informando que a contagem de seguidores não foi encontrada. Esse tratamento de erro é importante, pois o HTML pode variar, e a estrutura da página do Instagram pode mudar.
Passo 6: Retornando a Contagem de Seguidores
return match.Groups[1].Value;
}
Finalmente, retornamos o valor do grupo de captura Groups[1].Value
, que contém a contagem de seguidores no formato capturado do HTML.
5. Adicionando o Service
ao Container de Dependência
Para tornar o Service
disponível por injeção de dependência, adicionamos a configuração ao container de serviços.
private static void AddScraper(IServiceCollection services)
=> services.AddHttpClient<IInstagramScraper, InstagramScraper>();
No método de configuração de serviços:
public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
{
AddScraper(services);
// Outros métodos...
return services;
}
6. Exemplo de Uso do Service
Aqui está um exemplo de como o Service
pode ser utilizado em uma Handler
para processar uma consulta que retorna informações sobre influenciadores:
public record GetInfluencersQuery : IRequest<IEnumerable<ResponseInfluencerProfileJson>>;
public class GetInfluencersQueryHandler(
IInfluencerReadOnlyRepository repository,
IInstagramScraper instagramScraper) : IRequestHandler<GetInfluencersQuery, IEnumerable<ResponseInfluencerProfileJson>>
{
public async Task<IEnumerable<ResponseInfluencerProfileJson>> Handle(GetInfluencersQuery request, CancellationToken cancellationToken)
{
var influencers = await repository.GetInfluencers();
var responseTasks = influencers.Select(async influencer =>
{
try
{
var instagram = await instagramScraper.GetFollowerCountAsync(influencer.Instagram);
return new ResponseInfluencerProfileJson(
influencer.Username.Value,
influencer.Instagram,
instagram);
}
catch (Exception ex)
{
return new ResponseInfluencerProfileJson(
influencer.Username.Value,
influencer.Instagram,
ex.Message);
}
});
var responses = await Task.WhenAll(responseTasks);
return responses;
}
}
Esse exemplo demonstra como o InstagramScraper
pode ser usado em um Handler
para obter informações de seguidores e compilar um perfil de resposta, com tratamento de exceção para eventuais falhas na captura de dados.