#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 )" => ""
:(?<=n:)
обрезает пробелы.:
удаляет его.Total Traders: \d
удалите total traders …(?<= ) (?=[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»)