Sobre Nós


Bem-vindo ao site da Cooperchip!

Aqui você encontrará uma variedade de cursos de tecnologia.

Meu nome é Carlos Alberto dos Santos, Analista de Sistema, Arquiteto de Software e DBA SQL Server, com muitos anos de experiência. Também atuo como consultor e desenvolvedor Web. Espero que goste do que consumirá aqui. E, tendo qualquer dúvida ou sugestão, não hesite em entrar em contato.

Web Scraping com HtmlAgilityPack


Quer escovar bits de forma inteligente?


A biblioteca HtmlAgilityPack é uma biblioteca .NET (C#) que serve para manipular e extrair informações de documentos HTML. Ela fornece uma maneira fácil e eficiente de analisar, consultar e manipular a estrutura de documentos HTML, oferecendo uma série de recursos para lidar com diferentes cenários. Algumas das principais funcionalidades do HtmlAgilityPack incluem:

  • Análise de documentos HTML: A biblioteca pode analisar documentos HTML mesmo que estejam mal formatados, corrigindo automaticamente erros de marcação.
  • Seleção de elementos e atributos: Com a ajuda de consultas XPath, CSS ou LINQ, você pode selecionar facilmente elementos específicos ou atributos de um documento HTML.
  • Manipulação de elementos HTML: A biblioteca permite que você adicione, modifique ou remova elementos e atributos HTML em um documento.
  • Conversão de HTML para outros formatos: O HtmlAgilityPack pode ser usado para converter documentos HTML em outros formatos, como XML ou texto simples.
  • Web scraping: A biblioteca é frequentemente usada para web scraping, ou seja, extrair informações de páginas da web de maneira automatizada.
Em resumo, a biblioteca HtmlAgilityPack é uma ferramenta poderosa e flexível para trabalhar com documentos HTML, facilitando a extração e manipulação de informações em aplicações .NET. ### Observe o Código abaixo e depois vamos fazer um resumo do mesmo.
        

using Cooperchip.FeedRssBlogsAnalyticsApi.Models;
using HtmlAgilityPack;
using Microsoft.AspNetCore.Mvc;
using System.Globalization;
using System.Net.AspNetCore;
using System.Xml.Linq;

namespace Cooperchip.FeedRssBlogsAnalyticsApi.Controllers
{
[Route("[controller]")]
[ApiController]
public class AnalyticsController : ControllerBase
{
readonly CultureInfo culture = new("en-US");
private readonly MyDbContext _dbContext;
private readonly IConfiguration _configuration;
private static readonly object _lockObj = new();
public AnalyticsController(MyDbContext context, IConfiguration configuration)
{
_dbContext = context;
_configuration = configuration;
}

[HttpPost]
[Route("CreatePosts/{authorId}")]
public async Task CreatePosts(string authorId)
{
    try
    {
        XDocument doc = XDocument.Load("https://www.c-sharpcorner.com/members/" + authorId + "/rss");
        if (doc == null)
        {
            return false;
        }
        var entries = from item in doc.Root.Descendants().First(i => i.Name.LocalName == "channel").Elements().Where(i => i.Name.LocalName == "item")
                        select new Feed
                        {
                            Content = item.Elements().First(i => i.Name.LocalName == "description").Value,
                            Link = (item.Elements().First(i => i.Name.LocalName == "link").Value).StartsWith("/") ? "" + item.Elements().First(i => i.Name.LocalName == "link").Value : item.Elements().First(i => i.Name.LocalName == "link").Value,
                            PubDate = Convert.ToDateTime(item.Elements().First(i => i.Name.LocalName == "pubDate").Value, culture),
                            Title = item.Elements().First(i => i.Name.LocalName == "title").Value,
                            FeedType = (item.Elements().First(i => i.Name.LocalName == "link").Value).ToLowerInvariant().Contains("blog") ? "Blog" : (item.Elements().First(i => i.Name.LocalName == "link").Value).ToLowerInvariant().Contains("news") ? "News" : "Article",
                            Author = item.Elements().First(i => i.Name.LocalName == "author").Value
                    };

        List feeds = entries.OrderByDescending(o => o.PubDate).Where(d => d.PubDate.Year > 2018).ToList();

        string urlAddress = string.Empty;
        List articleMatrices = new();
        _ = int.TryParse(_configuration["ParallelTasksCount"], out int parallelTasksCount);

        Parallel.ForEach(feeds, new ParallelOptions { MaxDegreeOfParallelism = parallelTasksCount }, feed =>
        {
            urlAddress = feed.Link;

            var httpClient = new HttpClient
            {
                BaseAddress = new Uri(urlAddress)
            };
            var result = httpClient.GetAsync("").Result;

            string strData = "";

            if (result.StatusCode == HttpStatusCode.OK)
            {
                strData = result.Content.ReadAsStringAsync().Result;

                HtmlDocument htmlDocument = new();
                htmlDocument.LoadHtml(strData);

                ArticleMatrix articleMatrix = new()
                {
                    AuthorId = authorId,
                    Author = feed.Author,
                    Type = feed.FeedType,
                    Link = feed.Link,
                    Title = feed.Title,
                    PubDate = feed.PubDate
                };

                string category = "Videos";
                if (htmlDocument.GetElementbyId("ImgCategory") != null)
                {
                    category = htmlDocument.GetElementbyId("ImgCategory").GetAttributeValue("title", "");
                }

                articleMatrix.Category = category;

                var view = htmlDocument.DocumentNode.SelectSingleNode("//span[@id='ViewCounts']");
                if (view != null)
                {
                    articleMatrix.Views = view.InnerText;

                    if (articleMatrix.Views.Contains('m'))
                    {
                        articleMatrix.ViewsCount = decimal.Parse(articleMatrix.Views[0..^1]) * 1000000;
                    }
                    else if (articleMatrix.Views.Contains('k'))
                    {
                        articleMatrix.ViewsCount = decimal.Parse(articleMatrix.Views[0..^1]) * 1000;
                    }
                    else
                    {
                        _ = decimal.TryParse(articleMatrix.Views, out decimal viewCount);
                        articleMatrix.ViewsCount = viewCount;
                    }
                }
                else
                {
                    var newsView = htmlDocument.DocumentNode.SelectSingleNode("//span[@id='spanNewsViews']");
                    if (newsView != null)
                    {
                        articleMatrix.Views = newsView.InnerText;

                        if (articleMatrix.Views.Contains('m'))
                        {
                            articleMatrix.ViewsCount = decimal.Parse(articleMatrix.Views[0..^1]) * 1000000;
                        }
                        else if (articleMatrix.Views.Contains('k'))
                        {
                            articleMatrix.ViewsCount = decimal.Parse(articleMatrix.Views[0..^1]) * 1000;
                        }
                        else
                        {
                            _ = decimal.TryParse(articleMatrix.Views, out decimal viewCount);
                            articleMatrix.ViewsCount = viewCount;
                        }
                    }
                    else
                    {
                        articleMatrix.ViewsCount = 0;
                    }
                }
                var like = htmlDocument.DocumentNode.SelectSingleNode("//span[@id='LabelLikeCount']");
                if (like != null)
                {
                    _ = int.TryParse(like.InnerText, out int likes);
                    articleMatrix.Likes = likes;
                }

                lock (_lockObj)
                {
                    articleMatrices.Add(articleMatrix);
                }
            }
        });

        _dbContext.ArticleMatrices.RemoveRange(_dbContext.ArticleMatrices.Where(x => x.AuthorId == authorId));

        foreach (ArticleMatrix articleMatrix in articleMatrices)
        {
            if (articleMatrix.Category == "Videos")
            {
                articleMatrix.Type = "Video";
            }
            articleMatrix.Category = articleMatrix.Category.Replace("&", "&");
            await _dbContext.ArticleMatrices.AddAsync(articleMatrix);
        }

        await _dbContext.SaveChangesAsync();
        return true;
    }
    catch
    {
        return false;
    }
    }

    [HttpGet]
    [Route("GetAuthors")]
    public IQueryable GetAuthors()
    {
        return _dbContext.ArticleMatrices.GroupBy(author => author.AuthorId)
                .Select(group =>
                    new Authors
                    {
                        AuthorId = group.FirstOrDefault().AuthorId,
                        Author = group.FirstOrDefault().Author,
                        Count = group.Count()
                    })
                .OrderBy(group => group.Author);
    }

    [HttpGet]
    [Route("GetCategory/{authorId}")]
    public IQueryable GetCategory(string authorId)
    {
        return from x in _dbContext.ArticleMatrices?.Where(x => x.AuthorId == authorId).GroupBy(x => x.Category)
                select new Category
                {
                    Name = x.FirstOrDefault().Category,
                    Count = x.Count()
                };
    }

    [HttpGet]
    [Route("GetAll/{authorId}")]
    public IQueryable GetAll(string authorId)
    {
        return _dbContext.ArticleMatrices.Where(x => x.AuthorId == authorId).OrderByDescending(x => x.PubDate);
    }
}
}


        

💡 O código acima é um trecho de um controlador C# que faz parte de uma API para análise de feeds RSS de blogs. A API usa a biblioteca HtmlAgilityPack para extrair informações de páginas da web e analisar feeds RSS.

💡 O controlador contém três métodos HTTP GET que retornam informações sobre os autores, categorias e matrizes de artigos extraídos dos feeds RSS. Ele também contém um método HTTP POST que é usado para criar matrizes de artigos a partir de feeds RSS.

💡 O método CreatePosts() é um dos principais métodos do controlador. Ele usa a biblioteca HtmlAgilityPack para fazer web scraping em feeds RSS de blogs e extrair informações sobre os artigos publicados. Esse método é iniciado com o recebimento de uma lista de URLs de feeds RSS. A partir disso, o método usa a classe HttpClient da biblioteca System.Net.Http para enviar solicitações HTTP e receber respostas HTTP a partir das URLs fornecidas.

💡 Após o recebimento das respostas HTTP, o método usa a classe XDocument da biblioteca System.Xml.Linq para analisar feeds RSS e extrair informações sobre os artigos publicados. O método usa a classe Feed para armazenar informações sobre os artigos publicados, como o título, a data de publicação, o link e o conteúdo. Ele usa uma lista de objetos Feed para armazenar informações sobre todos os artigos extraídos de um feed RSS.

💡 O método usa a classe ArticleMatrix para armazenar informações adicionais sobre os artigos publicados, como o número de visualizações, o número de curtidas e a categoria do artigo. Ele usa a biblioteca HtmlAgilityPack para analisar o HTML das páginas da web e extrair informações sobre as visualizações e curtidas de cada artigo.

💡 Depois de processar todos os feeds RSS, o método usa a classe MyDbContext para armazenar as matrizes de artigos no banco de dados. Ele usa a classe Parallel.ForEach() para processar vários feeds RSS em paralelo e aumentar a velocidade de processamento. Ele usa o objeto _lockObj para sincronizar o acesso à lista de matrizes de artigos.

💡 Os métodos HTTP GET retornam várias informações sobre as matrizes de artigos armazenadas no banco de dados. O método GetAuthors() retorna uma lista de autores e o número de matrizes de artigos que eles têm. O método GetCategory() retorna uma lista de categorias e o número de matrizes de artigos que pertencem a cada categoria. O método GetAll() retorna todas as matrizes de artigos para um autor específico.

💡 O método GetAuthors() usa a classe IQueryable da biblioteca System.Linq para agrupar as matrizes de artigos por autor e contar quantas matrizes de artigos cada autor tem. Ele retorna uma lista de autores e o número de matrizes de artigos que eles têm.

💡 O método GetCategory() usa a classe IQueryable da biblioteca System.Linq para agrupar as matrizes de artigos por categoria e contar quantas matrizes de artigos pertencem a cada categoria. Ele retorna uma lista de categorias e o número de matrizes de artigos que pertencem a cada categoria.

💡 O método GetAll() usa a classe IQueryable da biblioteca System.Linq para retornar todas as matrizes de artigos para um autor específico. Ele usa o parâmetro authorId para identificar o autor e retorna todas as matrizes de artigos para esse autor.

💡 Em resumo, o código acima é um exemplo de como as bibliotecas HtmlAgilityPack e System.Xml.Linq podem ser usadas para extrair informações de feeds RSS de blogs e armazená-las em um banco de dados. Ele usa várias técnicas de programação, como web scraping, análise de XML e paralelismo, para aumentar a eficiência do processo de análise.

💡 Além disso, é possível notar que o código é bem organizado e segue boas práticas de programação. Ele usa classes e métodos bem definidos e faz uso de comentários para explicar o que cada parte do código faz. Também é importante destacar que o código é robusto e trata exceções para garantir que o sistema continue funcionando mesmo em caso de erros inesperados.

💡 Em conclusão, o código acima é um exemplo de como é possível utilizar diversas bibliotecas e técnicas de programação para extrair informações importantes de páginas web e feeds RSS e armazená-las de maneira organizada em um banco de dados. Com isso, é possível desenvolver ferramentas poderosas para análise de informações em diversos contextos.