2012-01-10 155 views
17

有沒有簡單的方法使用Mathematica從特定的HTML表格中提取數據? Import似乎非常強大,Mathematica似乎能夠很好地處理XML等格式。使用Mathematica從HTML中提取信息

下面是一個例子:http://en.wikipedia.org/wiki/Unemployment_by_country

+2

IMO,如果您使用的是版本8,JSON是要走的路。在野外有大量的API(通常以您的方式拋出XML或JSON)。我不會建議殺死時間從Wiki中翻譯失業數據。找到你感興趣的主要來源,它可能會有一個API。如果您只想快速翻閱某些內容,也可以嘗試在Excel中鏈接單元格,然後您可以導入到MMA中。 (如果你只是想玩得開心並學習,那麼忽略所有這一切,在這種情況下,解析掉):D – telefunkenvf14 2012-01-11 01:34:25

回答

13

對於這種普遍的例子還有這些密技:

對於這個具體的例子只是導入

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

清潔起來是相當有這種進口直線前進。該表是3列,以便從剩下的東西提取出來:

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

你大概會想刪除的方括號引用(?):

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

Grid[tmp1, Frame -> All] 

注意你也可以添加頭回來,如果你想在你的表,你可能

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

純粹主義者可能會反對的最後一步,但是當你刮數據通常你只想把工作做好,並且每個現場是個案前景。因此,一些手動檢查和靈活性可以讓您獲得最快的整體結果

編輯

,如果你想要的標誌,你也可以從CountryData得到它們。需要進一步清理,否則會發生很多錯失。清理包括刪除括號中對「主權國家」的提及。例如「關島(美國)」 - >「Gaum」。

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

這仍然會產生一些CountryData不能識別的輸出。

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

6未命中出190.從輸出刪除那些未命中:

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

注意這需要一段時間來呈現。

enter image description here

爲使用Grid選項需要,可以很明顯的風格和Grid也如果需要調整圖像。

+0

關於'(*比規則替換更快*) ',這比你的代碼更快:'List/@ Replace [flags,_CountryData - >「」,1 ]'。 (+1,btw) – 2012-01-12 10:21:07

+0

你是對的。我測試過'ReplaceAll',它很慢。 「替換」要快得多。 – 2012-01-12 11:51:18

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

當然,其結果將經常需要進一步的處理。你想如何想象它?

可以使用

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

我會以某種方式想象它,但主要的是首先創建一個對應於表的矩陣, 。 – 2012-01-10 20:20:30

+0

如果''Data''不起作用,那麼我會嘗試''XMLObject'',然後仔細使用'Cases'。儘管如此,這種方法很快就會變得麻煩。 – 2012-01-10 20:22:36

+1

+1用於指出「導入[...,」元素「] [。](http://reference.wolfram.com/mathematica/ref/Import.html#405487078) – Simon 2012-01-11 09:56:19

3

對於 '易' 的某些價值發現所有Import類型的,是的。請參閱:HTML Import documentation for Mathematica 8.

您可以使用"Data"格式選項(例如, Import["file.hml", "Data"]。這是一個開始,但你的鏈接是一個完整的DOM樹的價值表,divs和其他東西。它有文件記載,但很薄弱,你必須試驗。它確實可以與URL一起工作。

這個實際上工作。帶着幾分清洗,你可以在這裏使用的數據:

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

雖然使用Import可能是一個更好,更穩健的方式,我發現,至少在這個特定的問題,我自己的HTML解析器(出版在this thread),工作良好,少量的後處理。如果你從那裏的代碼並執行它,使用此功能增強它:

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

然後你得到,我想,一個非常完整的數據通過這個代碼:

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

這裏是如何結果看起來:

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

我喜歡什麼有關此方法(而不是說,Import->XMLObject)是的,因爲我轉換網頁爲最小的語法Mathematica表達式(例如不同XML對象),通常很容易建立一套替換規則,在每種情況下都能進行正確的後處理。最後一個免責聲明是我的解析器不健壯,確實包含許多錯誤,所以要警告。

+0

您必須有足夠的材料才能編寫現在另一本Mathematica書。其實,我希望你能做到。 ;-) – 2012-01-11 11:27:30

+0

@ ndroock1謝謝!我正在努力,但最近我有太多的直接工作要有足夠的空閒時間來快速完成。在SO這裏回答帖子是一回事,但寫一本認真的書需要更多的時間,至少在覈心完成之前。希望能儘快獲得更多時間。順便說一句,有一個新的Mathematica SE網站的建議:http://area51.stackexchange.com/proposals/37304/mathematica。如果你還沒有這樣做,請考慮支持它。 – 2012-01-11 11:48:03

+0

@ ndroock1只需添加到以前的內容:該提案現在正在將它的(希望是最終的)步驟從提交階段提交到測試版。以下是不夠的,它不會自動轉入提交。 – 2012-01-11 12:03:22

4

如果您想要導入[...,「XMLObject」]路線,下面概述了您可以執行的操作。

首先,讓頁面:

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

接下來,獲得的利息表(在這種情況下,大表也正好是第一的七個表此頁):

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

接下來,從table得到row,我挑選的第四行與對應阿爾及利亞:

行=例[表,的XMLElement [ 「TR」,___],[Infi的無窮大]] [[4]]

接着,從該行中提取表的數據元素():

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

缺貨那些​​元件的,可以挑例如國家標誌縮略圖,像這樣:

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

最後導入圖像的縮略圖(它需要的 「http:」 前面加上出於某種原因):

Import["http:" <> image] 

這是筆記本電腦是什麼樣子(縮略圖,加上其它輸入):

Mathematica graphics

6

沒有直接回答如何導入HTML(該人已很好地解釋),但獲得的數據來自HTML表格是恰恰是爲什麼我原來是我的table paste palette

如果您的目標是獲取數據,這可能比嘗試解析頁面更容易,更快速。使用調色板

  1. 指令計算創建調色板,去調色板的表達 - >安裝面板...並永久保存以備後用(如果你願意的話)。

  2. 在網頁上選擇一部分表格。如果您使用Firefox,請按住CTRL以選擇表格的任何矩形部分(非常有用!)將其複製。

  3. 如果您使用的是Firefox或Chrome,請按調色板上的TSV按鈕將數據粘貼到當前插入點的筆記本中。我不確定其他瀏覽器在複製時是否也會將選項與選項卡分開。

結果將是這樣的:

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

正如你所看到的,需要一些後處理多年轉換成合適的格式


(字符串或整數?)

這是舊的調色板代碼。我意識到它需要清理,但它仍然可以正常工作,而且我還沒有時間來修復它。在下面的評論中報告任何問題。

[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

這工作完美無瑕。非常便利。 – 2012-01-11 19:44:55

+0

這很好。我希望我能理解正則表達式。它似乎很神祕:) – 2012-01-11 21:35:25

+0

@Mike它只是一個'StringTrim'。我爲最初的Mathematica 6寫了這個,裏面沒有'StringTrim'。 – Szabolcs 2012-01-11 22:29:47