使用file_get_contents将html表格解析为php数组

16

我正在尝试解析这里显示的表格,将其转换为多维 php 数组。我正在使用以下代码,但出于某种原因它返回一个空数组。在网上搜索后,我找到了这个网站,其中包含我获取 parseTable() 函数的方法。从阅读该网站上的评论中,我看到该函数运行完美。因此我认为问题在于我从 file_get_contents() 获取 HTML 代码的方式有误。你对我做错了什么有什么想法吗?

<?php

$data = file_get_contents('http://flow935.com/playlist/flowhis.HTM');

function parseTable($html)
{
  // Find the table
  preg_match("/<table.*?>.*?<\/[\s]*table>/s", $html, $table_html);

  // Get title for each row
  preg_match_all("/<th.*?>(.*?)<\/[\s]*th>/", $table_html[0], $matches);
  $row_headers = $matches[1];

  // Iterate each row
  preg_match_all("/<tr.*?>(.*?)<\/[\s]*tr>/s", $table_html[0], $matches);

  $table = array();

  foreach($matches[1] as $row_html)
  {
    preg_match_all("/<td.*?>(.*?)<\/[\s]*td>/", $row_html, $td_matches);
    $row = array();
    for($i=0; $i<count($td_matches[1]); $i++)
    {
      $td = strip_tags(html_entity_decode($td_matches[1][$i]));
      $row[$row_headers[$i]] = $td;
    }

    if(count($row) > 0)
      $table[] = $row;
  }
  return $table;
}

$output = parseTable($data);

print_r($output);

?>

我希望我的输出数组看起来像这样:

1
--> 11:33AM
--> DEV
--> 在暗中
2 --> 11:29AM --> LIL' WAYNE --> 她会
3 --> 11:26AM --> KARDINAL OFFISHALL --> NUMBA 1 (TIDE IS HIGH)

1
不努力就是-1分。不要只是贴一大块代码,然后让别人去找出问题并修复它。你应该先确定问题所在。 - NullUserException
这个 [mcve] 已经因为示例输入链接失效而被破坏。 - undefined
2个回答

51

不要用正则表达式解析HTML! 相反,让一个HTML解析库为您处理标记的结构。

我建议您尝试使用Simple HTML DOM (http://simplehtmldom.sourceforge.net/)。它是一个专门为解决PHP中这种网络爬虫问题而编写的库。通过使用这样的库,您可以用更少的代码行编写爬虫程序,无需担心创建有效的正则表达式。

基本上,使用Simple HTML DOM只需编写如下代码:

$html = file_get_html('http://flow935.com/playlist/flowhis.HTM');
foreach($html->find('tr') as $row) {
   // Parse table row here
}

这可以进一步扩展以捕获您的数据以某种格式,例如创建一个包含艺术家和相应标题的数组,如下所示:

<?php
require('simple_html_dom.php');

$table = array();

$html = file_get_html('http://flow935.com/playlist/flowhis.HTM');
foreach($html->find('tr') as $row) {
    $time = $row->find('td',0)->plaintext;
    $artist = $row->find('td',1)->plaintext;
    $title = $row->find('td',2)->plaintext;

    $table[$artist][$title] = true;
}

echo '<pre>';
print_r($table);
echo '</pre>';

?>

我们可以看到这段代码很容易地改变为以任何其他方式重新格式化数据。


那个完美地运行了。但是我需要创建一个多维数组,就像原问题底部所示的那样。 - Farhan Ahmad
你有没有查看simplehtmldom网站上的“Scraping Slashdot!”示例?就我所知,它回答了那个问题。 - jsalonen
1
好的,我添加了一个进一步的例子,但这就是我的极限了。剩下的部分就留给你自己去解决吧。 - jsalonen
1
是的,我弄明白了。感谢您提供的进一步示例。 - Farhan Ahmad
使用simplehtmldom而不是正则表达式很有趣,不是吗? :) - jsalonen
如果 HTML 表格进行了分页,会怎么样? - Saurabh

22

我尝试了simple_html_dom,但在处理更大文件和重复调用函数时,我在php 5.3上遇到了zend_mm_heap_corrupted错误。我还尝试了preg_match_all,但是在一个较大的(5000行)HTML文件中失败了,这个文件只包含我的HTML表格约400行。

我正在使用这个方法,它运行速度快且不会出错。

$dom = new DOMDocument();  

//load the html  
$html = $dom->loadHTMLFile("htmltable.html");  

  //discard white space   
$dom->preserveWhiteSpace = false;   

  //the table by its tag name  
$tables = $dom->getElementsByTagName('table');   


    //get all rows from the table  
$rows = $tables->item(0)->getElementsByTagName('tr');   
  // get each column by tag name  
$cols = $rows->item(0)->getElementsByTagName('th');   
$row_headers = NULL;
foreach ($cols as $node) {
    //print $node->nodeValue."\n";   
    $row_headers[] = $node->nodeValue;
}   

$table = array();
  //get all rows from the table  
$rows = $tables->item(0)->getElementsByTagName('tr');   
foreach ($rows as $row)   
{   
   // get each column by tag name  
    $cols = $row->getElementsByTagName('td');   
    $row = array();
    $i=0;
    foreach ($cols as $node) {
        # code...
        //print $node->nodeValue."\n";   
        if($row_headers==NULL)
            $row[] = $node->nodeValue;
        else
            $row[$row_headers[$i]] = $node->nodeValue;
        $i++;
    }   
    $table[] = $row;
}   

var_dump($table);

这段代码对我很有效。 原始代码示例在此处。

http://techgossipz.blogspot.co.nz/2010/02/how-to-parse-html-using-dom-with-php.html


你应该使用array_shift($table)来移除数组的第一个元素,因为它是空的,即[0] => array(0) {}。这是因为你在$rows中获取了所有的tr标签,包括带有th标签的那个。我建议进行修改。 - Oleg Abrazhaev
我正在使用 PHP 5.6.31 中的 DOM,但是发现 $rows = $tables->item(0)->getElementsByTagName('tr') 的结果不包含任何 <td> 标签,导致后续的 $cols = $row->getElementsByTagName('td') 无法获取到数据。您有什么想法吗?为什么我的第一次调用 getElementsByTagName() 似乎会去掉 HTML 标签? - Tony

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接