解析复杂的HTML表格

MCL*_*MCL 9 html javascript php html-table web-scraping

我正在尝试解析我大学提供的课程安排,以便将信息导入某种日历.可以在此处看到时间表的示例:http:
//www.asw-berufsakademie.de/fileadmin/download/download/Sked%20Stundenplan/WIA13-7.%20Block.html

在我看来,自动生成的HTML内容是一团糟,很难掌握.例如,表格主要是用rowpans和colspans构建的(代码中的单元格位置与浏览器中的实际视觉位置相比似乎是部分任意的).

我已经尝试过的:

  1. 要求大学的行政办公室分别提供更简单,更容易阅读的文件.当然这是不可能的,毕竟这意味着一分钟的额外努力.
  2. 研究用于生成HTML的原始工具.它被称为"sked Stundenplan Software".我找不到任何提示或工具来"逆转"生成过程.
  3. 寻找现有的解决方案,此时我发现了一些不适用于我的日程安排的工具(例如http://code.google.com/p/skd-schedule-parser/).在研究了这些工具的代码之后,我得出结论,它们必须是为其他/过时版本的sked设计的.
  4. 使用PHP解析HTML(主要使用DOMDocument).这有时起作用,但太不可靠......考虑的例外似乎是无限期的.

现在我不认为传统的HTML解析会让我走得太远,至少不会在可接受的开发时间内.我正在寻找的是从复杂的HTML表中获取信息的其他方法,例如YQL,或者可以使用col-/rowspans对这些表进行规范化的实用程序.因为我没有任何具体的想法,我主要是要求提供一些其他方法的提示或提示.

是否有其他更合适的方法来解析这些表格,还是我坚持使用传统的HTML解析?

编辑:

代表请求,我将粘贴一个原始代码示例...

本星期:
安排周

此代码的结果:http:
//pastebin.com/BJduUVtU

编辑2:
由于一些解析讨论,我还将添加我的PHP代码.这是我第一次使用PHP,所以它不是很复杂.它应该更深入地了解我在理论上解析表格的程度.实际工作发生在函数parseSkedTable()中,请专注于此.此外,我想指出评论中出现的"双重课程"一词,它描述了两个不同的课程同时发生(课程将在这样的时刻分开).这些课程的一个例子可以在第二周找到: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解析器:

    (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);
                        }
                    }
                } 
    
            }
    
        });
    
    
    });
    
    Run Code Online (Sandbox Code Playgroud)

    }(jQuery的));

  2. JS解析器使用 我的位置信息,实现了rambo编码器的想法

Ste*_*ens 0

许多开发人员使用 HTML Agility Pack 来解析 HTML:

http://htmlagilitypack.codeplex.com/