2012-01-10 16 views
17

¿Hay alguna manera fácil de extraer datos de tablas HTML específicas usando Mathematica? Import parece ser bastante potente, y Mathematica parece ser capaz de manejar formatos como XML bastante bien.Extraiga información de HTML usando Mathematica

He aquí un ejemplo: http://en.wikipedia.org/wiki/Unemployment_by_country

+2

IMO, si está utilizando la versión 8, JSON es el camino a seguir. Hay montones de API en la naturaleza (normalmente lanzando XML o JSON a su manera). No recomendaría matar el tiempo extrayendo datos de desempleo de un Wiki. Encuentre la fuente principal de lo que le interesa y probablemente tenga una API. Si solo quieres ripear algo rápidamente, también puedes probar las celdas enlazadas en Excel --- entonces puedes importar a MMA. (Haga caso omiso de todo esto si solo quiere divertirse y aprender. En ese caso, ¡analícelo!): D – telefunkenvf14

Respuesta

13

Para ejemplos generales de este existen Estas guías prácticas tos:

Para este ejemplo específico simplemente importar que

tmp = Import["http://en.wikipedia.org/wiki/Unemployment_by_country", "Data"] 

limpieza para arriba es bastante sencillo con esta importación.La mesa es de 3 columnas para extraerlo del resto de las cosas:

tmp1 = Cases[tmp, {_, _?NumberQ, _}, \[Infinity]] 

Va a suponer que desee eliminar las referencias de corchete (??):

tmp1[[All, 3]] = Flatten[If[StringQ[#], 
StringCases[#, x__ ~~ Whitespace ~~ "[" ~~ __ :> x], #] & /@ tmp1[[All, 3]]] 

Grid[tmp1, Frame -> All] 

Nota También se puede añadir el header regreso si lo quieres en tu mesa, que es probable que sí

Grid[Join[{{"Country/Region", "Unemployment rate (%)", 
    "Source/date of information"}}, tmp1], Frame -> All] 

puristas podrían oponerse al último paso, pero cuando se está raspando datos por lo general lo que desea es hacer el trabajo y cada el sitio es un prospecto caso por caso. Por lo tanto, un poco de inspección manual y flexibilidad le da el resultado general más rápido.

Editar

si quisiera las banderas también se puede obtener de CountryData. Se necesita más limpieza, de lo contrario ocurrirán muchas fallas. La limpieza implica eliminar la referencia al "país soberano" entre paréntesis. p.ej. "Guam (Estados Unidos)" -> "Gaum".

tmp2 = Flatten[ 
    If[StringMatchQ[#, __ ~~ "(" ~~ __], 
    StringCases[#, 
     z__ ~~ Shortest["(" ~~ __ ~~ ")" ~~ EndOfString] :> 
     [email protected]], StringTrim[#]] & /@ tmp1[[All, 1]]] 

Esto sigue siendo enviado algunos datos que CountryData no reconoce.

flags = CountryData[#, "Flag"] & /@ tmp2; 
Cases[flags, _CountryData] 

6 se pierde de 190. Eliminar los fallos de la salida:

flags = If[Head[#] === CountryData, {""}, {#}] & /@ flags; (*much faster than rule replacement*) 
tmp2 = Join[flags, tmp1, 2]; 
Grid[tmp2, Frame -> All] 

Tenga en cuenta que esto toma algún tiempo para representar.

enter image description here

Puede, evidentemente, el estilo de la Grid según se desee utilizando Grid opciones y también cambiar el tamaño de las imágenes si es necesario.

+0

Con respecto a '(* mucho más rápido que la sustitución de regla *) ', esto es más rápido que su código: 'List/@ Replace [flags, _CountryData ->" ", 1 ] '. (+1, btw) –

+0

Tienes razón. Probé 'ReplaceAll', que es bastante lento. 'Reemplazar' es mucho más rápido. –

5
Import[ 
    "http://en.wikipedia.org/wiki/Unemployment_by_country", 
    "Data"] 

Por supuesto, el resultado frecuentemente necesitará un procesamiento adicional. ¿Cómo quieres visualizarlo?

Usted puede encontrar todos los tipos Import usando

Import[ 
    "http://en.wikipedia.org/wiki/Unemployment_by_country", 
    "Elements"] 
+0

Lo visualizaré de alguna manera, pero lo principal es crear primero una matriz correspondiente a la tabla sin todo lo demás . –

+0

Si '" Datos "' no funciona, probaría '" XMLObject "' a continuación, combinado con el uso cuidadoso de 'Casos'. Sin embargo, ese enfoque se torna bastante rápido. –

+1

+1 Para señalar 'Importar [...," Elementos "]' [.] (Http://reference.wolfram.com/mathematica/ref/Import.html#405487078) – Simon

3

Para ciertos valores de 'fácil', sí. Consulte aquí: HTML Import documentation for Mathematica 8.

Puede importar desde tablas con la opción de formato "Data", p. Ej. Import["file.hml", "Data"]. Eso es un comienzo, pero su enlace es un conjunto completo de tablas, divs y otras cosas del árbol DOM. Está documentado, pero escasamente, y tendrías que experimentar. Sin embargo, funciona con URL.

Este realmente funciona. Con un poco de limpieza podría utilizar los datos aquí:

Import["http://en.wikipedia.org/wiki/Unemployment_by_country", "Data"] 
6

Aunque el uso de Import es probablemente una manera mejor y más robusto, me encontré con que, al menos para este problema en particular, mi propio analizador HTML (publicado en this thread), funciona bien con una pequeña cantidad de post-procesamiento. Si se toma el código de allí y lo ejecuta, aumentando con esta función:

Clear[findAndParseTables]; 
findAndParseTables[text_String] := 
    Module[{parsed = [email protected][text]}, 
    DeleteCases[ 
     Cases[parsed, _tableContainer, Infinity], 
     _attribContainer | _spanContainer, Infinity 
    ] //. 
    {(supContainer | tdContainer | trContainer | thContainer)[x___] :> {x}, 
     iContainer[x___] :> x, 
     aContainer[x_] :> x, 
     "\n" :> Sequence[], 
     divContainer[] | ulContainer[] | liContainer[] | aContainer[] :> Sequence[]}]; 

A continuación presentamos lo mejor, creo, un conjunto de datos más o menos completa por este código:

text = Import["http://en.wikipedia.org/wiki/Unemployment_by_country", "Text"]; 
myData = [email protected][text]; 

Aquí es cómo el resultado es:

In[92]:= Short[myData,5] 
Out[92]//Short= 
tableContainer[{{Country/Region},{Unemployment rate (%)},{Source/date of information}}, 
{{Afghanistan},{35.0},{2008,{3}}},{{Albania},{13.49},{2010 (Q4),{4}}}, 
{{Algeria},{10.0},{2010 (September),{5}}},<<188>>,{{West Bank},{17.2},{2010,{43}}}, 
{{Yemen},{35.0},{2009 (June),{128}}},{{Zambia},{16.0},{2005,{129}}},{{Zimbabwe},{97.0},{2009}}] 

lo que me gusta de este enfoque (en contraposición a decir, Import->XMLObject) es que, desde que convertir la página web en la expresión de Mathematica con la sintaxis mínima (por ejemplo, a diferencia de Objetos XML), a menudo es muy fácil establecer un conjunto de reglas de reemplazo que hace el postproceso correcto en cada caso dado. Un último descargo de responsabilidad es que mi analizador no es robusto y sí contiene una cantidad de errores, así que tenga cuidado.

+0

Debe tener suficiente material para escribir otro libro de Mathematica por ahora. De hecho, espero que lo hagas. ;-) –

+0

@ ndroock1 ¡Gracias! Estoy trabajando en ello, pero recientemente tuve demasiado trabajo directo para tener suficiente tiempo libre para hacerlo rápido. Una cosa es responder mensajes aquí en SO, pero escribir un libro serio necesita mucho más tiempo que eso, al menos hasta que el núcleo esté terminado. Espero tener más tiempo pronto. Por cierto, hay una nueva propuesta de sitio de Mathematica SE: http://area51.stackexchange.com/proposals/37304/mathematica. Por favor considere apoyarlo si aún no lo ha hecho. –

+0

@ ndroock1 Solo para agregar a lo anterior: la propuesta ahora está dando sus (afortunadamente definitivos) pasos para salir de la fase de confirmación en versión beta. Lo siguiente no es suficiente, no se transfiere automáticamente a una confirmación. –

4

Si desea ir a la ruta Importar [..., "XMLObject"], aquí hay un resumen de lo que puede hacer.

En primer lugar, obtener la página:

page = Import["http://en.wikipedia.org/wiki/Unemployment_by_country", "XMLObject"]; 

A continuación, obtener la tabla de interés (en este caso la mesa grande también pasa a ser la primera de las siete tablas en esta página):

table = Cases[page, XMLElement["table", ___], \[Infinity]][[1]] 

a continuación, obtener una row del table, cogí la cuarta fila que corresponde con Argelia:

fila = casos [mesa, XMLElement [ "tr", ___], [Infi nidad]] [[4]]

A continuación, extraer los elementos de datos tabla() de esta fila:

data = Cases[row, XMLElement["td", ___], \[Infinity]] 

Fuera de estos elementos, se puede recoger, por ejemplo, la miniatura de la bandera de país, así:

image = Cases[data, XMLElement["img", {___, "src" -> src_, ___}, _] :> src, \[Infinity]] 

Finalmente importar ese miniatura de la imagen (que necesitaba "http:" antepuesto por alguna razón):

Import["http:" <> image] 

Esto es lo que el portátil se parece a (la miniatura, además de las otras entradas):

Mathematica graphics

6
No

una respuesta directa a la forma de importar HTML (que otros han explicado muy bien), pero conseguir los datos de las tablas HTML es precisamente por qué hice originalmente mi table paste palette.

Si su objetivo es obtener los datos, probablemente sea más fácil y rápido que intentar analizar la página.

Instrucciones de cómo utilizar la paleta

  1. evaluar la expresión que crea la paleta, paletas de ir a -> Instalar paleta ... y guardarlo de forma permanente para su uso posterior (si lo desea).

  2. Seleccione una parte de la tabla en la página web. Si está trabajando con Firefox, mantenga presionada la tecla CTRL para seleccionar cualquier sección rectangular de la tabla (¡muy útil!) Cópielo.

  3. Si está utilizando Firefox o Chrome, presione el botón TSV en la paleta para pegar los datos en el cuaderno en el punto de inserción actual. No estoy seguro de si otros navegadores también separan elementos con pestañas al copiar.

El resultado se verá así:

{{"Afghanistan", 35.`, "2008[3]"}, {"Albania", 13.49`, 
    "2010 (Q4)[4]"}, {"Algeria", 10.`, 
    "2010 (September)[5]"}, {"American Samoa (United States)", 23.8`, 
    "2010[3]"}, {"Andorra", 2.9`, 2009}} 

Como se puede ver, se necesita un post-procedimiento para convertir año a un formato adecuado


(cadena o un entero?)

Este es el código de la paleta anterior.Me doy cuenta de que necesita limpieza, pero funciona como es, y aún no he tenido tiempo de arreglarlo. Informe cualquier problema en los comentarios a continuación.

[email protected]@{Button["TSV", 
    Module[{data, strip}, 
    data = NotebookGet[ClipboardNotebook[]][[1, 1, 1]]; 
    strip[s_String] := 
     StringReplace[s, RegularExpression["^\\s*(.*?)\\s*$"] -> "$1"]; 
    strip[e_] := e; 
    If[Head[data] === String, 
     NotebookWrite[InputNotebook[], 
     [email protected][strip, ImportString[data, "TSV"], {2}]] 
     ] 
    ] 
    ], 
    Button["CSV", 
    Module[{data, strip}, 
    data = NotebookGet[ClipboardNotebook[]][[1, 1, 1]]; 
    strip[s_String] := 
     StringReplace[s, RegularExpression["^\\s*(.*?)\\s*$"] -> "$1"]; 
    strip[e_] := e; 
    If[Head[data] === String, 
     NotebookWrite[InputNotebook[], 
     [email protected][strip, ImportString[data, "CSV"], {2}]] 
     ] 
    ] 
    ], 
    Button["Table", 
    Module[{data}, 
    data = NotebookGet[ClipboardNotebook[]][[1, 1, 1]]; 
    If[Head[data] === String, 
     NotebookWrite[InputNotebook[], 
     [email protected][data, "Table"]] 
     ] 
    ] 
    ]} 
+0

Esto funcionó perfectamente. Muy útil. –

+0

Esto es bueno. Desearía haber entendido las expresiones regulares. Parece tan críptico :) –

+0

@Mike Es solo un 'StringTrim'. Escribí esto para Mathematica 6 originalmente que no tiene 'StringTrim' incorporado. – Szabolcs

Cuestiones relacionadas