2012-01-10 35 views
17

Có cách nào dễ dàng trích xuất dữ liệu từ các bảng HTML cụ thể bằng Mathematica không? Import có vẻ khá mạnh mẽ, và Mathematica dường như có khả năng xử lý các định dạng như XML khá tốt.Trích xuất thông tin từ HTML bằng cách sử dụng Mathematica

Dưới đây là một ví dụ: http://en.wikipedia.org/wiki/Unemployment_by_country

+2

IMO, nếu bạn đang sử dụng phiên bản 8, JSON là cách để thực hiện. Có rất nhiều API trong tự nhiên (thường là trượt XML hoặc JSON theo cách của bạn). Tôi sẽ không khuyên bạn nên giết thời gian trích xuất dữ liệu thất nghiệp từ một Wiki. Tìm nguồn chính cho những gì bạn quan tâm và có thể sẽ có API. Nếu bạn chỉ muốn rip một cái gì đó một cách nhanh chóng, bạn cũng có thể thử các tế bào liên kết trong Excel --- sau đó bạn có thể nhập khẩu vào MMA. (Bỏ qua tất cả điều này nếu bạn chỉ muốn vui vẻ và học hỏi. Trong trường hợp đó, phân tích đi !!): D – telefunkenvf14

Trả lời

13

Đối với ví dụ chung về điều này có những thế nào tos:

Ví dụ cụ thể này chỉ nhập nó

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

sạch nó lên là khá thẳng về phía trước với nhập khẩu này.Bảng này là 3 cột để trích xuất nó ra khỏi phần còn lại của các công cụ:

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

Bạn có lẽ sẽ muốn loại bỏ các tài liệu tham khảo khung vuông (??):

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

Grid[tmp1, Frame -> All] 

Cũng lưu ý bạn có thể thêm tiêu đề trở lại nếu bạn muốn nó trong bảng của bạn, mà bạn có thể làm

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

chủ nghĩa thuần túy có thể phản đối đến bước cuối cùng nhưng khi bạn đang cào dữ liệu nói chung bạn chỉ muốn có được công việc thực hiện và mỗi trang web là một trường hợp của khách hàng tiềm năng. Vì vậy, một số kiểm tra thủ công và tính linh hoạt giúp bạn có được kết quả tổng thể nhanh nhất.

Sửa

nếu bạn muốn cờ bạn cũng có thể nhận được chúng từ CountryData. Một số làm sạch thêm là cần thiết nếu không rất nhiều lỗi sẽ xảy ra. Việc dọn dẹp liên quan đến việc loại bỏ tham chiếu đến "quốc gia có chủ quyền" trong ngoặc đơn. ví dụ. "Guam (Hoa Kỳ)" -> "Gaum".

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

Điều này vẫn sẽ tạo ra một số đầu ra là CountryData không nhận ra.

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

6 lỡ ra khỏi 190. Di chuyển những bỏ lỡ từ đầu ra:

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

Lưu ý rằng điều này mất một thời gian để render.

enter image description here

Bạn rõ ràng là có thể tạo kiểu các Grid như mong muốn sử dụng Grid lựa chọn và cũng thay đổi kích thước hình ảnh nếu cần thiết.

+0

Về '(* nhanh hơn thay thế quy tắc *) ', điều này nhanh hơn mã của bạn: 'Danh sách/@ Thay thế [cờ, _CountryData ->" ", 1 ] '. (+1, btw) –

+0

Bạn nói đúng. Tôi đã thử nghiệm 'ReplaceAll' khá chậm. 'Thay thế' nhanh hơn nhiều. –

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

Tất nhiên, kết quả sẽ thường xuyên cần tiếp tục xử lý. Bạn muốn hình dung nó như thế nào?

Bạn có thể tìm thấy tất cả Import loại sử dụng

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

Tôi sẽ hình dung nó bằng cách nào đó, nhưng điều chính là đầu tiên tạo một ma trận tương ứng với bảng mà không cần mọi thứ khác . –

+0

Nếu '" Dữ liệu "' không hoạt động, tôi sẽ thử '" XMLObject "' tiếp theo, kết hợp với việc sử dụng cẩn thận các 'Trường hợp'. Cách tiếp cận đó khá nhanh chóng. –

+1

+1 Để chỉ ra 'Nhập [...," Phần tử "]' [.] (Http://reference.wolfram.com/mathematica/ref/Import.html#405487078) – Simon

3

Đối với giá trị nhất định của 'dễ dàng', vâng. Xem tại đây: HTML Import documentation for Mathematica 8.

Bạn có thể nhập từ các bảng bằng cách sử dụng tùy chọn định dạng "Data", ví dụ: Import["file.hml", "Data"]. Đó là một sự khởi đầu, nhưng liên kết của bạn là toàn bộ giá trị của bảng DOM, các div và những thứ khác. Đó là tài liệu, nhưng mỏng, và bạn phải thử nghiệm. Nó hoạt động với các URL mặc dù.

Điều này thực sự hoạt động. Với một chút làm sạch bạn có thể sử dụng dữ liệu ở đây:

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

Trong khi việc sử dụng các Import có lẽ là một cách tốt hơn và mạnh mẽ hơn, tôi thấy rằng, ít nhất cho vấn đề này cụ thể, phân tích cú pháp HTML của riêng tôi (xuất bản trong this thread), hoạt động tốt với một lượng nhỏ xử lý hậu kỳ. Nếu bạn lấy mã từ đó và thực hiện nó, làm tăng nó với chức năng này:

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

Sau đó, bạn nhận được, tôi nghĩ rằng, một khá nhiều hoàn chỉnh dữ liệu bằng cách mã này:

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

Sau đây là cách kết quả trông:

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

những gì tôi thích về phương pháp này (như trái ngược với nói, Import->XMLObject) là, kể từ khi tôi chuyển đổi trang web vào biểu với cú pháp tối thiểu Mathematica (không giống như ví dụ Các đối tượng XML), thường rất dễ thiết lập một bộ các quy tắc thay thế, thực hiện xử lý hậu xử lý đúng trong từng trường hợp cụ thể. Tuyên bố từ chối trách nhiệm cuối cùng là trình phân tích cú pháp của tôi không mạnh mẽ và chắc chắn chứa một số lỗi, vì vậy hãy cảnh báo.

+0

Bạn phải có đủ tài liệu để viết một cuốn sách Mathematica khác bây giờ. Trong thực tế, tôi hy vọng bạn làm. ;-) –

+0

@ ndroock1 Cảm ơn! Tôi đang làm việc trên nó, nhưng gần đây tôi đã có quá nhiều công việc trực tiếp để có đủ thời gian rảnh để làm điều đó nhanh chóng. Nó là một điều để trả lời các bài viết ở đây tại SO, nhưng viết một cuốn sách nghiêm trọng cần nhiều thời gian hơn thế, ít nhất là cho đến khi cốt lõi được hoàn thành. Hy vọng sẽ sớm có thêm thời gian. Nhân tiện, có một đề xuất trang web Mathematica SE mới: http://area51.stackexchange.com/proposals/37304/mathematica. Hãy xem xét hỗ trợ nó nếu bạn chưa làm như vậy. –

+0

@ ndroock1 Chỉ cần thêm vào trước đó: đề xuất hiện đang thực hiện các bước (hy vọng cuối cùng) của nó để thoát khỏi giai đoạn cam kết thành beta. Sau đây là không đủ, nó không tự động được chuyển vào một cam kết. –

4

Nếu bạn muốn chuyển tuyến nhập [..., "XMLObject"], dưới đây là phác thảo những gì bạn có thể làm.

Đầu tiên, có được trang:

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

Tiếp theo, lấy bảng quan tâm (trong trường hợp này bảng lớn cũng sẽ xảy ra là đầu tiên trong bảy bảng trên trang này):

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

Tiếp theo, có được một row từ table, tôi chọn hàng ghế thứ tư tương ứng với Algeria:

row = các trường hợp [bảng, XmlElement [ "tr", ___], [Infi nity]] [[4]]

Tiếp theo, trích xuất các yếu tố bảng dữ liệu() từ dòng này:

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

Trong số những yếu tố này, bạn có thể chọn ví dụ như hình ảnh thu nhỏ nước cờ, như vậy:

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

Cuối cùng nhập mà hình ảnh thu nhỏ (nó cần thiết "http:" prepended đối với một số lý do):

Import["http:" <> image] 

Đây là những gì các máy tính xách tay trông giống như (hình thu nhỏ, cộng với các đầu vào khác):

Mathematica graphics

6

Không phải là một câu trả lời trực tiếp cho cách nhập HTML (mà những người khác đã giải thích độc đáo), nhưng nhận được dữ liệu từ các bảng HTML là chính xác là lý do tại sao tôi thực hiện lần đầu tiên là table paste palette.

Nếu mục tiêu của bạn là chỉ lấy dữ liệu, điều này có thể sẽ dễ dàng hơn và nhanh hơn việc phân tích trang.

Hướng dẫn về cách sử dụng bảng màu

  1. Đánh giá các biểu hiện tạo bảng, đi đến Palettes -> Install Palette ... và lưu nó vĩnh viễn để sử dụng sau (nếu bạn muốn).

  2. Chọn một phần của bảng trên trang web. Nếu bạn đang làm việc với Firefox, hãy giữ CTRL để chọn bất kỳ phần hình chữ nhật nào của bảng (rất hữu ích!) Sao chép nó.

  3. Nếu bạn đang sử dụng Firefox hoặc Chrome, hãy nhấn nút TSV trên bảng màu để dán dữ liệu vào sổ ghi chép tại điểm chèn hiện tại. Tôi không chắc liệu các trình duyệt khác có phân tách các mục bằng các tab khi sao chép hay không.

Kết quả sẽ giống như thế này:

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

Như bạn thấy, một số sau xử lý là cần thiết để chuyển đổi năm sang một định dạng thích hợp


(string hoặc số nguyên?)

Đây là mã bảng màu cũ.Tôi nhận ra rằng nó cần dọn dẹp, nhưng nó hoạt động như hiện tại, và tôi chưa có thời gian sửa chữa nó. Báo cáo bất kỳ vấn đề nào trong phần bình luận bên dưới.

[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

Điều này làm việc hoàn hảo. Rất tiện dụng. –

+0

Điều này thật tuyệt. Tôi ước tôi hiểu những biểu hiện thông thường. Nó có vẻ rất khó hiểu :) –

+0

@Mike Nó chỉ là một 'StringTrim'. Tôi đã viết này cho Mathematica 6 ban đầu mà không có 'StringTrim' được xây dựng trong. – Szabolcs

Các vấn đề liên quan