WebRequest: So finden Sie eine Postleitzahl mit einem WebRequest gegen diesen ContentType = „Application/XHTML+XML, Text/XML, Text/HTML; charset = utf-8 ”?

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

Frage

Ich habe das zuerst gepostet: HttpwebRequest: Wie finde ich eine Postleitzahl in Canada Post über eine WebRequest mit X-WWW-Form-Form?.

Nach Anthonywjones -Vorschlägen änderte ich meinen Code nach seinen Vorschlägen.

In einer Fortsetzung meiner Anfrage habe ich mit der Zeit bemerkt, dass der Inhaltsart der Kanada-Post eher wahrscheinlich ist "Anwendung/xhtml+xml, text/xml, text/html; charset = utf-8".

Meine Fragen sind:

  1. Wie können wir mit einer solchen Inhaltswebsite wandern?
  2. Müssen wir mit dem NamensvalueCollection -Objekt weitermachen?
  3. Laut Scott Lance, der mir in meiner vorherigen Frage großzügig kostbare Informationen zur Verfügung gestellt hat, muss der WebRequest die Art der Informationen zurückgeben, was auch immer der Inhaltstyp sein mag, fehlt mir hier etwas?
  4. Muss ich meinen Code wegen der Änderung des Inhalts ändern?

Hier ist mein Code, damit es einfacher ist, meinen Fortschritt zu verstehen.

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;
    }
}
}

Dieser Code gibt tatsächlich den HTML -Quellcode des Formulars zurück, den Sie mit den erforderlichen Informationen ausfüllen müssen, um mit der Post -Code -Suche zu verarbeiten. Ich wünsche mir den HTML -Quellcode oder was auch immer er mit dem gefundenen Postcode sein kann.

BEARBEITEN: Hier ist die WebException, die ich jetzt bekomme: "Ein Inhaltskörper mit dieser Art von Verb nicht zu senden. (Dies ist eine Übersetzung aus der französischen Ausnahme "Impossible d'Envoyer un Corps de Contenu AVec CE -Typ de Verbe.")

Hier ist mein Code:

    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;
}

Die Linie, die die Ausnahme verursacht, wird mit "=>" gezeigt. Es scheint, dass ich Get als Methode nicht verwenden kann, aber das wurde mir gesagt, dass ich ...

Irgendeine Idee, was ich hier fehlt? Ich versuche zu tun, was Justin (siehe Antwort) mir empfohlen hat.

Vielen Dank im Voraus für jede Hilfe! :-)

War es hilfreich?

Lösung

Als Einführung in die Welt des Screen-Scraping haben Sie einen sehr harten Fall ausgewählt! Die Suchseite von Canada Post funktioniert wie folgt:

  1. Die erste Seite ist ein Formular, das die Adresswerte akzeptiert
  2. Diese Seite veröffentlicht zu einer zweiten URL.
  3. Diese zweite URL wird wiederum (unter Verwendung einer HTTP 302 -Umleitung) in eine dritte URL weitergeleitet, die Ihnen tatsächlich die HTML -Antwort zeigt, die den Postcode enthält.

Wenn sich die Sache noch schlimmer macht, muss die Seite in Schritt 3 das Cookie in Schritt 1 kennen. Sie müssen also dasselbe verwenden CookieContainer für alle drei Anfragen (obwohl es möglicherweise ausreichen kann, dasselbe zu senden CookieContainer Nur bis #2 und #3).

Darüber hinaus müssen Sie möglicherweise auch zusätzliche HTTP -Header in diesen Anfragen senden, z. B. Akzeptanz. Ich vermute, wo Sie auf Probleme stoßen, ist, dass httpwebRequest standardmäßig für Sie transparent umgeleitet wird- aber wenn es transparent umleitet, kann es nicht die richtigen HTTP-Header hinzufügen, die erforderlich sind, um sich als Browser auszugeben.

Die Lösung besteht darin, die festzulegen HttpWebRequest's AllowAutoRedirect Eigentum zu falsch und die Umleitung selbst übernehmen. Mit anderen Worten, sobald die erste Anfrage eine Umleitung zurückgibt, müssen Sie die URL in der HttpWebResponse's Location: Header. Dann müssen Sie ein neues erstellen HttpWebRequest (Diesmal eine reguläre Get -Anfrage, nicht ein Beitrag) für diese URL. Denken Sie daran, dasselbe Cookie zu senden! (das CookieContainer Klasse macht das sehr einfach)

Möglicherweise müssen Sie auch eine zusätzliche Anfrage (in meiner Liste oben) stellen, um das Sitzungs -Cookie einzurichten. Wenn ich Sie wäre, würde ich davon ausgehen, dass dies erforderlich ist, um es einfach als Problem zu beseitigen und diesen Schritt später zu entfernen und zu sehen, ob Ihre Lösung noch funktioniert.

Sie möchten Fiddler herunterladen und verwenden (www.fiddlertool.com) um Ihnen bei all dem zu helfen. Mit Fiddler können Sie die HTTP -Anfragen ansehen, die über das Kabel übergehen, und ermöglicht Ihnen (über die Feature Builder -Funktion) HTTP -Anforderungen, damit Sie sehen können, welche Header tatsächlich erforderlich sind.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top