XamarinのHtmlAgilityPackでAJAXを待つ

ajax c# html-agility-pack xamarin

質問

私は以前に尋ねられたような質問がありますが、少し異なります。私はこのウェブサイトからデータを削り取ろうとしていますが、問題はAJAXがロードされているようです。そのため、私のアプリケーションでは、私が探しているHTMLのIDとクラスを見つけることができません。

これを再現するには、要素を調べるか、ソースを表示します。ソースを見ている間、私は要素を調べている間よりずっと少なく見ています。

私は、AJAXを含むファイルを追跡して、F12を押して、ネットワークタブに行き、XHRを選択して、このhtmlをロードすることができたと思っていましたが、それを見つけることができません。

私の質問は:どのように私はこのデータを取得するか、またはデータを収集するためにどのファイルが使用されているかを調べることです。

私のコードの例(私はTimetable_toolbar_elementSelect_popup0を見つけることができません):

private async Task GetHtmlDocument(string url)
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
            //request.Credentials = new LoginCredentials().Credentials;

            try
            {
                WebResponse myResponse = await request.GetResponseAsync();
                HtmlDocument htmlDoc = new HtmlDocument();
                htmlDoc.OptionFixNestedTags = true;
                htmlDoc.Load(myResponse.GetResponseStream());
                var test = htmlDoc.GetElementbyId("Timetable_toolbar_elementSelect_popup0");
            }
            catch (Exception e)
            {
            }
        }

受け入れられた回答

Webリクエストを使用してajaxメソッドを呼び出すソリューション。

だから私は退屈して、それのほとんどを考え出した。以下に欠けているのは、idによってKlaseを特定する方法です。以下の例は、クラース '1GLD'をフェッチします。私たちがクッキーを必要とする理由は、クラースを取り出す学校を知りたいという要求に応えるためです。また、以下のコードはJSONを返します。これはHTMLではなく、私たちが呼び出すajaxメソッドです。

CookieContainer cookies = new CookieContainer();
try
{
    string webAddr = "https://roosters.windesheim.nl/";
    var httpWebRequest = (HttpWebRequest)WebRequest.Create(webAddr);
    httpWebRequest.ContentType = "application/json; charset=utf-8";
    httpWebRequest.Method = "POST";
    httpWebRequest.CookieContainer = cookies;        
    httpWebRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
    httpWebRequest.Headers.Add("X-Requested-With", "XMLHttpRequest");

    var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
    using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
    {
        cookies.Add(httpWebRequest.CookieContainer.GetCookies(httpWebRequest.RequestUri));
    }
}
catch (WebException ex)
{
    Console.WriteLine(ex.Message);
}

//According to my web debugger the cookie will last until the 10th of December. So need to fix a new cookie until then.
//I noticed the url used unixtimestamps at the end of the url. So we just add the unixtimestamp at the end for each request.
long unixTimeStamp = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds() - 100;

//we are now ready to call the ajax method and get the JSON.
try
{
    string webAddr = "https://roosters.windesheim.nl/WebUntis/Timetable.do?request.preventCache="+unixTimeStamp.ToString();
    var httpWebRequest = (HttpWebRequest)WebRequest.Create(webAddr);
    httpWebRequest.ContentType = "application/x-www-form-urlencoded; charset=utf-8";
    httpWebRequest.Method = "POST";
    httpWebRequest.CookieContainer = cookies;
    httpWebRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
    httpWebRequest.Headers.Add("X-Requested-With", "XMLHttpRequest");

    using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
    {
        string json = "ajaxCommand=getWeeklyTimetable&elementType=1&elementId=13090&date=20171126&formatId=7&departmentId=0&filterId=-2";

        //The command below will return a JSON datastructure containing all the klases and their relevant ID.
        //string otherJson = "ajaxCommand=getPageConfig&type=1&filter=-2"


        streamWriter.Write(json);
        streamWriter.Flush();
    }


    var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
    using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
    {
        var responseText = streamReader.ReadToEnd();
        //THE RESULTS GETS PRINTED HERE.
        Console.Write(responseText);
    }
}
catch (WebException ex)
{
    Console.WriteLine(ex.Message);
}

Seleniumと他のソリューションFirefoxのドライバ。

これは簡単な方法です。それには時間がかかります。すべてのスレッドがスリープする必要はありません。これはあなたが要求したのと同じようにisnteadで動作するHTMLを与えます。しかし、私はそれが最後のforeachループで必要であることが分かった。

CookieContainer cookies = new CookieContainer();
try
{
    string webAddr = "https://roosters.windesheim.nl/";
    var httpWebRequest = (HttpWebRequest)WebRequest.Create(webAddr);
    httpWebRequest.ContentType = "application/json; charset=utf-8";
    httpWebRequest.Method = "POST";
    httpWebRequest.CookieContainer = cookies;        
    httpWebRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
    httpWebRequest.Headers.Add("X-Requested-With", "XMLHttpRequest");

    var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
    using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
    {
        cookies.Add(httpWebRequest.CookieContainer.GetCookies(httpWebRequest.RequestUri));
    }
}
catch (WebException ex)
{
    Console.WriteLine(ex.Message);
}

//According to my web debugger the cookie will last until the 10th of December. So need to fix a new cookie until then.
//I noticed the url used unixtimestamps at the end of the url. So we just add the unixtimestamp at the end for each request.
long unixTimeStamp = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds() - 100;

//we are now ready to call the ajax method and get the JSON.
try
{
    string webAddr = "https://roosters.windesheim.nl/WebUntis/Timetable.do?request.preventCache="+unixTimeStamp.ToString();
    var httpWebRequest = (HttpWebRequest)WebRequest.Create(webAddr);
    httpWebRequest.ContentType = "application/x-www-form-urlencoded; charset=utf-8";
    httpWebRequest.Method = "POST";
    httpWebRequest.CookieContainer = cookies;
    httpWebRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
    httpWebRequest.Headers.Add("X-Requested-With", "XMLHttpRequest");

    using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
    {
        string json = "ajaxCommand=getWeeklyTimetable&elementType=1&elementId=13090&date=20171126&formatId=7&departmentId=0&filterId=-2";

        //The command below will return a JSON datastructure containing all the klases and their relevant ID.
        //string otherJson = "ajaxCommand=getPageConfig&type=1&filter=-2"


        streamWriter.Write(json);
        streamWriter.Flush();
    }


    var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
    using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
    {
        var responseText = streamReader.ReadToEnd();
        //THE RESULTS GETS PRINTED HERE.
        Console.Write(responseText);
    }
}
catch (WebException ex)
{
    Console.WriteLine(ex.Message);
}

最後の更新

セレンのソリューションを使用して、私はすべてのコースのIDを取得することができました。私はあなたのajaxとWebリクエストでそれを使用できるように、 ここにファイルを含めました。


人気のある回答

私はこれをコメントとして残すつもりだった。しかし、それはあまりにも大きくなり過ぎてひどくフォーマットされました。だからここに行く。

まず、このサイトは、ajaxコマンドで呼び出されるjavascriptを使用して動的に更新されます。

セッションを開き、SESSIONIDと現在の "暗号化された"スクールネームを含むCookieを保存することができれば、ajaxコマンドをそのように呼び出すことができます。

    https://roosters.windesheim.nl/ajaxCommand=getWeeklyTimetable&elementType=1&elementId=13090&date=20171126&formatId=7&departmentId=0&filterId=-2

しかし、これはelementTypeが何で、どのelementIdが何であるかを知る必要があります。

この場合、elementIdは1GLDに等しいときにKlasを参照します。また、formatID(7)はRoosterformaatが "Beknopt"に等しいときに参照します。残りの変数が何をしているのか把握しなければなりません。さらに重要な点は、サーバーに有効なajaxコマンドを作成することができれば、htmlを応答として取得できないことです。これはJSONでデータを受け取ることになります。

あなたが望むことを行う最も簡単な方法は、すべてのクラスを別々のファイルに入れることです 。それを基準点として使用してください。他のオプションも同じです。

そして、 Seleniumと phantomjs.orgのようなヘッドレスブラウザを使いましょう 。この方法で、スクラップしたいクラスを見つけてクリックすることができます。 HTMLをHtmlAgilityPack.HtmlDocumentにロードしてから、必要な処理を行います。セレン/ PhantomJSあなたのクッキーを追跡するまで。この方法は遅くなりますが、やりやすくなります。

EDITウェブリクエストからのクッキーの保存 - 簡単な方法。

私はこの主題に熱心ではない。しかし、OPは尋ねた。もし誰かがそれを行う良い方法があれば、編集してください。

    https://roosters.windesheim.nl/ajaxCommand=getWeeklyTimetable&elementType=1&elementId=13090&date=20171126&formatId=7&departmentId=0&filterId=-2



ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ