La mejor forma de analizar múltiples sitios web de texto plano que no contienen HTML

Estoy buscando una forma de leer múltiples (más de 50) sitios web de texto plano y analizar solo cierta información en una tabla html, o como un archivo csv. Cuando digo “texto plano” me refiero a que, aunque es una dirección web, no tiene ningún html asociado. Esto sería un ejemplo de la fuente. Soy bastante nuevo en esto y estaba buscando ayuda para ver cómo se podía hacer esto.

update-token:179999210 vessel-name:Name Here vessel-length:57.30 vessel-beam:14.63 vessel-draft:3.35 vessel-airdraft:0.00 time:20140104T040648.259Z position:25.04876667 -75.57001667 GPS river-mile:sd 178.71 rate-of-turn:0.0 course-over-ground:58.5 speed-over-ground:0.0 ais-367000000 { pos:45.943912 -87.384763 DGPS cog:249.8 sog:0.0 name:name here call:1113391 imo:8856857 type:31 dim:10 20 4 5 draft:3.8 destination: } ais-367000000 { pos:25.949652 -86.384535 DGPS cog:105.6 sog:0.0 name:CHRISTINE call:5452438 type:52 status:0 dim:1 2 3 4 draft:3.0 destination:IMTT ST.ROSE eta:06:00 } 

Gracias por cualquier sugerencia que puedan tener.

Puede que me esté faltando completamente el punto aquí, pero aquí es cómo puedes tomar los contenidos (suponiendo que los tengas como una cadena) y ponerlos en una matriz de php / valor. “Codifiqué” la cadena que tenías, y cambié un valor (la clave ais-3670000 parecía repetirse, y eso hace que el segundo objeto sobrescriba el primero).

Este es un analizador muy básico que asume un formato como el descrito anteriormente. Doy el resultado debajo del código:

 "; $s="update-token:179999210 vessel-name:Name Here vessel-length:57.30 vessel-beam:14.63 vessel-draft:3.35 vessel-airdraft:0.00 time:20140104T040648.259Z position:25.04876667 -75.57001667 GPS river-mile:sd 178.71 rate-of-turn:0.0 course-over-ground:58.5 speed-over-ground:0.0 ais-367000000 { pos:45.943912 -87.384763 DGPS cog:249.8 sog:0.0 name:name here call:1113391 imo:8856857 type:31 dim:10 20 4 5 draft:3.8 destination: } ais-367000001 { pos:25.949652 -86.384535 DGPS cog:105.6 sog:0.0 name:CHRISTINE call:5452438 type:52 status:0 dim:1 2 3 4 draft:3.0 destination:IMTT ST.ROSE eta:06:00 }"; $lines = explode("\n", $s); $output = Array(); $thisElement = & $output; foreach($lines as $line) { $elements = explode(":", $line); if (count($elements) > 1) { $thisElement[trim($elements[0])] = $elements[1]; } if(strstr($line, "{")) { $elements = explode("{", $line); $key = trim($elements[0]); $output[$key] = Array(); $thisElement = & $output[$key]; } if(strstr($line, "}")) { $thisElement = & $output; } } echo '
'; print_r($output); echo '

'; echo ''; ?>

Salida de lo anterior (se puede ver trabajando en http://www.floris.us/SO/ships.php ):

 Array ( [update-token] => 179999210 [vessel-name] => Name Here [vessel-length] => 57.30 [vessel-beam] => 14.63 [vessel-draft] => 3.35 [vessel-airdraft] => 0.00 [time] => 20140104T040648.259Z [position] => 25.04876667 -75.57001667 GPS [river-mile] => sd 178.71 [rate-of-turn] => 0.0 [course-over-ground] => 58.5 [speed-over-ground] => 0.0 [ais-367000000] => Array ( [pos] => 45.943912 -87.384763 DGPS [cog] => 249.8 [sog] => 0.0 [name] => name here [call] => 1113391 [imo] => 8856857 [type] => 31 [dim] => 10 20 4 5 [draft] => 3.8 [destination] => ) [ais-367000001] => Array ( [pos] => 25.949652 -86.384535 DGPS [cog] => 105.6 [sog] => 0.0 [name] => CHRISTINE [call] => 5452438 [type] => 52 [status] => 0 [dim] => 1 2 3 4 [draft] => 3.0 [destination] => IMTT ST.ROSE [eta] => 06 ) ) 

Un mejor enfoque sería convertir la cadena en “JSON correctamente formado”, luego use json_decode . Eso podría parecerse a lo siguiente:

 "; $s="update-token:179999210 vessel-name:Name Here vessel-length:57.30 vessel-beam:14.63 vessel-draft:3.35 vessel-airdraft:0.00 time:20140104T040648.259Z position:25.04876667 -75.57001667 GPS river-mile:sd 178.71 rate-of-turn:0.0 course-over-ground:58.5 speed-over-ground:0.0 ais-367000000 { pos:45.943912 -87.384763 DGPS cog:249.8 sog:0.0 name:name here call:1113391 imo:8856857 type:31 dim:10 20 4 5 draft:3.8 destination: } ais-367000001 { pos:25.949652 -86.384535 DGPS cog:105.6 sog:0.0 name:CHRISTINE call:5452438 type:52 status:0 dim:1 2 3 4 draft:3.0 destination:IMTT ST.ROSE eta:06:00 }"; echo '
'; print_r(parseString($s)); echo '

'; function parseString($s) { $lines = explode("\n", $s); $jstring = "{ "; $comma = ""; foreach($lines as $line) { $elements = explode(":", $line); if (count($elements) > 1) { $jstring = $jstring . $comma . '"' . trim($elements[0]) . '" : "' . $elements[1] .'"'; $comma = ","; } if(strstr($line, "{")) { $elements = explode("{", $line); $key = trim($elements[0]); $jstring = $jstring . $comma . '"' . $key .'" : {'; $comma = ""; } if(strstr($line, "}")) { $jstring = $jstring . '} '; $comma = ","; } } $jstring = $jstring ."}"; return json_decode($jstring); } echo ''; ?>

Demostración en http://www.floris.us/SO/ships2.php ; Tenga en cuenta que utilizo la variable $comma para asegurarme de que las comas están incluidas o no incluidas en varios puntos de la cadena.

La salida de este código es similar a lo que teníamos antes:

 stdClass Object ( [update-token] => 179999210 [vessel-name] => Name Here [vessel-length] => 57.30 [vessel-beam] => 14.63 [vessel-draft] => 3.35 [vessel-airdraft] => 0.00 [time] => 20140104T040648.259Z [position] => 25.04876667 -75.57001667 GPS [river-mile] => sd 178.71 [rate-of-turn] => 0.0 [course-over-ground] => 58.5 [speed-over-ground] => 0.0 [ais-367000000] => stdClass Object ( [pos] => 45.943912 -87.384763 DGPS [cog] => 249.8 [sog] => 0.0 [name] => name here [call] => 1113391 [imo] => 8856857 [type] => 31 [dim] => 10 20 4 5 [draft] => 3.8 [destination] => ) [ais-367000001] => stdClass Object ( [pos] => 25.949652 -86.384535 DGPS [cog] => 105.6 [sog] => 0.0 [name] => CHRISTINE [call] => 5452438 [type] => 52 [status] => 0 [dim] => 1 2 3 4 [draft] => 3.0 [destination] => IMTT ST.ROSE [eta] => 06 ) ) 

Pero tal vez su pregunta es “¿cómo puedo obtener el texto en php en primer lugar”. En ese caso, podrías ver algo como esto:

  1) { $jstring = $jstring . $comma . '"' . trim($elements[0]) . '" : "' . $elements[1] .'"'; $comma = ","; } if(strstr($line, "{")) { $elements = explode("{", $line); $key = trim($elements[0]); $jstring = $jstring . $comma . '"' . $key .'" : {'; $comma = ""; } if(strstr($line, "}")) { $jstring = $jstring . '} '; $comma = ","; } } $jstring = $jstring ."}"; return json_decode($jstring); } ?> 

Incluyo la misma función de análisis que antes; es posible hacerlo mucho mejor, o dejarlo de lado por completo. Difícil saber de su pregunta.

Preguntas bienvenidas

ACTUALIZAR

En base a los comentarios, he agregado una función que realizará el curl en el recurso de archivo; Hazme saber si esto funciona para ti. He creado un archivo http://www.floris.us/SO/ships.txt que es una copia exacta del archivo que mostraste arriba, y un http://www.floris.us/SO/ships3.php que contiene el siguiente código fuente: puede ejecutarlo y ver que funciona (nota: en esta versión no leo nada de un archivo .csv) ya sabe cómo hacerlo. Esto es solo tomar la matriz, y usar para obtener un archivo de texto, luego convertirlo a una estructura de datos que puede usar, mostrar, lo que sea):

 
'; print_r($responses); echo '

'; function parseString($s) { $lines = explode("\n", $s); $jstring = "{ "; $comma = ""; foreach($lines as $line) { $elements = explode(":", $line); if (count($elements) > 1) { $jstring = $jstring . $comma . '"' . trim($elements[0]) . '" : "' . $elements[1] .'"'; $comma = ","; } if(strstr($line, "{")) { $elements = explode("{", $line); $key = trim($elements[0]); $jstring = $jstring . $comma . '"' . $key .'" : {'; $comma = ""; } if(strstr($line, "}")) { $jstring = $jstring . '} '; $comma = ","; } } $jstring = $jstring ."}"; return json_decode($jstring); } function myCurl($f) { // create curl resource $ch = curl_init(); // set url curl_setopt($ch, CURLOPT_URL, $f); //return the transfer as a string curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // $output contains the output string $output = curl_exec($ch); // close curl resource to free up system resources curl_close($ch); return $output; } ?>

Nota: debido a que dos entradas tienen la misma “etiqueta”, la segunda sobrescribe la primera cuando se utilizan los datos de origen originales. Si ese es un problema, házmelo saber. Además, si tiene ideas sobre cómo realmente desea mostrar los datos, intente simular algo y pueda ayudarlo a hacerlo bien.

Sobre el tema de los tiempos muertos

Hay varios posibles mecanismos de tiempo de espera que pueden estar causando problemas; dependiendo de cuál sea, una de las siguientes soluciones puede ayudarlo a:

  1. Si el navegador no obtiene ninguna respuesta del servidor, eventualmente terminará el tiempo de espera. Es casi seguro que este no es su problema en este momento; pero podría convertirse en tu problema si arreglas los otros problemas
  2. Los scripts php normalmente tienen incorporado un “tiempo máximo para ejecutar” antes de decidir que los envió a un bucle infinito. Si sabe que va a hacer muchas solicitudes, y estas solicitudes llevarán mucho tiempo, es posible que desee establecer un tiempo de espera más alto. Consulte http://www.php.net/manual/en/function.set-time-limit.php para obtener detalles sobre cómo hacer esto. Yo recomendaría establecer el límite en un valor “razonable” dentro del ciclo de curl , por lo que el contador se restablece para cada nueva solicitud.
  3. Su bash de conectarse al servidor puede tomar demasiado tiempo (este es el problema más probable, como usted dijo). Puede establecer el valor (tiempo que espera esperar para establecer la conexión) a algo “vagamente razonable” como 10 segundos; esto significa que no esperará por siempre a los servidores que están fuera de línea. Utilizar

    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);

por una espera de 10 segundos. Consulte Configuración del tiempo de espera de Curl en PHP Finalmente, querrá manejar los errores con elegancia: si la conexión no tuvo éxito, no desea procesar la respuesta. Poner todo esto en orden te da algo como esto:

 $i = 0; foreach($urls as $url) { $temp = myCurl($url); if (strlen($temp) == 0) { echo 'no response from '.$url.'
'; } else { $responses[$i] = parseString(myCurl($url)); $i = $i + 1; } } echo '
'; print_r($responses); echo '

'; function myCurl($f) { // create curl resource $ch = curl_init(); // set url curl_setopt($ch, CURLOPT_URL, $f); //return the transfer as a string curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_NOSIGNAL, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // try for 10 seconds to get a connection curl_setopt($ch, CURLOPT_TIMEOUT, 30); // try for 30 seconds to complete the transaction // $output contains the output string $output = curl_exec($ch); // see if any error was set: $curl_errno = curl_errno($ch); // close curl resource to free up system resources curl_close($ch); // make response depending on whether there was an error if($curl_errno > 0) { return ''; } else { return $output; } }

¿Última actualización? He actualizado el código una vez más. Es ahora

  1. Lee una lista de URL de un archivo (una URL por línea, totalmente formada)
  2. Trata de buscar los contenidos de cada archivo uno por uno, manejando tiempos muertos y haciendo eco del progreso en la pantalla
  3. Crea tablas con parte de la información de los archivos (incluida una marca de tiempo reformateada)

Para que esto funcione, tenía los siguientes archivos:

www.floris.us/SO/ships.csv contiene tres líneas con

 http://www.floris.us/SO/ships.txt http://floris.dnsalias.com/noSuchFile.html http://www.floris.us/SO/ships2.txt 

Archivos ships.txt y ships2.txt en la misma ubicación (copias casi idénticas, pero para el nombre del barco): estos son como sus archivos de texto sin formato.

File ships3.php en la misma ubicación. Este contiene el siguiente código fuente, que realiza los diversos pasos descritos anteriormente, e intenta enhebrarlo todo:

  0) { $responses[$i] = parseString($temp); $i = $i + 1; } else { echo "URL ".$url." did not repond
"; } } // produce the actual output table: echo ''; writeTable($responses); echo '

'; // ------------ support functions ------------- function parseString($s) { $lines = explode("\n", $s); $jstring = "{ "; $comma = ""; foreach($lines as $line) { $elements = explode(":", $line); if (count($elements) > 1) { $jstring = $jstring . $comma . '"' . trim($elements[0]) . '" : "' . $elements[1] .'"'; $comma = ","; } if(strstr($line, "{")) { $elements = explode("{", $line); $key = trim($elements[0]); $jstring = $jstring . $comma . '"' . $key .'" : {'; $comma = ""; } if(strstr($line, "}")) { $jstring = $jstring . '} '; $comma = ","; } } $jstring = $jstring ."}"; return json_decode($jstring, true); } function myCurl($f) { // create curl resource $ch = curl_init(); // set url curl_setopt($ch, CURLOPT_URL, $f); //return the transfer as a string curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_NOSIGNAL, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // try for 10 seconds to get a connection curl_setopt($ch, CURLOPT_TIMEOUT, 30); // try for 30 seconds to complete the transaction // $output contains the output string $output = curl_exec($ch); // see if any error was set: $curl_errno = curl_errno($ch); $curl_error = curl_error($ch); // close curl resource to free up system resources curl_close($ch); // make response depending on whether there was an error if($curl_errno > 0) { echo 'Curl reported error '.$curl_error.'
'; return ''; } else { echo 'Successfully fetched '.$f.'
'; return $output; } } function writeTable($r) { echo 'The following ships reported:
'; echo '

'; foreach($r as $value) { if (strlen($value["vessel-name"]) > 0) { echo '

'; echo '

'; echo '

'; echo '

'; echo '

Vessel Name '.$value["vessel-name"].'
Time: '.dateFormat($value["time"]).'
Position: '.$value["position"].'

'; } echo '

'; } } function dateFormat($d) { // with input yyyymmddhhmm // return dd/mm/yy hh:mm $date = substr($d, 6, 2) ."/". substr($d, 4, 2) ."/". substr($d, 2, 2) ." ". substr($d, 9, 2) . ":" . substr($d, 11, 2); return $date; } ?>

La salida de esto es:

enter image description here

Obviamente puedes hacer esto más lindo, e incluir otros campos, etc. Sin embargo, creo que esto debería hacerte llegar lejos. Podría considerar (si puede) ejecutar un script en segundo plano para crear estas tablas cada 30 minutos, y guardar las tablas html resultantes en un archivo local en su servidor; luego, cuando las personas quieran ver el resultado, no tendrían que esperar las respuestas (lentas) de los diferentes servidores remotos, sino obtener un resultado “casi instantáneo”.

Pero eso está algo alejado de la pregunta original. Si puede implementar todo esto de manera viable y luego quiere volver y hacer una pregunta de seguimiento (si todavía está atascado / no satisfecho con el resultado), ese es probablemente el camino a seguir. Creo que ya hemos vencido a este hasta la muerte.

Primero combine los sitios web en un csv o matriz codificada, luego file_get_contents () / file_put_contents () en cada uno. Esencialmente:

 $file = dataFile.csv foreach($arrayOfSites as $site){ $data = file_get_contents($site); file_put_contents($file, $data . "\n", FILE_APPEND); } 

Editar: Lo siento tratando de hacer esto rápido. aquí está el completo