Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

Buscar dados em texto HTML

          string urlAddress = "https://www.confaz.fazenda.gov.br/legislacao/atos-pmpf/2015/pmpf002_15";

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlAddress);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            if (response.StatusCode == HttpStatusCode.OK)
            {
                Stream receiveStream = response.GetResponseStream();
                StreamReader readStream = null;

                if (response.CharacterSet == null)
                {
                    readStream = new StreamReader(receiveStream);
                }
                else
                {
                    readStream = new StreamReader(receiveStream, Encoding.GetEncoding(response.CharacterSet));
                }

                string data = readStream.ReadToEnd();

                Console.WriteLine(data);

                response.Close();
                readStream.Close();
            }

Com esse código, consigo buscar a string do HTML de um site do governo com uma tabela de preços-padrão de combustíveis por Estado. Estes preços são atualizados quinzenalmente e meu objetivo é automatizar a atualização destes dados em um banco de dados.

Para tanto, tenho pesquisado sobre Expressões Regulares mas ainda não consegui entender e fazer a extração das informações da tabela.

Como posso fazer para buscar de dentro do HTML somente as informações da tabela presente no site indicado?

Os dados que preciso são representados pelo "@@@" na expressão:

<p class="A7-1TabelaSubtitulo">@@@</p>
6 respostas

Opa Vitor! blz?

É só tratar o HTML como se fosse um XML e utilizar o System.Xml.XmlDocument.

Você consegue carregar o Html recebido no Response com o .Load() através de um memory stream.

A partir daí há várias estratégias para percorrer os nós, pegando os elementos com .GetElements ou retornando com uma expressão XPath.

Dá uma lida na documentação do XmlDocument que vai ser bem fácil você realizar essa leitura:

Documentação XmlDocument

Espero ter dado uma luz!

Abs.

Olá Márcio, adicionei as seguintes linha ao código:

XmlDocument document = new XmlDocument();
document.Load(receiveStream);

No Load me apresenta o erro:

System.Xml.XmlException: 'Elemento raiz inexistente.'

Estou fazendo algo errado? =/

Agradeço o auxílio!

solução!

Olá! A melhor forma que eu encontrei de utilizar no c# foi com o pacote HTMLAGILTYPACK que você encontrar no gerenciador de pacotes nuget no visual studio.

O site oficial é esse aqui, é por ele que aconselho a ler e se entender o básico. https://html-agility-pack.net/

Com esse pacote eu aconselho você a fazer buscas no documento HTML pelo XPATH.

Acredito que é o básico pra você tentar! segue um exemplo de código.

var web = new HtmlWeb();
var html = web.Load('URL'); 
var conteudoBuscado=html.DocumentNode.SelectSingleNode('xpath').InnerHtml;

Jõao Gabriel, realmente em pesquisas na internet me sugeriram esta ferramenta e eu utilizei ela, só achei que ficou feio demais meu teste... Site do governo é uma tristeza, todo ano muda alguma coisa no html e na forma de disponibilizar a página dai tem que ir socando "ifs" no código.

Para pesquisas futuras, fica aí como montei o teste salvando as tabelas em um arquivo csv:

string url = "https://www.confaz.fazenda.gov.br/legislacao/atos-pmpf/";

            for (int ano = 2014; ano < 2020; ano++)
            {
                for (int i = 1; i < 26; i++)
                {
                    string site = url + $"{ano}/pmpf{i.ToString("000")}_{ano - 2000}";

                    HtmlWeb web = new HtmlWeb();
                    HtmlDocument doc = web.Load(site);

                    HtmlNode no = doc.GetElementbyId("parent-fieldname-text");

                    if (no == null)
                        continue;
                    DateTime dataAtoCotepe = DateTime.MinValue;
                    foreach (var item in no.ChildNodes.Where(c => c.Name == "p"))
                    {
                        string replacement = Regex.Replace(item.InnerText, @"\t|\n|\r|\b", "").Trim();
                        if (replacement.StartsWith("O Secretário"))
                        {
                            string[] campo = replacement.Split(',');
                            foreach (string dado in campo)
                            {
                                if (dado.Trim().StartsWith("a partir de"))
                                {
                                    string data = dado.Replace("a partir de", "").Replace("º", "").Trim();
                                    DateTime.TryParse(data, out dataAtoCotepe);
                                }
                            }
                        }
                    }

                    HtmlNode tabela = no.SelectSingleNode("table");

                    if (tabela == null)
                    {
                        foreach (HtmlNode item in no.ChildNodes.Where(c => c.Name == "div"))
                        {
                            foreach (HtmlNode valor in item.ChildNodes)
                            {
                                if (valor.Name == "table")
                                {
                                    tabela = valor;
                                    break;
                                }
                            }
                            if (tabela != null)
                                break;
                        }
                    }

                    tabela = tabela.SelectSingleNode("tbody");
                    if (tabela == null)
                        continue;

                    List<string> textoTabela = new List<string>();

                    foreach (HtmlNode linha in tabela.ChildNodes)
                    {
                        string dados = dataAtoCotepe.ToShortDateString() + ";";
                        foreach (HtmlNode coluna in linha.ChildNodes.Where(c => c.Name == "td"))
                        {
                            string replacement = Regex.Replace(coluna.InnerText, @"\t|\n|\r|", " ");
                            dados += replacement.Replace("*", "").Trim() + ";";
                        }
                        textoTabela.Add(dados);
                    }

                    if (textoTabela.Count == 0)
                        continue;



                    using (FileStream stream = new FileStream($@"C:\A\Preço Pauta\preco_pauta_{ano}-{i.ToString("000")}.csv", FileMode.Create, FileAccess.Write))
                    {
                        using (StreamWriter writer = new StreamWriter(stream, Encoding.Default))
                        {
                            foreach (string linha in textoTabela)
                            {
                                writer.WriteLine(linha);
                            }
                        }
                    }


                }
            }

Vitor Gonçalves mas deu certo seu código final ?

Deu certo sim João. Obrigado.

Igual falei, para mim ficou muito feio... rsrs Mas... está cumprindo o propósito!