2012-01-10 16 views
17

Czy istnieje prosty sposób wyodrębniania danych z określonych tabel HTML przy użyciu Mathematica? Import wydaje się być dość potężny, a Mathematica wydaje się być w stanie całkiem dobrze obsługiwać formaty takie jak XML.Wyodrębnianie informacji z HTML przy użyciu Mathematica

Oto przykład: http://en.wikipedia.org/wiki/Unemployment_by_country

+2

IMO, jeśli używasz wersji 8, JSON jest drogą do zrobienia. Istnieje mnóstwo API w środowisku naturalnym (zazwyczaj zawiesia XML lub JSON na swój sposób). Nie polecałbym zabijania czasu zgrywania danych o bezrobociu z Wiki. Znajdź główne źródło tego, co Cię interesuje, a prawdopodobnie będzie mieć interfejs API. Jeśli chcesz tylko szybko zgrać coś, możesz także spróbować połączyć komórki w Excelu --- wtedy możesz zaimportować do MMA. (Ignoruj ​​to wszystko, jeśli chcesz po prostu dobrze się bawić i się uczyć, w takim przypadku spróbujmy!): D – telefunkenvf14

Odpowiedz

13

Dla ogólnych przykładów tego są takie jak tos:

W tym konkretnym przykładzie tylko importować to

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

Czyszczenie go jest dość proste z tego importu.Stół jest 3 kolumny tak wyodrębnić go z resztą rzeczy:

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

Będziesz prawdopodobnie chcesz usunąć kwadratowych referencje wspornik (??):

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

Grid[tmp1, Frame -> All] 

Uwaga również można dodać nagłówek z powrotem, jeśli chcesz go w tabeli, która prawdopodobnie zrobić

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

puryści mogą wyrazić sprzeciw wobec ostatniego etapu, ale jeśli są skrobanie dane generalnie po prostu chcesz otrzymać pracę i każdy strona jest perspektywą dla każdego przypadku. Dzięki temu ręczna inspekcja i elastyczność zapewniają najszybszy ogólny wynik.

Edit

jeśli chciał flagi można również uzyskać je od CountryData. Konieczne jest dalsze oczyszczanie, w przeciwnym razie wystąpi wiele błędów. Oczyszczenie obejmuje usunięcie odniesienia do "suwerennego kraju" w nawiasie. na przykład "Guam (Stany Zjednoczone)" -> "Gaum".

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

Spowoduje to wyświetlenie niektórych wyników, których nie rozpoznaje CountryData.

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

6 zagra z 190. Usuń te nie wykorzystuje wyjście:

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

pamiętać, że ta zajmuje trochę czasu, aby uczynić.

enter image description here

Można oczywiście styl dla Grid dowolnie za pomocą Grid opcje, a także zmiana rozmiaru obrazów w razie potrzeby.

+0

Jeśli chodzi o '(* znacznie szybciej niż zastąpienie reguły *) ', to jest szybsze niż twój kod: 'List/@ Replace [flags, _CountryData ->" ", 1 ] '. (+1, btw) –

+0

Masz rację. Przetestowałem 'ReplaceAll', który jest dość powolny. 'Zamień' jest znacznie szybszy. –

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

Oczywiście, wynik będzie często wymagają dalszej obróbki. Jak chcesz go sobie wyobrazić?

można znaleźć wszystkie rodzaje Import użyciu

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

Wyobrazię to jakoś, ale najważniejsze jest, aby najpierw utworzyć macierz odpowiadającą tabeli bez wszystkiego innego . –

+0

Jeśli '" Dane "' nie działa, chciałbym wypróbować '" XMLObject "', w połączeniu z ostrożnym użyciem 'Cases'. Jednak takie podejście dość szybko staje się kłopotliwe. –

+1

+1 Dla wskazania 'Import [...," Elementy "]' [.] (Http://reference.wolfram.com/mathematica/ref/Import.html#405487078) – Simon

3

Dla pewnych wartości 'łatwa', tak. Zobacz tutaj: HTML Import documentation for Mathematica 8.

Możesz importować z tabel przy użyciu opcji formatu "Data", np. Import["file.hml", "Data"]. To jest początek, ale twój link to cała tabela wartości DOM, div i innych rzeczy. Jest to udokumentowane, ale słabo, i musiałbyś eksperymentować. Działa to jednak z adresami URL.

Ta wersja faktycznie działa. Przy odrobinie czyszczenia można użyć danych tutaj:

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

Chociaż zastosowanie Import jest prawdopodobnie lepszy i bardziej wydajny sposób, uważam, że przynajmniej dla tego konkretnego problemu, mój własny HTML parser (opublikowane w this thread), działa dobrze z niewielką ilością przetwarzania końcowego. Jeśli wziąć kod stamtąd i wykonać ją, zwiększając go z tej funkcji:

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[]}]; 

następnie dostać się, jak sądzę, dość dużo kompletne dane przez ten kod:

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

Oto jak wynik wygląda:

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}}] 

Co lubię tego podejścia (w przeciwieństwie do powiedzenia, Import->XMLObject) jest to, że od przekonwertować stronę internetową do ekspresji Mathematica z minimalnym składni (w przeciwieństwie do np Obiektów XML), często bardzo łatwo jest ustanowić zestaw reguł zastępowania, który w każdym przypadku ma odpowiednie przetwarzanie końcowe. Ostatnim zastrzeżeniem jest to, że mój parser nie jest solidny i na pewno zawiera wiele błędów, więc ostrzegaj.

+0

Musisz mieć wystarczającą ilość materiału do napisania kolejna książka Mathematica. Mam nadzieję, że tak. ;-) –

+0

@ ndroock1 Dzięki! Pracuję nad tym, ale ostatnio miałem zbyt dużo pracy bezpośredniej, aby mieć wystarczająco dużo wolnego czasu, aby zrobić to szybko. Jedną rzeczą jest odpowiadać na posty tutaj w SO, ale pisanie poważnej książki wymaga znacznie więcej czasu, przynajmniej do momentu, gdy rdzeń zostanie ukończony. Mam nadzieję, że wkrótce otrzymam więcej czasu. Nawiasem mówiąc, istnieje nowa propozycja strony Mathematica SE: http://area51.stackexchange.com/proposals/37304/mathematica. Proszę rozważyć wsparcie, jeśli jeszcze tego nie zrobiłeś. –

+0

@ ndroock1 Wystarczy dodać do poprzedniego: propozycja robi teraz (miejmy nadzieję, że ostatnie) kroki, aby wyjść z etapu zatwierdzania do wersji beta. Następujące jest niewystarczające, nie jest automatycznie przekazywane do zatwierdzenia. –

4

Jeśli chcesz przejść do trasy Import [..., "XMLObject"], oto zarys tego, co możesz zrobić.

pierwsze, uzyskać na stronie:

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

Następnie dostać stolik zainteresowania (w tym przypadku duży stół również dzieje się pierwsza z siedmiu stołach na tej stronie):

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

Następnie uzyskać row z table, że odebrał czwartego rzędu co odpowiada Algieria

wiersz = przypadkach [tabela XMLELEMENT [ „tr” ___], [INFI nity]] [[4]]

Następnie wyodrębnić elementy danych tabeli() z tego wiersza:

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

Spośród tych elementów, można wybrać na przykład miniatury flagę kraju, tak jak poniżej:

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

Wreszcie zaimportować miniaturę obrazu (to potrzebne "http:" na początku jakiegoś powodu):

Import["http:" <> image] 

To, co notebook wygląda (miniatury, plus innych wejść):

Mathematica graphics

6

Nie bezpośrednią odpowiedź na temat importowania HTML (których inni wyjaśnili ładnie), lecz pobieranie danych z tabel HTML jest właśnie dlatego, dlaczego pierwotnie zrobiłem mój table paste palette.

Jeśli Twoim celem jest pobranie danych, prawdopodobnie będzie to łatwiejsze i szybsze niż analiza strony.

Instrukcje dotyczące korzystania z palety

  1. ocena ekspresji, która tworzy paletę, przejdź do palet -> Install Palette ... i zapisać go na stałe do późniejszego wykorzystania (jeśli chcesz).

  2. Wybierz część tabeli na stronie. Jeśli pracujesz z przeglądarką Firefox, przytrzymaj CTRL, aby wybrać dowolny prostokątny fragment tabeli (bardzo przydatny!) Skopiuj go.

  3. Jeśli używasz przeglądarki Firefox lub Chrome, naciśnij przycisk TSV na palecie, aby wkleić dane do notatnika w bieżącym punkcie wstawiania. Nie jestem pewien, czy inne przeglądarki również podczas kopiowania oddzielają elementy z kartami.

Wynik będzie wyglądać następująco:

{{"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}} 

Jak widać, niektóre post-processing jest potrzebny do konwersji lat do odpowiedniego formatu


(ciąg lub całkowitą?)

To jest stary kod palety.Zdaję sobie sprawę, że wymaga oczyszczenia, ale działa tak, jak jest, a ja nie miałem jeszcze czasu go naprawić. Zgłoś wszelkie problemy w komentarzach poniżej.

[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

To działało bezbłędnie. Bardzo przydatny. –

+0

To jest miłe. Chciałbym zrozumieć wyrazy regularne. Wydaje się tak tajemniczy :) –

+0

@Mike To tylko 'StringTrim'. Napisałem to dla oryginalnego Mathematica 6, który nie ma wbudowanego 'StringTrim'. – Szabolcs

Powiązane problemy