Как загрузить и прочитать htm. файл в R

#r

#r

Вопрос:

Я хочу загрузить информацию в R с веб-сайта Комиссии по торговле товарными фьючерсами. Меня особенно интересует отчет об обязательствах трейдеров. Сам файл имеет расширение .htm. Необходимая информация в теле страницы завернута в

  <pre> 
  

тег. Сама информация напоминает текст файлов dos. Вот пример:

введите описание изображения здесь

С помощью следующего кода я смог загрузить эту информацию в R:

  library('XML')
 
 url <- 'https://www.cftc.gov/dea/options/ag_sof.htm'
 webpage <- readLines(url, warn=FALSE)
 html <- htmlTreeParse(webpage, useInternalNodes = TRUE, asText = TRUE)
 tableNodes <- getNodeSet(html, "//pre")
  

элемент tableNodes имеет следующую структуру:

  str(tableNodes)
 List of 1
 $ :Classes 'XMLInternalElementNode', 'XMLInternalNode', 'XMLAbstractNode' <externalptr> 
  - attr(*, "class")= chr "XMLNodeSet"
  

Теперь я в тупике и не знаю, как привести этот объект даже к форме таблицы.

Ответ №1:

учитывая тот факт, что то, что вы пытаетесь прочитать как таблицу, является просто обычным текстом, одним из способов было бы преобразовать его в формат, который можно было бы анализировать с read. помощью функций с помощью регулярных выражений (я использовал {stringr} библиотеку, чтобы минимизировать вызовы gsub ).

примечания:

  • таблица всегда начинается со 10th строки.
  • строки Positions, .... , содержащие, не содержат других данных.
  • одинаковое количество столбцов для всех строк, содержащих данные.

Используемые регулярные выражения

  • "(?<=n:) |:|Total Traders: \d |(?<= ) (?=[A-Za-z] \d , \d )" => "" :
    1. (?<=n:) обрезает пробелы.
    2. : удаляет его.
    3. Total Traders: \d удалите total traders …
    4. (?<= ) (?=[A-Za-z] \d , \d ) склеивает дату : Changes from: October 6, 2020 с первой частью.
  • " \n" => " " Например, склеивается Positions со следующей строкой.
  • " " => "@" преобразует 2 пробела или более в символ at, поскольку он будет использоваться позже в качестве разделителя значений.

Тестирование результатов:

 library(stringr)
txt <- ": Positions                                                                                                    :
:   16,643    17,427         0         0         0         0         0         0     1,820     1,036    11,401 :
:                                                                                                              :
: Changes from:     October 6, 2020                                                                            :
:     -264     1,739         0         0         0         0         0         0     1,122      -881       335 :
:                                                                                                              :
: Percent of Open Interest Represented by Each Category of Trader                                              :
:     55.7      58.4       0.0       0.0       0.0       0.0       0.0       0.0       6.1       3.5      38.2 :
:                                                                                                              :
: Number of Traders in Each Category                                  Total Traders:    22                     :
:       10        10         0         0         0         0         0         0         4         5         7 :"

cat(str_replace_all( gsub("(?<=n:) |:|Total Traders:  \d |  (?=[A-Za-z]  \d , \d )", "", txt, perl=T), c( "   \n"=" ", "   "="@")))

#> Positions@16,643@17,427@0@0@0@0@0@0@1,820@1,036@11,401 
#> Changes from October 6, 2020@-264@1,739@0@0@0@0@0@0@1,122@-881@335 
#> Percent of Open Interest Represented by Each Category of Trader@55.7@58.4@0.0@0.0@0.0@0.0@0.0@0.0@6.1@3.5@38.2 
#> Number of Traders in Each Category@10@10@0@0@0@0@0@0@4@5@7 

read.table(text=str_replace_all( gsub("(?<=n:) |:|Total Traders:  \d |(?<= )  (?=[A-Za-z]  \d , \d )", "", txt, perl=T), c( "   \n"=" ", "   "="@")), sep="@")

#>                                                                 V1     V2     V3 V4 V5 V6 V7 V8 V9   V10   V11    V12
#> 1                                                        Positions 16,643 17,427  0  0  0  0  0  0 1,820 1,036 11,401
#> 2                                     Changes from October 6, 2020   -264  1,739  0  0  0  0  0  0 1,122  -881    335
#> 3  Percent of Open Interest Represented by Each Category of Trader   55.7   58.4  0  0  0  0  0  0   6.1   3.5   38.2
#> 4                               Number of Traders in Each Category     10     10  0  0  0  0  0  0     4     5      7
  

Rcode

Сначала мы создаем функцию, которая берет полный сегмент из заголовка и далее и преобразует его в a data.frame . Я добавил некоторый код, чтобы сохранить некоторую информацию о каждой таблице.

 read.commodities <- function(x){
  txt <- paste0(x[10:length(x)], collapse="n")
  df <- read.table(text=str_replace_all( gsub("(?<=n:) |:|Total Traders:  \d |  (?=[A-Za-z]  \d , \d )", "", txt, perl=T), c( "   \n"=" ", "   |(?<=\d) (?=\d)"="@")), sep="@", header=F)
  attr(df, "CFTC Code") <- str_extract(x[9],"#\d ")
  attr(df, "Open Interest") <- trimws(str_extract(pattern="(?<=Open Interest is)  [\d,.] ",x[9]))
  attr(df, "Commodity") <- trimws(sub(":", "", x[8]))
  attr(df, "Caption") <- trimws(x[1])
  attr(df, "Date") <- str_extract(x[1], "[A-Z][a-z]  \d , \d ")
  colnames(df) <- c("Type", "PMLong", "PMShort", "SwapDLong", "SwapDShort", "SwapDSpreading", 
  "ManagedMoneyLong", "ManagedMoneyShort", "ManagedMoneySpreading", 
  "OtherLong", "OtherShort", "OtherSpreading")
  class(df) <- c("commodities", class(df))
  df
}
  

Пусть commodities — вектор символов, содержащий pre содержимое:

 commodities %>%
  strsplit("n- n(?=[^n:] n)", perl=T) %>%
  lapply(strsplit, "n") %>%
  `[[`(1) %>%
  lapply(read.commodities)
  

результат для таблицы на изображении

                                                               Type PMLong PMShort SwapDLong SwapDShort SwapDSpreading ManagedMoneyLong ManagedMoneyShort ManagedMoneySpreading OtherLong OtherShort OtherSpreading
1                                                        Positions  6,604  18,806         0        325             25           13,099                 0                   195         5        310           496 
2                                     Changes from October 6, 2020    811    -130         0          0              0           -1,136                 0                     0         5        119            41 
3  Percent of Open Interest Represented by Each Category of Trader   31.5    89.8         0        1.6            0.1             62.6                 0                   0.9       0.0        1.5           2.4 
4                               Number of Traders in Each Category      8      20         0          .              .                6                 0                     .         .          .             . 
  

данные

 library(rvest)
webpage <- read_html(url)
commodities <- webpage %>%
  html_nodes("pre") %>%
  html_text() %>% str_replace_all(c("\r\n"="n", "- nn |n n"=""))
  

Комментарии:

1. Безусловно правильный ответ. Возможно ли перехватить данные по открытому интересу (9-я строка)?

2. используйте attr(df, "Open Interest") , и у вас появится открытый интерес к этому df. Если вы хотите связать все dfs в один df, я могу помочь.

3. После обновления последнего отчета COT я получил следующую ОШИБКУ Ошибка в names (x) <- value: атрибут ‘names’ [12] должен иметь ту же длину, что и вектор [11] Можете ли вы помочь мне разобраться?

4. Пожалуйста, нужна ваша помощь

5. проблема здесь: colnames(df) <- c(«Type», «PMLong», «PMShort», «SwapDLong», «SwapDShort», «SwapDSpreading», «ManagedMoneyLong», «ManagedMoneyShort», «ManagedMoneySpreading», «OtherLong», «OtherShort», «OtherSpreading»)