2013-04-17 1 views
2

Я пытаюсь прочитать данные из таблиц, похожих на следующие http://www.fec.gov/pubrec/fe1996/hraz.htm, используя R, но не смог достигнуть прогресса. Я понимаю, что для этого мне нужно использовать XML и RCurl, но, несмотря на множество других примеров в Интернете, связанных с аналогичными проблемами, я не смог решить эту проблему.Чтение текстовых таблиц формата фиксированной ширины с HTML-страницы

Первая проблема заключается в том, что таблица является только таблицей при ее просмотре, но не кодируется как таковая. Рассмотрев его как XML-документ, я могу получить доступ к «данным» в таблице, но поскольку есть несколько таблиц, которые я хотел бы получить, я не считаю, что это самое элегантное решение.

Рассмотрение его как html-документа может работать лучше, но я относительно незнакомый с xpathApply и не знаю, как получить фактические «данные» в таблице, поскольку он не заключен в скобки ничем (т.е. i-/i или b-/b).

У меня был некоторый успех с использованием файлов xml в прошлом, но это моя первая попытка сделать что-то подобное с html-файлами. Эти файлы, в частности, имеют меньшую структуру, чем другие примеры, которые я видел.

Любая помощь очень ценится.

+0

Просмотр источника этой страницы, это не таблица. – A5C1D2H2I1M1N2O1R2T1

+0

Я думаю, что вам нужен читатель xml, а не читатель csv (table) – Nishanth

+0

Снова просмотрев исходный код страницы, они * попытались * представить данные в формате фиксированной ширины, чтобы вы могли просто «скопировать и вставить "и использовать' read.fwf'. Однако. Я упоминаю, что они * попытались * сделать фиксированную ширину данных, но вы можете видеть, что «Район 3» выровнен по-другому, чем другие, что потребует дальнейшей очистки после импорта. – A5C1D2H2I1M1N2O1R2T1

ответ

1

Предполагая, что вы можете прочитать html вывод в текстовый файл (эквивалент копирования + вставки формируют свой веб-браузер), это вы должны получить хороший кусок пути туда:

# x is the output from the website 


library(stringr) 
library(data.table) 

# First, remove commas from numbers (easiest to do at beginning) 
x <- gsub(",([0-9])", "\\1", x) 

# split the data by District 
districts <- strsplit(x, "DISTRICT *")[[1]] 

# separate out the header info 
headerInfo <- districts[[1]] 
districts <- tail(districts, -1) 


# grab the straggling district number, use it as a name and remove it 

    # end of first line 
    eofl <- str_locate(districts, "\n")[,2] 

    # trim white space and assign as name 
    names(districts) <- str_trim(substr(districts, 1, eofl)) 

    # remove first line 
    districts <- substr(districts, eofl+1, nchar(districts)) 

# replace the ending '-------' and trime white space 
    districts <- str_trim(str_replace_all(districts, "---*", "")) 

# Adjust delimeter (this is the tricky part) 

    ## more than two spaces are a spearator 
    districts <- str_replace_all(districts, " +", "\t") 

    ## lines that are total tallies are missing two columns. 
    ## thus, need to add two extra delims. After the first and third columns 

     # this function will 
     padDelims <- function(section, splton) { 
      # split into lines 
      section <- strsplit(section, splton)[[1]] 
      # identify lines starting with totals 
      LinesToFix <- str_detect(section, "^Total") 
      # pad appropriate columns 
      section[LinesToFix] <- sub("(.+)\t(.+)\t(.*)?", "\\1\t\t\\2\t\t\\3", section[LinesToFix]) 

      # any rows missing delims, pad at end 
      counts <- str_count(section, "\t") 
      toadd <- max(counts) - counts 
      section[ ] <- mapply(function(s, p) if (p==0) return (s) else paste0(s, paste0(rep("\t", p), collapse="")), section, toadd) 

      # paste it back together and return 
      paste(section, collapse=splton) 
     } 

    districts <- lapply(districts, padDelims, splton="\n") 

    # reading the table and simultaneously addding the district column 
    districtTables <- 
     lapply(names(districts), function(d) 
     data.table(read.table(text=districts[[d]], sep="\t"), district=d)) 
    # ... or without adding district number: 
    ##  lapply(districts, function(d) data.table(read.table(text=d, sep="\t"))) 

    # flatten it 
    votes <- do.call(rbind, districtTables) 
    setnames(votes, c("Candidate", "Party", "PrimVotes.Abs", "PrimVotes.Perc", "GeneralVotes.Abs", "GeneralVotes.Perc", "District")) 

Пример таблицы :

votes 

         Candidate  Party PrimVotes.Abs PrimVotes.Perc GeneralVotes.Abs GeneralVotes.Perc District 
1:     Salmon, Matt   R   33672   100.00  135634.00    60.18  1 
2:   Total Party Votes:     33672    NA    NA    NA  1 
3:              NA    NA    NA    NA  1 
4:      Cox, John  W(D)/D   1942   100.00   89738.00    39.82  1 
5:   Total Party Votes:      1942    NA    NA    NA  1 
6:              NA    NA    NA    NA  1 
7:   Total District Votes:     35614    NA  225372.00    NA  1 
8:     Pastor, Ed   D   29969   100.00   81982.00    65.01  2 
9:   Total Party Votes:     29969    NA    NA    NA  2 
10:              NA    NA    NA    NA  2 
... 
51:    Hayworth, J.D.   R   32554   100.00  121431.00    47.57  6 
52:   Total Party Votes:     32554    NA    NA    NA  6 
53:              NA    NA    NA    NA  6 
54:     Owens, Steve   D   35137   100.00  118957.00    46.60  6 
55:   Total Party Votes:     35137    NA    NA    NA  6 
56:              NA    NA    NA    NA  6 
57:    Anderson, Robert  LBT   148   100.00   14899.00    5.84  6 
58:              NA    NA    NA    NA  6 
59:   Total District Votes:     67839    NA  255287.00    NA  6 
60:              NA    NA    NA    NA  6 
61:   Total State Votes:     368185    NA  1356446.00    NA  6 
         Candidate  Party PrimVotes.Abs PrimVotes.Perc GeneralVotes.Abs GeneralVotes.Perc District 
Смежные вопросы