enviar datos con WebRequest

Iniciado por s_azazel, 9 Marzo 2014, 15:21 PM

0 Miembros y 1 Visitante están viendo este tema.

s_azazel

Buenas tardes!!! estoy intentando automatizar un registro. tengo algo en phyton pero me gustaria pasarlo a vb.net porque me siento mas comodo

en phyton pido info de una url enviandole unos datos:

Citara=requests.get(url) data={'idDepartamento':'1','idServicio':'1','idTramite':'22','idAsunto':'42'}

e=requests.post(url,data=data)

Y en vb.net tengo algo asi:

CitarDim request As System.Net.HttpWebRequest = System.Net.HttpWebRequest.Create("URL")
     
       
        request.CookieContainer = New CookieContainer()
        Dim response As System.Net.HttpWebResponse = request.GetResponse()

El codigo de la pagina me lo devuelve perfectamente pero no encuento la forma de enviar con el request los datos ({'idDepartamento':'1','idServicio':'1','idTramite':'22','idAsunto':'42'})
Que envio con phyton


Gracias!!!


kub0x

Buenas s_azazel,

por lo que veo quieres enviar una ristra de parámetros por POST a un apartado de registro específico en un servidor web.

En Python parece bastante intuitivo, en .NET también lo es, sin necesidad de tener que lidiar con APIs molestas, ya que el Framework (conjunto de clases, librerias etc) nos aporta un nivel aceptable de abstración.

Si tienes FireFox con la extensión de FireBug podrás analizar las cabeceras de los paquetes que envias en todo momento, pudiendo analizar el paquete que envias a dicho apartado de registro. Ahí lo dejo caer...

Te dejo un ejemplo de como enviar datos por POST, puede que haya algo mal ya que lo he escrito del tirón:

Código (VB.NET) [Seleccionar]

Dim request As HttpWebRequest = CType(HttpWebRequest.Create(URL), HttpWebRequest)
With request
'El UserAgent es el que utiliza mi navegador, pon aqui uno cualquiera
.UserAgent = "Mozilla/5.0 (Windows NT 6.1; rv:22.0) Gecko/20130315 Firefox/22.0"
.Proxy = Nothing
.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
.Method = "POST"
.ContentType = "application/x-www-form-urlencoded"
.ContentLength = Data.Length 'Donde data son los datos que quieres enviar IdDepartamento, IdServicio...
End With
'Llegados a este punto ya hemos configurado las cabeceras del paquete Http que vamos a enviar por POST
'Ahora solo falta escribir esos datos en el paquete que queremos enviar
Using requestStream As Stream = req.GetRequestStream()
  requestStream.Write(data, 0, data.Length)
  requestStream.Close()
End Using
'Hemos terminado de escribir los datos en el paquete, ahora solo falta enviarlo y recibir la respuesta
Dim response As HttpWebResponse = req.GetResponse()
'...... y aquí lo que necesites


Un saludo!
Viejos siempre viejos,
Ellos tienen el poder,
Y la juventud,
¡En el ataúd! Criaturas Al poder.

Visita mi perfil en ResearchGate


Eleкtro

#2
Kubox, tengo la sensación de que el código lo escribiste al vuelo (porque no tiene indentación), te equivocaste al escribir un par de cosas, el nombre del objeto que usas es 'request', pero luego lo escribes como 'req', también el Stream espera un array de bytes pero le estás pasando un String a secas (Data) :P, pero vamos, creo que se entiende perféctamente lo que quisiste explicar, son cosas sin importancia pero... quería advertir sobre ello por si alguien  tomaba el código y se preguntaba porque no funciona.

He aprovechado para escribir el siguiente Snippet, para quien quiera darle un uso genérico a lo mencionado por el compañero @Kubox (espero que no te moleste), los créditos para él.

Código (vbnet) [Seleccionar]
   ''' <summary>
   ''' Sends a POST method petition and returns the server response.
   ''' </summary>
   ''' <param name="URL">Indicates the URL.</param>
   ''' <param name="PostData">Indicates the post data.</param>
   ''' <returns>The response.</returns>
   Public Function SendPOST(ByVal URL As String,
                            ByVal PostData As Dictionary(Of String, String)) As String

       Dim Data As New System.Text.StringBuilder ' PostData to send, formated.
       Dim Request As Net.HttpWebRequest = HttpWebRequest.Create(URL) ' HTTP Request.
       Dim Response As HttpWebResponse ' Server response.
       Dim ResponseContent As String ' Server response result.

       ' Set and format the post data of the query.
       For Each Item As KeyValuePair(Of String, String) In PostData
           Data.AppendFormat("{0}={1}&", Item.Key, Item.Value)
       Next Item

       ' Set the Request properties.
       With Request
           .Method = "POST"
           .ContentType = "application/x-www-form-urlencoded"
           .ContentLength = Data.ToString.Length
           .Proxy = Nothing
           ' .UserAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0"
       End With

       ' Write the POST data bytes into the Stream.
       Using RequestStream As IO.Stream = Request.GetRequestStream()
           RequestStream.Write(System.Text.Encoding.UTF8.GetBytes(Data.ToString), 0, Data.ToString.Length)
       End Using

       ' Get the response.
       Response = Request.GetResponse()

       ' Get the response content.
       Using Reader As New System.IO.StreamReader(Request.GetResponse().GetResponseStream)
           ResponseContent = Reader.ReadToEnd
           Response.Close()
       End Using

       ' Return the response content.
       Return ResponseContent

   End Function


Ejemplo de uso:

Código (vbnet) [Seleccionar]
   Private Sub Test() Handles MyBase.Shown

       Dim Url As New Uri("http://es.wikipedia.org/wiki/Special:Search?")

       Dim PostData As New Dictionary(Of String, String) From
           {
               {"search", "Petición+POST"},
               {"sourceid", "Mozilla-search"}
           } ' Formated Result: "search=Petición+POST&sourceid=Mozilla-search"

       Dim Response As String =
           SendPOST(Url.AbsoluteUri, PostData)

       Clipboard.SetText(Response) ' Copy to clipboard.
       MessageBox.Show(Response)

   End Sub


Saludos!








s_azazel

Mil gracias a los dos!!!
Me ha funcionado perfectamente  :D :D :D

s_azazel

No se si esto lo deberia de preguntar aqui...

La idea de le programa es porque en la web que me quiero registrar solo abren los registros una vez cada 15 dias y se acaban en unos 5 o 10 minutos

Durante este tiempo el server se cae varias veces e incluso me ha tardado en cargar una pagina mas de 5 minutos

Asi que habia pensado poner un timeout con un retry cada 10 seg o asi

La pregunta es: ¿se podria hacer mediante HttpWebRequest  mas de una peticion de vez para asegurarme que al menos acepte una??

Gracias!!!

Eleкtro

Kubox sabe más sobre este tema que yo, pero si la página no te carga... creo que sería una tontería hacer peticiones simultaneas desde la misma IP ya que ninguna te cargaría, creo.

De todas formas, poder se puede, puedes usar el método HttpWebRequest.BeginGetResponse, que es asíncrono, pero también podrías enviar una única petición y esperar hasta que se realice corréctamente con un Do Until/While Not

El siguiente Snippet lo escribí hace mucho tiempo, se puede mejorar, pero siempre me ha funcionado bien, pruébalo.

Código (vbnet) [Seleccionar]
   ''' <summary>
   ''' Determines whether a connectivity to an URL is avaliable.
   ''' </summary>
   ''' <param name="url">Indicates the URL.</param>
   ''' <param name="RetryInterval">
   ''' Indicates the retry interval, in seconds.
   ''' Use "-1" to any interval.</param>
   ''' <param name="StatusControl">
   ''' Indicates the status control.
   ''' If any control is specified, the status will be shown in Debug console.
   ''' </param>
   ''' <returns><c>true</c> if connectivity avaliable; otherwise, <c>false</c>.</returns>
   Private Function IsConnectivityAvaliable(ByVal url As String,
                                            Optional ByVal RetryInterval As Integer = -1,
                                            Optional ByVal StatusControl As Control = Nothing) As Boolean

       Dim NoNetworkMessage As String = "Network connection is not avaliable."
       Dim NoWebsiteMessage As String = "WebSite is not avaliable."
       Dim NoNetworkRetryMessage As String = "Network connection is not avaliable, retrying in {0} seconds..."
       Dim NoWebsiteRetryMessage As String = "WebSite is not avaliable, retrying in {0} seconds..."
       Dim YesNetworkMessage As String = "Network connection established."
       Dim YesWebsiteMessage As String = "WebSite connection established."

       Select Case My.Computer.Network.IsAvailable

           Case False ' No network device avaliable

               If RetryInterval = -1 Then ' Do not retry
                   PrintNetworkStatus(NoNetworkMessage, StatusControl)
                   Return False

               Else ' Retry

                   For X As Integer = 0 To RetryInterval
                       WaitNetworkStatus()
                       PrintNetworkStatus(String.Format(NoNetworkRetryMessage, RetryInterval - X), StatusControl)
                   Next X

                   IsConnectivityAvaliable(url, RetryInterval, StatusControl)

               End If ' RetryInterval

           Case True ' Network device is avaliable

               ' Inform that network device is avaliable.
               PrintNetworkStatus(YesNetworkMessage, StatusControl)

               Try ' Try connect to the given url
                   My.Computer.Network.Ping(url)

                   ' Inform that Website connection is avaliable.
                   PrintNetworkStatus(YesWebsiteMessage, StatusControl)
                   Return True

               Catch ex As Net.NetworkInformation.PingException

                   If RetryInterval = -1 Then ' Do not retry
                       PrintNetworkStatus(NoWebsiteMessage, StatusControl)
                       Return False

                   Else ' Retry

                       For X As Integer = 0 To RetryInterval
                           WaitNetworkStatus()
                           PrintNetworkStatus(String.Format(NoWebsiteRetryMessage, RetryInterval - X), StatusControl)
                       Next X

                       IsConnectivityAvaliable(url, RetryInterval, StatusControl)

                   End If ' RetryInterval

               Catch ex As InvalidOperationException

                   If RetryInterval = -1 Then ' Do not retry
                       PrintNetworkStatus(NoNetworkMessage, StatusControl)
                       Return False

                   Else ' Retry

                       For X As Integer = 0 To RetryInterval
                           WaitNetworkStatus()
                           PrintNetworkStatus(String.Format(NoNetworkRetryMessage, RetryInterval - X), StatusControl)
                       Next

                       IsConnectivityAvaliable(url, RetryInterval, StatusControl)

                   End If ' RetryInterval

               End Try

       End Select

   End Function

   ''' <summary>
   ''' Prints the network status.
   ''' </summary>
   ''' <param name="Message">Indicates the Status message.</param>
   ''' <param name="StatusControl">Indicates the control to print the connection Status.</param>
   Private Sub PrintNetworkStatus(ByVal Message As String,
                                  Optional ByVal StatusControl As Control = Nothing)

       If StatusControl IsNot Nothing Then
           StatusControl.Invoke(Sub() StatusControl.Text = Message)
       Else
           Debug.WriteLine(Message)
       End If

   End Sub

   ''' <summary>
   ''' Waits an interval before trying to reconnect.
   ''' </summary>
   ''' <param name="WaitPeriod">Indicates the wait interval, in ms.</param>
   Private Sub WaitNetworkStatus(Optional ByVal WaitPeriod As Integer = 1000)
       Threading.Thread.Sleep(WaitPeriod)
   End Sub


Ejemplo de uso:

Código (vbnet) [Seleccionar]
   Private Sub Test() Handles MyBase.Load

       Dim t As New Threading.Thread(AddressOf CheckConnectivity)
       t.Start()

   End Sub

   Private Sub CheckConnectivity()

       Do Until IsConnectivityAvaliable("sqwertyqwertyqwerty.com", 10, Label1)
           Application.DoEvents()
       Loop

       ' Enviar POST aquí...

   End Sub


Saludos








s_azazel

Muchas gracias!!! lo tengo ya preparado y con varias el intento de varias conexiones simultaneas

Cuando lo ahaci con el navegador se quedaba colgado hasta 5 minutos o mas hasta que abria la pagina en el momento de el colapso

¿Sabeis si es mejor poner un timeout bajo y refrescar o dejarlo que acabe de cargar (no se si todo ese rato esta cargado algo.La verdad es que es ligerisima la pagina)

El mayor problema es ese pues las citas disponibles se acaban enseguida

Gracias

kub0x

Si no sabes que día ni a que hora exacta va a ser abierto el servidor de registro entonces te recomiendo que montes una aplicación que realice checkeos a la dirección de dicho servidor cada poco tiempo. Cuando detecte que el servidor está activo entonces debería de enviar la petición, siendo uno de los primeros en realizarla. No sé si habrá más bots en juego en dicho momento, ya que no conozco la página contra la que intentas autenticarte, puede que no tengas problemas, o puede que sí.

Para poner el timeout debes pensar en cuanto tiempo tarda el servidor de la página en procesar tu registro, ya que si pones un timeout más bajo cortará la conexión.

Hay varías formas de enviar peticiones a servidores web, una es haciendo uso de hilos, otra es utilizando Tasks (.NET Framework 4.5 creo) y la mejor para mí es haciendo uso de CallBacks, que es uno de los fuertes de .NET. No es más que programación asíncrona, bellísima por cierto.

Cuidado no acabes haciendo un DDoS jajajajajaja, suerte!

Saludos!
Viejos siempre viejos,
Ellos tienen el poder,
Y la juventud,
¡En el ataúd! Criaturas Al poder.

Visita mi perfil en ResearchGate


s_azazel

Muchas gracias!!! Lo he hecho a traves de hilos.
Se que abre un viernes de cada dos a las 9 am
Tengo ya mas o menos acabado tiene que pasar por dos paginas por temas de cookies, finalmente hace un get a la captcha y envia los datos al formulario

intentare cunado lo abran crear unos 20 hilos a ver si lo agunata

Muchas Gracias!!!!