2012-01-10 156 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