刮没没有HTML的纯文本文件?

时间:2011-12-08 14:13:30

标签: php screen-scraping

我在纯文本文件中有以下数据:

1.  Value
Location :  Value
Owner:  Value
Architect:  Value

2.  Value
Location :  Value
Owner:  Value
Architect:  Value

... upto 200+ ...

每个细分的编号和单词值会发生变化。

现在我需要将这些数据插入到MySQL数据库中。

您是否有关于我如何遍历和抓取它的建议,以便我可以获得数字旁边的文本值以及“位置”,“所有者”,“架构师”的价值?

似乎很难处理DOM抓取类,因为没有HTML标记。

6 个答案:

答案 0 :(得分:5)

如果数据经常结构化,您可以使用fscanf从文件中扫描它们。

/* Notice the newlines at the end! */
$format = <<<FORMAT
%d. %s
Location :  %s
Owner:  %s
Arcihtect:  %s


FORMAT;

$file = fopen('file.txt', 'r');
while ($data = fscanf($file, $format)) {
    list($number, $title, $location, $owner, $architect) = $data;
    // Insert the data to database here
}
fclose($file);

有关fscanf in docs的更多信息。

答案 1 :(得分:4)

如果每个块具有相同的结构,您可以使用file()函数执行此操作:http://nl.php.net/manual/en/function.file.php

$data = file('path/to/file.txt');

这样,每一行都是数组中的一个项目,你可以遍历它。

for ($i = 0; $i<count($data); $i+=5){
    $valuerow = $data[$i];
    $locationrow = $data[$i+1];
    $ownerrow = $data[$i+2];
    $architectrow = $data[$i+3];
    // strip the data you don't want here, and instert it into the database.
}

答案 2 :(得分:3)

这将适用于一个非常简单的有状态的面向行的解析器。累积的每一行都将数据解析为数组()。当某些东西告诉你正在使用新记录时,你会转储你解析的内容并重新开始。

面向行的解析器有一个很好的属性:它们需要很少的内存和最重要的,恒定的内存。他们可以毫不费力地处理千兆字节的数据。我正在管理一堆生产服务器,没有什么比那些将整个文件插入内存的脚本更糟糕了(然后填充带有解析内容的数组,这需要原始文件大小超过内存的两倍)。

这种方法很有效,而且几乎不会破碎:

<?php
$in_name = 'in.txt';
$in = fopen($in_name, 'r') or die();

function dump_record($r) {
    print_r($r);
}

$current = array();
while ($line = fgets($in)) {
    /* Skip empty lines (any number of whitespaces is 'empty' */
    if (preg_match('/^\s*$/', $line)) continue;

    /* Search for '123. <value> ' stanzas */
    if (preg_match('/^(\d+)\.\s+(.*)\s*$/', $line, $start)) {
        /* If we already parsed a record, this is the time to dump it */
        if (!empty($current)) dump_record($current);

        /* Let's start the new record */
        $current = array( 'id' => $start[1] );
    }
    else if (preg_match('/^(.*):\s+(.*)\s*/', $line, $keyval)) {
        /* Otherwise parse a plain 'key: value' stanza */
        $current[ $keyval[1] ] = $keyval[2];
    }
    else {
        error_log("parsing error: '$line'");
    }
}

/* Don't forget to dump the last parsed record, situation
 * we only detect at EOF (end of file) */
if (!empty($current)) dump_record($current);

fclose($in);
?>

function dump_record中,你需要一些适合自己口味的东西,比如打印一个正确格式化的INSERT SQL语句。

答案 3 :(得分:2)

这会给你你想要的东西,

$array = explode("\n\n", $txt);
foreach($array as $key=>$value) {
    $id_pattern = '#'.($key+1).'. (.*?)\n#';
    preg_match($id_pattern, $value, $id);

    $location_pattern = '#Location \: (.*?)\n#';
    preg_match($location_pattern, $value, $location);


    $owner_pattern = '#Owner\: (.*?)\n#';
    preg_match($owner_pattern, $value, $owner);


    $architect_pattern = '#Architect\: (.*?)#';
    preg_match($architect_pattern, $value, $architect);

    $id = $id[1];
    $location = $location[1];
    $owner = $owner[1];
    $architect = $architect[1];

    mysql_query("INSERT INTO table (id, location, owner, architect) VALUES ('".$id."', '".$location."', '".$owner."', '".$architect."')");
//Change MYSQL query

}

答案 4 :(得分:0)

同意Topener解决方案,这是一个例子,如果每个块是4行+空行:

$data = file('path/to/file.txt');
$id = 0;
$parsedData = array();
foreach ($data as $n => $row) {
  if (($n % 5) == 0) $id = (int) $row[0];
  else {
    $parsedData[$id][$row[0]] = $row[1];
  }
}

结构将方便使用,对于MySQL或whatelse。我没有添加代码来删除第一段中的冒号。

祝你好运!

答案 5 :(得分:0)

preg_match_all("/(\d+)\.(.*?)\sLocation\s*\:\s*(.*?)\sOwner\s*\:\s*(.*?)\sArchitect\s*\:\s*(.*?)\s?/i",$txt,$m);

$matched = array();

foreach($m[1] as $k => $v) {

    $matched[$v] = array(
        "location" => trim($m[2][$v]),
        "owner" => trim($m[3][$v]),
        "architect" => trim($m[4][$v])
    );

}