VB .NET - Obtendo informações de uma web page


Você já precisou obter informações de uma site da web ?

Se você é um programador Visual Basic (ou C#) provavelmente se deparou ou vai deparar com essa tarefa, afinal hoje praticamente quase todas as informações são acessadas através de uma página web.

Neste artigo eu procuro apresentar alternativas viáveis de como você pode realizar esta tarefa usando a linguagem VB .NET (em outro artigo mostrarei a mesma coisa usando a linguagem C#).

Para acompanhar os exemplos deste artigo você vai precisar usar o Visual Basic 2010 Express Edition.

Um pouco de teoria

A plataforma .NET fornece duas classes presentes no namespace System.NET que podemos usar para podermos interagir diretamente com servidores usando HTTP. São elas:

  1. WebRequest - Realiza uma requisição para uma URI - Uniform Resource Identifier . É uma classe abstrata.
  2. WebResponse - Fornece uma resposta a partir de uma URI - Uniform Resource Identifier . É uma classe abstrata.

Para podermos usar os recursos da classe WebRequest podemos usar as classes HttpWebRequest e HttpWebResponse que fornecem implementações específicas destas classes.

Dessa forma a classe HttpWebRequest fornece suporte para as propriedades e métodos definidos na classe WebRequest e para propriedades e métodos adicionais que permitem interagir usando o protocolo HTTP.

- O método Create() de uma instância da classe WebRequest para iniciar os objetos HttpWebRequest;
- O método GetResponse() realiza uma requisição síncrona através da propriedade RequestUri, retornando um objeto HttpWebResponse contendo a resposta de uma requisição;
- O método GetRequestStream() obtém um objeto stream usado para escrever os dados da requisição;

Usando estas duas classes, temos tudo que precisamos para fazer o download de uma página Web completa em um stream ou postar dados para uma URL.

Criando o projeto

Abra o Visual Basic 2010 Express Edition e crie um novo projeto (File-> New Project) do tipo Windows Forms Application com o nome ExtraindoDadosWeb;

A seguir vamos incluir uma classe no projeto via menu Project -> Add Class com o nome Web.vb e definir o seguinte código nesta classe:

1- Namespaces

Imports System.Net
Imports System.Text.RegularExpressions
Imports System.IO
Imports System.Data

2- Método RequestDadosWeb que retorna uma string contendo o código de uma URL definida:

Public Function RequestDadosWeb(ByVal pstrURL As String) As String
        Dim oWebRequest As WebRequest
        Dim oWebResponse As WebResponse = Nothing
        Dim strBuffer As String = ""
        Dim objSR As StreamReader = Nothing
        'conecta com o website
        Try
            oWebRequest = HttpWebRequest.Create(pstrURL)
            oWebResponse = oWebRequest.GetResponse()
            'Le a resposta do web site e armazena em uma stream
            objSR = New StreamReader(oWebResponse.GetResponseStream)
            strBuffer = objSR.ReadToEnd
        Catch ex As Exception
            Throw ex
        Finally
            objSR.Close()
            oWebResponse.Close()
        End Try
        Return strBuffer
    End Function

A seguir vamos mostrar como usar este método para obter informações de uma página Web.

Inclua no formulário form1.vb, a partir da ToolBox, os controles TextBox(txtDados Multiline=True), Button (btnObterPagina), TextBox(txtUrl) conforme o leiaute abaixo:

No evento Click do botão de comando - Obter Página - incluo código abaixo:

 Private Sub btnObterPagina_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnObterPagina.Click
        Try
            Dim wc As New Web
            txtDados.Text = wc.RequestDadosWeb(txtUrl.Text.Trim)
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
End Sub

Executando o projeto iremos obter:

Podemos a partir das informações obtidas extrair outras informações realizando um filtro no arquivo recebido. Para ilustrar isso vamos extrair os links de uma página web.

Para isso temos que incluir na nossa classe Web.vb os métodos ExtrairLinks e MapearUrl conforme o código a seguir:

    Public Function ExtrairLinks(ByVal url As String) As DataTable
        Dim dt As New DataTable
        dt.Columns.Add("LinkTexto")
        dt.Columns.Add("LinkUrl")

        Dim wc As New WebClient
        Dim html As String = wc.DownloadString(url)

        Dim links As MatchCollection = Regex.Matches(html, "<a.*?href=""(.*?)"".*?>(.*?)</a>")

        For Each match As Match In links
            Dim dr As DataRow = dt.NewRow
            Dim matchUrl As String = match.Groups(1).Value
            'Ignora todos os links âncoras
            If matchUrl.StartsWith("#") Then
                Continue For
            End If
            'Ignora todas as chamadas javascript
            If matchUrl.ToLower.StartsWith("javascript:") Then
                Continue For
            End If
            'Ignora todos os links de email
            If matchUrl.ToLower.StartsWith("mailto:") Then
                Continue For
            End If
            'Para links internos, constroi a url mapeada para o endereço base
            If Not matchUrl.StartsWith("http://") And Not matchUrl.StartsWith("https://") Then
                matchUrl = MapearUrl(url, matchUrl)
            End If
            'Inclui o link no datatable
            dr("LinkUrl") = matchUrl
            dr("LinkTexto") = match.Groups(2).Value
            dt.Rows.Add(dr)
        Next

        Return dt
    End Function

    Public Function MapearUrl(ByVal enderecoBase As String, ByVal caminhoRelativo As String) As String
        Dim u As New System.Uri(enderecoBase)

        If caminhoRelativo = "./" Then
            caminhoRelativo = "/"
        End If

        If caminhoRelativo.StartsWith("/") Then
            Return u.Scheme + Uri.SchemeDelimiter + u.Authority + caminhoRelativo
        Else
            Dim Caminho_Consulta As String = u.AbsolutePath
            ' Se o enderecoBase contem o nome do arquivo como ..../Something.aspx
            ' ajusta o nome do arquivo

            Caminho_Consulta = Caminho_Consulta.Split("?")(0).TrimEnd("/")
            If Caminho_Consulta.Split("/")(Caminho_Consulta.Split("/").Count - 1).Contains(".") Then
                Caminho_Consulta = Caminho_Consulta.Substring(0, Caminho_Consulta.LastIndexOf("/"))
            End If
            enderecoBase = u.Scheme + Uri.SchemeDelimiter + u.Authority + Caminho_Consulta

            'se o caminhoRelativo contém ../ então
            ' ajusta o enderecoBase

            While caminhoRelativo.StartsWith("../")
                caminhoRelativo = caminhoRelativo.Substring(3)
                If enderecoBase.LastIndexOf("/") > enderecoBase.IndexOf("//" + 2) Then
                    enderecoBase = enderecoBase.Substring(0, enderecoBase.LastIndexOf("/")).TrimEnd("/")
                End If
            End While

            Return enderecoBase + "/" + caminhoRelativo
        End If

    End Function

O método ExtrairLInks obtêm os links da URL definida salvando as informações em um DataTable e utiliza o método MapearUrl que faz os ajustes nos nomes extraídos:

Para testar a nova funcionalidade vamos incluir mais controle Button (btnLinks), uma caixa de Texto (txtLinks0) e um controle DataGridView(dgvDados) conforme a figura abaixo:

No evento Click do botão Obter Links inclua o código a seguir:

 Private Sub btnLinks_Click(sender As System.Object, e As System.EventArgs) Handles btnLinks.Click
        Dim wc As New Web
        dgvDados.DataSource = wc.ExtrairLinks(txtLinks.Text.Trim)
    End Sub

Executando o projeto e fornecendo a URL, após clicar no botão Obter Links teremos o seguinte resultado:

Que tal obter imagens de páginas web ?

Vamos fazer isso primeiro alterando o leiaute do formulário form1.vb, incluindo dois controles Button(btnImage1 e btnImage2) e dois controles PictureBox conforme o leiaute abaixo:

Vamos agora incluir na classe Web.vb o método RequestImagemWeb que retorna uma imagem obtida do website conforme a seguir:

Public Function RequestImagemWeb(ByVal pstrURL As String, ByVal imagem As String) As String
        Dim oWebRequest As WebRequest
        Dim oWebResponse As WebResponse

 
      'conecta com o website
        oWebRequest = HttpWebRequest.Create(pstrURL)
        oWebResponse = oWebRequest.GetResponse()

     
  'Le a resposta do website e armazena em uma stream
        Dim objStream As Stream
        objStream = oWebResponse.GetResponseStream
        Dim inBuf(100000) As Byte
        Dim bytesToRead As Integer = CInt(inBuf.Length)
        Dim bytesRead As Integer = 0
        While bytesToRead > 0
            Dim n As Integer = objStream.Read(inBuf, bytesRead, bytesToRead)
            If n = 0 Then
                Exit While
            End If
            bytesRead += n
            bytesToRead -= n
        End While
        Dim fstr As New FileStream(imagem, FileMode.OpenOrCreate, FileAccess.Write)
        fstr.Write(inBuf, 0, bytesRead)
        objStream.Close()
        fstr.Close()

        oWebResponse.Close()
  
     'retorna a imagem
        Return imagem
    End Function

No evento Click de cada um dos botões - Obter Imagem - inclua o código abaixo:

Private Sub btnImagem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnImagem1.Click
        Dim strArquivo As String
        Dim wc As New Web
        strArquivo = wc.RequestImagemWeb("http://www.macoratti.net/images/maco1b.gif", "maco1b.gif")
        PictureBox1.Image = Image.FromFile(strArquivo)
    End Sub

    Private Sub btnImagem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnImagem2.Click
        Dim strArquivo As String
        Dim wc As New Web
        strArquivo = wc.RequestImagemWeb("http://www.macoratti.net/images/dvdnet2.gif", "dvdnet2.gif")
        PictureBox2.Image = Image.FromFile(strArquivo)
    End Sub

O código acima recebe a imagem do website e a exibe em um controle PictureBox.

Executando o projeto e clicando em cada um dos botões de comando teremos:

Configurando o acesso via proxy

Tudo o que foi mostrado aqui vai falhar se você estiver sob um proxy que requeira uma autenticação para acessar as páginas usadas.

Mas podemos facilmente contornar o problema configurando as propriedades Proxy e usando a classe NetWorkCredential(username,password) para definir o nome do usuário e a senha do proxy.

A propriedade Proxy define ou obtém o proxy da rede e a classe NetWorkCredential permite fornecer as credenciais usadas para acessar o proxy.

No nosso caso, supondo que exista um proxy configurado como : proxy.com.br na porta 80, e que o usuário usado fosse macoratti com senha numsey, bastaria incluir as seguintes linhas de código para acessar as páginas:

Dim wp As WebProxy = New WebProxy("proxy.com.br", 80)
wp.Credentials = New NetworkCredential("
macoratti", "numsey")
request.Proxy = wp

E assim vimos como extrair informações e imagens de páginas web usando as classe WebRequest e WebResponse.

pegue o projeto completo aqui: ExtraindoDadosWeb.zip

Filipenses 2:14 Fazei todas as coisas sem murmurações nem contendas;
Filipenses 2:15
para que vos torneis irrepreensíveis e sinceros, filhos de Deus imaculados no meio de uma geração corrupta e perversa, entre a qual resplandeceis como luminares no mundo,

Filipenses 2:16
retendo a palavra da vida; para que no dia de Cristo eu tenha motivo de gloriar-me de que não foi em vão que corri nem em vão que trabalhei.

Referências:

José Carlos Macoratti