9

情報をある種のカレンダーにインポートするために、大学から提供された授業スケジュールを解析しようとしています。スケジュールの例は、 http ://www.asw-berufsakademie.de/fileadmin/download/download/Sked%20Stundenplan/WIA13-7.%20Block.html で確認できます。

私の意見では、自動生成された HTML コンテンツはごちゃごちゃしていて、把握するのが非常に困難です。たとえば、テーブルは主に rowspan と colspan で構築されます (コード内のセルの位置は、ブラウザーでの実際の視覚的な位置と比較すると、部分的に恣意的に見えます)。

私がすでに試したこと:

  1. 大学の事務局に、よりシンプルで読みやすいファイルを別に提供するよう依頼する。もちろん、これは不可能です。結局のところ、1 分間の追加作業が必要になるからです。
  2. HTML の生成に使用された元のツールの調査。それは「sked Stundenplan ソフトウェア」と呼ばれます。生成プロセスを「逆」にするためのヒントやツールは見つかりませんでした。
  3. 既存のソリューションを探していますが、その時点で、私のスケジュールでは機能しないツール ( http://code.google.com/p/skd-schedule-parser/など) を見つけました。これらのツールのコードを調べた結果、これらのツールは sked の他のバージョンまたは古いバージョン用に設計されたに違いないと結論付けました。
  4. HTML を PHP で解析します (主に DOMDocument を使用)。それは時々うまくいきましたが、信頼性が低すぎました...考慮すべき例外は無期限のようです.

今のところ、従来の HTML 構文解析では、少なくとも許容できる開発時間では、うまくいかないと思います。私が探しているのは、YQL のような複雑な HTML テーブルから情報を取得する他の方法、またはそのようなテーブルを列/行スパンで正規化できるユーティリティです。具体的なことは何も考えていないので、主に別のアプローチのヒントやヒントを求めています。

そのようなテーブルを解析するための他のより適切な方法はありますか、それとも従来の HTML 解析にこだわっていますか?

編集:

リクエストに代わって、生のコードの例を貼り付けます...

今週:
スケジュールの週

このコードの結果:
http://pastebin.com/BJduUVtU

編集 2:
解析に関する議論があったため、PHP コードも追加します。PHPは初めてなので、あまり洗練されていません。むしろ、理論的にテーブルを解析することで私がどこまで来たかについての洞察を与えるべきです. 実際の作業は関数parseSkedTable()で行われます。この関数に集中してください。また、コメントに表示される「ダブルコース」という用語を指摘したいと思います。これは、2 つの異なるコースが同時に行われていることを表します (そのような瞬間にクラスが分割されます)。これらのコースの例は、第 2 週にここにあります:
http://www.asw-berufsakademie.de/fileadmin/download/download/Sked%20Stundenplan/WIB14-4.%20Block.html

次のようになります。 ダブルコース

その週の対応するHTML コードは、http: //pastebin.com/gLTWz5KUからもアクセスできます。

そして今、PHPコード(最初の言語でコメントを表現するのにすでに苦労していたので、コメントを翻訳するのに苦労しました...それでも役立つことを願っています):
http://pastebin.com/Nzi8m2v8

アップデート

これまでのところ、構文解析の問題に対するいくつかの解決策があり、それぞれ JavaScript を使用しています。JavaScript (ブラウザでレンダリングされたデータを使用できるため、ここでは特に強力です) が HTML から信頼できる情報を取得する唯一の効率的な方法のように思われるため、私は現在、ある種のヘッドレス ブラウザまたはレンダリング エンジンを実装する方法を探しています。 x10hosting.com の無料サーバーで。残念ながら、softaculousが提供する以外のソフトウェアをインストールすることも、PHP のexec()コマンドを使用することも許可されていません。
どんなアイデアでも大歓迎です!

完全を期すために、現在まで存在する両方のソリューションを投稿します。

  1. Pierre DuboisによるjQueryパーサー

    (関数 ($) { $(document).ready(function() {

        var _pe = window.pe || {
            fn : {}
        };
    
        var tblNumber = 0; // Just a incremental number to identify the schedule item with the table
    
        // For each table
        $('table').each(function () {
    
            $('#output').append('Parsing the table number: ' + tblNumber + '<br>');
            // console.log('Parsing the table number: ' + tblNumber);
            tblNumber += 1;
    
            var currentTable = this;
    
    
            // Parser the complex table
            _pe.fn.parsertable.parse($(currentTable));
    
            // Retrieve the parsed data
            var parsedData = $(currentTable).data().tblparser;
    
            //
            // Information about the column structure, nice that is consistent
            //
    
            // Day: Cell index position (0 based)
            // Mo: 3
            // Di: 7
            // Mi: 11
            // Do: 15
            // Fr: 19
            // Sa: 23
    
            // Title Location at Row index position "0"
    
            // "i" represent the middle column position
            for (var i = 3; i < 24; i += 4) {
    
                var currentDay;
    
                // Get the day
                currentDay = $(parsedData.row[0].cell[i].elem).text();
    
                $('#output').append('  Day: ' + currentDay + '<br>');
                // console.log('Day: ' + currentDay);
    
                // Get all the events for that day, excluding the first row and the last row
                for (var j = 1; j < parsedData.col[i].cell.length - 2; j += 1) {
    
                    // First column 
                    if (parsedData.col[i - 1].cell[j - 1].uid !== parsedData.col[i - 1].cell[j].uid ) {
    
                        // Get the content of that cell and remove ending space
                        var event = $(parsedData.col[i - 1].cell[j].elem).text().trim();
    
                        if (event.length > 0) {
                            $('#output').append('  + Event: ' + event + '<br>');
                            // console.log('Event: ' + event);
                        }
                    }
    
                    // Second Column
                    if (parsedData.col[i].cell[j - 1].uid !== parsedData.col[i].cell[j].uid &&
                        parsedData.col[i - 1].cell[j].uid !== parsedData.col[i].cell[j].uid) {
    
                        // Get the content of that cell and remove ending space
                        var event = $(parsedData.col[i].cell[j].elem).text().trim();
    
                        if (event.length > 0) {
                            $('#output').append('  + Event: ' + event + '<br>');
                            // console.log('Event: ' + event);
                        }
                    }
    
                    // Third Column
                    if (parsedData.col[i + 1].cell[j - 1].uid !== parsedData.col[i + 1].cell[j].uid &&
                        parsedData.col[i].cell[j].uid !== parsedData.col[i + 1].cell[j].uid) {
    
                        // Get the content of that cell and remove ending space
                        var event = $(parsedData.col[i + 1].cell[j].elem).text().trim();
    
                        if (event.length > 0) {
                            $('#output').append('  + Event: ' + event + '<br>');
                            // console.log('Event: ' + event);
                        }
                    }
                } 
    
            }
    
        });
    
    
    });
    

    }(jQuery));

  2. rambo coderのアイデアを実現する、私による位置情報を使用したJSパーサー

4

6 に答える 6

1

ここでブラウザのレンダリング/レイアウトエンジンを利用できます。

http://phantomjs.org/を使用して、WebページのDOMでJavaScriptを実行できるヘッドレスブラウザにアクセスします。

jqueryを少し使用すると、残りの擬似コードを簡単に実装できます。

foreach (td.t as dateElement) {
    //parse date from element text
    //use pixel position + dimensions to calc pixel coord of center
    // save this center in a list along with the date
}

foreach (td.v as calendarEntryElement) {
    //parse time + other stuff from element text
    //use pixel position to find the closest date element in that list(it must be the closest one above)
}

すべてがネストされた長方形であり、すべてテーブルを介して行われるため、ここでは位置情報は非常に信頼できると思います。

phantomjsを使用する必要はありません。ブラウザを手動で簡単に実行し、ローカルサーバーにリクエストを送信して結果を収集することができます。

大まかに次のようないくつかのシェルコマンド

firefox file://foo123.html

あなたが<script>彼らのウェブページの1つの終わりにいくつかの習慣を加えてそれを保存したところ。

于 2012-10-22T01:36:28.833 に答える
0

多くの開発者は HTML Agility Pack を使用して HTML を解析します。

http://htmlagilitypack.codeplex.com/

于 2012-10-20T13:37:40.527 に答える
0

興味深い複雑なテーブル。レイアウト テーブルとデータ テーブルの組み合わせ。

これは、解決策が jQuery にあり、 Web Experience Toolkit Projectで利用可能な同じ複雑なテーブル パーサーを使用するのに役立つ場合があります。そのテーブル パーサーを使用すると、スケジュール データを取得できます。実行する必要があるのは、カレンダー アプリにインポートするためにスケジュール アイテムのコンテンツを解析することだけです。

このソリューションでは、行ではなくを使用してスケジュール項目を取得します

作業例:http://jsfiddle.net/3t2A8/2/

スケジュール アイテムを抽出して表示するために使用される JavaScript コードは次のとおりです。

(function ($) {
    $(document).ready(function() {

        var _pe = window.pe || {
            fn : {}
        };

        var tblNumber = 0; // Just a incremental number to identify the schedule item with the table

        // For each table
        $('table').each(function () {

            $('#output').append('Parsing the table number: ' + tblNumber + '<br>');
            // console.log('Parsing the table number: ' + tblNumber);
            tblNumber += 1;

            var currentTable = this;


            // Parser the complex table
            _pe.fn.parsertable.parse($(currentTable));

            // Retrieve the parsed data
            var parsedData = $(currentTable).data().tblparser;

            //
            // Information about the column structure, nice that is consistent
            //

            // Day: Cell index position (0 based)
            // Mo: 3
            // Di: 7
            // Mi: 11
            // Do: 15
            // Fr: 19
            // Sa: 23

            // Title Location at Row index position "0"

            // "i" represent the middle column position
            for (var i = 3; i < 24; i += 4) {

                var currentDay;

                // Get the day
                currentDay = $(parsedData.row[0].cell[i].elem).text();

                $('#output').append('  Day: ' + currentDay + '<br>');
                // console.log('Day: ' + currentDay);

                // Get all the events for that day, excluding the first row and the last row
                for (var j = 1; j < parsedData.col[i].cell.length - 2; j += 1) {

                    // First column 
                    if (parsedData.col[i - 1].cell[j - 1].uid !== parsedData.col[i - 1].cell[j].uid ) {

                        // Get the content of that cell and remove ending space
                        var event = $(parsedData.col[i - 1].cell[j].elem).text().trim();

                        if (event.length > 0) {
                            $('#output').append('  + Event: ' + event + '<br>');
                            // console.log('Event: ' + event);
                        }
                    }

                    // Second Column
                    if (parsedData.col[i].cell[j - 1].uid !== parsedData.col[i].cell[j].uid &&
                        parsedData.col[i - 1].cell[j].uid !== parsedData.col[i].cell[j].uid) {

                        // Get the content of that cell and remove ending space
                        var event = $(parsedData.col[i].cell[j].elem).text().trim();

                        if (event.length > 0) {
                            $('#output').append('  + Event: ' + event + '<br>');
                            // console.log('Event: ' + event);
                        }
                    }

                    // Third Column
                    if (parsedData.col[i + 1].cell[j - 1].uid !== parsedData.col[i + 1].cell[j].uid &&
                        parsedData.col[i].cell[j].uid !== parsedData.col[i + 1].cell[j].uid) {

                        // Get the content of that cell and remove ending space
                        var event = $(parsedData.col[i + 1].cell[j].elem).text().trim();

                        if (event.length > 0) {
                            $('#output').append('  + Event: ' + event + '<br>');
                            // console.log('Event: ' + event);
                        }
                    }
                } 

            }

        });


    });

}(jQuery));

「ダブルコース」テーブルに出力されます

Parsing the table number: 0
  Day: Mo, 22.10.2012
  + Event: 12:45 - 14:15 Uhr
      Vorlesung
      DATMOD Gr. 1
      HG: 13
  + Event: 12:45 - 14:15 Uhr
      Vorlesung
      PROG III Gr. 2
      HG: 15
  + Event: 14:30 - 16:00 Uhr
      Vorlesung
      DATMOD Gr. 1
      HG: 13
  + Event: 14:30 - 16:00 Uhr
      Vorlesung
      PROG III Gr. 2
      HG: 15
  + Event: 16:15 - 17:45 Uhr
      Vorlesung
      DATMOD Gr. 2
      HG: 13
  + Event: 16:15 - 17:45 Uhr
      Vorlesung
      PROG III Gr. 1
      HG: 15
  + Event: 18:00 - 19:30 Uhr
      Vorlesung
      DATMOD Gr. 2
      HG: 13
  + Event: 18:00 - 19:30 Uhr
      Vorlesung
      PROG III Gr. 1
      HG: 15
  Day: Di, 23.10.2012
  + Event: 9:00 - 10:30 Uhr
      Vorlesung
      DATMOD Gr. 2
      HG: 13
  + Event: 10:45 - 12:15 Uhr
      Vorlesung
      DATMOD Gr. 2
      HG: 13
  + Event: 12:45 - 14:15 Uhr
      Vorlesung
      DATMOD Gr. 1
      HG: 13
  + Event: 14:30 - 16:00 Uhr
      Vorlesung
      DATMOD Gr. 1
      HG: 13
  + Event: 16:15 - 17:45 Uhr
      Vorlesung
      PROG III Gr. 1
      HG: 15
  + Event: 18:00 - 19:30 Uhr
      Vorlesung
      PROG III Gr. 1
      HG: 15
  Day: Mi, 24.10.2012
  + Event: 9:00 - 10:30 Uhr
      Vorlesung
      DATMOD
      HG: 09
  + Event: 10:45 - 12:15 Uhr
      Vorlesung
      DATMOD
      HG: 09
  + Event: 12:45 - 14:15 Uhr
      Vorlesung
      IuF
      HG: 09
  + Event: 14:30 - 16:00 Uhr
      Vorlesung
      IuF
      HG: 09
  Day: Do, 25.10.2012
  + Event: 12:45 - 14:15 Uhr
      Vorlesung
      PROG III Gr. 2
      HG: 15
  + Event: 14:30 - 16:00 Uhr
      Vorlesung
      PROG III Gr. 2
      HG: 15
  + Event: 16:15 - 17:45 Uhr
      Vorlesung
      Linux Gr. 2
      HG: 15
  + Event: 18:00 - 19:30 Uhr
      Vorlesung
      Linux Gr. 2
      HG: 15
  Day: Fr, 26.10.2012
  Day: Sa, 27.10.2012
  + Event: 9:00 - 11:15 Uhr
      Klausur
      MP INT RW
      HG: 14

:-)

于 2012-10-23T19:45:45.083 に答える
0

疑似PHP

class ScheduleTableParser {
  buildTimetableFromTable() {
    //Trivial
    Parse Day Rowspans, Day Names, Dates into $this->days;
    e.g. $days[0]['rowspan'] = 4 for Monday 22/10/2012

    //Extract Lessons      
    $tr = 0;
    foreach tr {
      $td = 0;
      foreach td{
        if(td.class = 'v') {
          parseClass($td,$tr,$tdDOMObject);
        }
        $td++;
      }
    }
 }
 parseClass($td,$tr,$tdDOMObject) {
   //Trivial
   Get the Class Name Etc   

   //Calculate Time
   $time = 9:00 + 5mins*tr;
   $tr = $tr - 2;
   $i = 0;
   while($tr > 0) {
     $tr - $this->days[$i]['rowspan'];
     $day = $this->days[$i]['name'];
     $date = $this->days[$i]['date'];
     $i++;
   }
 }
}
于 2012-10-23T20:17:38.957 に答える