WebRequest: cómo encontrar un código postal utilizando una reducción web contra este contentType = “Aplicación/XHTML+XML, Text/XML, Text/Html; charset = utf-8 "?

StackOverflow https://stackoverflow.com/questions/1455567

Pregunta

Primero publiqué esto: HttpwebRequest: ¿Cómo encontrar un código postal en Canadá Post a través de una reducción web con X-www-form-engranado?.

Siguiendo las sugerencias de Anthonywjones, cambié mi código siguiendo sus sugerencias.

Sobre una continuación de mi consulta, he notado con el tiempo que es más probable que el tipo de contenido de Canadá sea "Aplicación/XHTML+XML, Text/XML, Text/Html; Charset = UTF-8".

Mis preguntas son:

  1. ¿Cómo tenemos una reducción web contra un sitio web de este tipo de contenido?
  2. ¿Tenemos que seguir con el objeto NameValuecollection?
  3. Según Scott Lance, quien generosamente me proporcionó información preciosa dentro de mi pregunta anterior, la reducción web devolverá el tipo de información, sea cual sea el tipo de contenido, ¿me estoy perdiendo algo aquí?
  4. ¿Tengo que cambiar mi código debido al cambio de tipo de contenido?

Aquí está mi código para que sea más fácil entender mi progreso.

internal class PostalServicesFactory {
/// <summary>
/// Initializes an instance of GI.BusinessSolutions.Services.PostalServices.Types.PostalServicesFactory class.
/// </summary>
internal PostalServicesFactory() {
}
/// <summary>
/// Finds a Canadian postal code for the provided Canadian address.
/// </summary>
/// <param name="address">The instance of GI.BusinessSolutions.Services.PostalServices.ICanadianCityAddress for which to find the postal code.</param>
/// <returns>The postal code found, otherwise null.</returns>
internal string FindPostalCode(ICanadianCityAddress address) {
    if (address == null)
        throw new InvalidOperationException("No valid address specified.");

    using (ServicesWebClient swc = new ServicesWebClient()) {
        var values = new System.Collections.Specialized.NameValueCollection();

        values.Add("streetNumber", address.StreetNumber.ToString());
        values.Add("numberSuffix", address.NumberSuffix);
        values.Add("suite", address.Suite);
        values.Add("streetName", address.StreetName);
        values.Add("streetDirection", address.StreetDirection);
        values.Add("city", address.City);
        values.Add("province", address.Province);

        byte[] resultData = swc.UploadValues(@"http://www.canadapost.ca/cpotools/apps/fpc/personal/findByCity", "POST", values);

        return Encoding.UTF8.GetString(resultData);
    }
}

private class ServicesWebClient : WebClient {
    public ServicesWebClient()
        : base() {
    }
    protected override WebRequest GetWebRequest(Uri address) {
        var request = (HttpWebRequest)base.GetWebRequest(address);
        request.CookieContainer = new CookieContainer();
        return request;
    }
}
}

Este código realmente devuelve el código fuente HTML del formulario que uno debe completar con la información requerida para procesar con la búsqueda del código postal. Lo que deseo es obtener el código fuente HTML o lo que sea con el código postal encontrado.

EDITAR: Aquí está la WebException que obtengo ahora: "No puedo enviar un cuerpo de contenido con este tipo de verbo". (Esta es una traducción de la excepción de francés "Imposible d'Envoyer Un Corps de Contenu Avec Ce Type de Verbe").

Aquí está mi código:

    internal string FindPostalCode(string url, ICanadianAddress address) {
    string htmlResult = null;

    using (var swc = new ServiceWebClient()) {
        var values = new System.Collections.Specialized.NameValueCollection();

        values.Add("streetNumber", address.StreetNumber.ToString());
        values.Add("numberSuffix", address.NumberSuffix);
        values.Add("suite", address.Suite);
        values.Add("streetName", address.StreetName);
        values.Add("streetDirection", address.StreetDirection);
        values.Add("city", address.City);
        values.Add("province", address.Province);

        swc.UploadValues(url, @"POST", values);
        string redirectUrl = swc.ResponseHeaders.GetValues(@"Location")[0];
        => swc.UploadValues(redirectUrl, @"GET", values);
    }

    return htmlResult;
}

La línea que causa la excepción se apunta con "=>". Parece que no puedo usar Get como método, pero esto es lo que me ha dicho que haga ...

¿Alguna idea de lo que me estoy perdiendo aquí? Intento hacer lo que Justin (ver respuesta) me recomendó que hiciera.

¡Gracias de antemano por cualquier ayuda! :-)

¿Fue útil?

Solución

Como introducción al mundo del raspado de pantalla, ¡ha elegido un caso muy difícil! La página de búsqueda de Canada Post funciona así:

  1. La primera página es un formulario que acepta los valores de la dirección
  2. Esta página publica en una segunda URL.
  3. Esa segunda URL a su vez redirige (usando una redirección HTTP 302) a una tercera URL que realmente muestra la respuesta HTML que contiene el código postal.

Para empeorar las cosas, la página en el Paso 3 necesita saber la cookie establecida en el paso #1. Entonces necesitas usar lo mismo CookieContainer para las tres solicitudes (aunque posiblemente sea suficiente enviar lo mismo CookieContainer solo a #2 y #3).

Además, es posible que deba enviar encabezados HTTP adicionales en estas solicitudes también, como aceptar. Sospecho que dónde se encuentra con problemas es que httpwebRequest, por defecto, maneja redirigir de manera transparente para usted, pero cuando redirige transparentemente, puede no agregar los encabezados HTTP correctos necesarios para hacerse pasar por un navegador.

La solución es establecer el HttpWebRequest's AllowAutoRedirect propiedad a falso y manejar la redirección usted mismo. En otras palabras, una vez que la primera solicitud devuelve una redirección, deberá sacar la URL en el HttpWebResponse's Location: encabezamiento. Entonces necesitarás crear un nuevo HttpWebRequest (Esta vez una solicitud de obtención regular, no una publicación) para esa URL. ¡Recuerda para enviar la misma galleta! (la CookieContainer La clase lo hace muy fácil)

También es posible que deba hacer una solicitud adicional (#1 en mi lista anterior) para configurar la cookie de sesión. Si yo fuera usted, supongo que esto es necesario, simplemente para eliminarlo como un problema e intente eliminar ese paso más tarde y ver si su solución aún funciona.

Querrás descargar y usar fiddler (www.fiddlertool.com) para ayudarte con todo esto. Fiddler le permite ver las solicitudes HTTP sobre el cable, y le permite (a través de la función del constructor de solicitudes) le permite crear solicitudes HTTP para que pueda ver qué encabezados realmente se requieren.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top