#r #selenium #web-scraping
#r #селен #очистка веб-страниц
Вопрос:
Я пытаюсь очистить текст с этой веб-страницы (нажмите «Открыть все уровни» для лучшего понимания) Ожидаемый результат — это весь текст в таблице, который вы видите в столбце, и количество подуровней, из которых он состоит.
Динамический xpath, который я пробовал
treeView <- rawdata %>%
html_nodes(xpath = '//div//p[contains(@class, "Mui")]') %>%
html_text(trim = TRUE)
дает текст, который мне нужен, но не показатели того, сколько уровней (или строк) внутри. Какие-либо решения, позволяющие сделать это возможным?
редактировать: добавлен еще один рисунок
-
Первый текст, который мы имеем в этом примере, «Электродвигатели и генераторы (за исключением генераторных установок)». будет равно нулю (что означает, что у него нет родительского уровня)
-
Второй текст; (Двигатели мощностью не более 37,5 Вт) имеет одного родителя, поэтому его подуровень равен 1.
-
То же самое относится и к 3-му и 4-му (у них есть только один родительский элемент, поэтому его подуровень равен 1).
-
Давайте посмотрим на 5-й (с мощностью, не превышающей 750 Вт), у него есть один родительский элемент (4-й текст и который, в свою очередь, имеет 1 родительский элемент). Это делает 5-й текстовый подуровень равным 2. Это также относится ко всему тексту с 6-го по 8-й. (1 родитель 1 родитель для родителя = 2)
-
9-й и 10-й имеют одного родителя, поэтому они имеют подуровень 1.
-
11-й и 12-й имеют одного родителя, а у родителя есть один родитель, поэтому его подуровень равен 2.
-
13-й текст (двигатели переменного тока с редукторами или преобразователями скорости 🙂 имеет 1 родительский элемент (и последующие 2 родительских элемента). Таким образом, его подуровень равен 3.
Ответ №1:
Вы не можете этого сделать, потому что контент на этом веб-сайте отображается с помощью javascript. К счастью, если вы исследуете трафик на этом веб-сайте, вы можете найти API, который предоставляет вам необходимые данные.
Тогда мы можем просто
library(httr)
json_list <- content(GET("https://tolltariffen.toll.no/api/search/headings/85.01"))
Чтобы преобразовать список в ожидаемый результат, нам нужно написать простую функцию для рекурсивной распаковки значений из этого списка. Что-то вроде этого
recur_pluck <- function(x) {
sublevel <- integer()
text <- character()
recur_ <- function(x) {
text <<- c(text, trimws(gsub("<[^<>] >", "", x$description$en)))
if (is.null(x$headingItems)) {
sublevel <<- c(sublevel, 1L)
return(NULL)
}
sublevel <<- c(sublevel, length(x$headingItems))
lapply(x$headingItems, recur_)
}
recur_(x)
data.frame(sublevel, text)
}
Тогда мы можем просто
recur_pluck(json_list)
что дает вам
sublevel text
1 6 Electric motors and generators (excluding generating sets).
2 1 Motors of an output not exceeding 37.5 W
3 1 Universal AC/DC motors of an output exceeding 37.5 W
4 4 Other DC motors; DC generators :
5 1 Of an output not exceeding 750 Wamp;nbsp;
6 1 Of an output exceeding 750 W but not exceeding 75 kWamp;nbsp;
7 1 Of an output exceeding 75 kW but not exceeding nn 375 kW
8 1 Of an output exceeding 375 kW
9 1 Other AC motors, single-phase
10 3 Other AC motors, multi-phase :
11 1 Of an output not exceeding 750 Wamp;nbsp;
12 2 Of an output exceeding 750 W but not exceeding nn 75 kW :
13 2 AC motors with gear or speed converters :
14 1 Of an output exceeding 750 W but not exceeding 15 kW
15 1 Of an output exceeding 15 kW but not exceeding 75 kW
16 3 Other :
17 1 Of an output exceeding 750 W but not exceeding 7.5 kW
18 1 Of an output exceeding 7.5 kW but not exceeding 22 kW
19 1 Of an output exceeding 22 kW but not exceeding 75 kW
20 1 Of an output exceeding 75 kWamp;nbsp;
21 4 AC generators (alternators) :
22 1 Of an output not exceeding 75 kVA
23 1 Of an output exceeding 75 kVA but not exceeding nn 375 kVA
24 1 Of an output exceeding 375 kVA but not exceeding 750 kVA
25 1 Of an output exceeding 750 kVA
Обновить
Эта функция дает вам подуровень в торговой области.
recur_pluck <- function(x) {
sublevel <- integer()
text <- character()
recur_ <- function(x, depth = 0L) {
text <<- c(text, trimws(gsub("<[^<>] >", "", x$description$en)))
sublevel <<- c(sublevel, depth)
if (is.null(x$headingItems)) {
return(NULL)
}
lapply(x$headingItems, recur_, depth 1L)
}
recur_(x)
data.frame(sublevel, text)
}
Обновление 2
`%||%` <- function(x, y) if (is.null(x)) y else x
recur_pluck <- function(x) {
sublevel <- integer()
code <- character()
text <- character()
recur_ <- function(x, depth = 0L) {
text <<- c(text, trimws(gsub("<[^<>] >", "", x$description$en)))
sublevel <<- c(sublevel, depth)
code <<- c(code, x$commodityCode %||% x$headingCode %||% "")
if (is.null(x$headingItems)) {
return(NULL)
}
lapply(x$headingItems, recur_, depth 1L)
}
recur_(x)
data.frame(sublevel, code, text)
}
Пояснения
%||%
это простая функция, которая возвращает y, если x равно НУЛЮ (он же не существует) или x в противном случае. recur_pluck
это рекурсивная функция, которая проходит через каждый элемент в списке (т.е. x
). Функция может быть интерпретирована как сначала определяющая некоторые переменные для хранения нужных нам данных, затем определяющая способ обхода (т.Е. recur_
), затем просматривающая список ( recur_(x)
) и, наконец, возвращающая эти переменные хранилища вместе в виде фрейма данных.
recur_pluck <- function(x) {
sublevel <- integer()
code <- character()
text <- character()
recur_ <- function(x, depth = 0L) {...}
recur_(x)
data.frame(sublevel, code, text)
}
Далее, recur_
определяется следующим образом:
-
Для каждого элемента функция добавляет целевые данные в соответствующие переменные хранилища
text
,sublevel
иcode
. Мы используем эту%||%
функцию при добавлении данныхcode
, поскольку требуемый 8-значный код может иметь разные имена. Эта строка просто переводится сначала на получение «commodityCode», затем «Код заголовка», если «commodityCode» отсутствует, или просто возвращает пустую строку, если ничего не может быть найдено.text <<- c(text, trimws(gsub("<[^<>] >", "", x$description$en))) sublevel <<- c(sublevel, depth) code <<- c(code, x$commodityCode %||% x$headingCode %||% "")
-
Это заканчивается, если внутри списка больше ничего нет.
if (is.null(x$headingItems)) { return(NULL) }
-
Он проходит глубже с подсчетом глубины плюс 1, если внутри есть другие
headingItems
.lapply(x$headingItems, recur_, depth 1L)
Конечный результат
sublevel code text
1 0 85.01 Electric motors and generators (excluding generating sets).
2 1 85.01.1000 Motors of an output not exceeding 37.5 W
3 1 85.01.2000 Universal AC/DC motors of an output exceeding 37.5 W
4 1 Other DC motors; DC generators :
5 2 85.01.3100 Of an output not exceeding 750 Wamp;nbsp;
6 2 85.01.3200 Of an output exceeding 750 W but not exceeding 75 kWamp;nbsp;
7 2 85.01.3300 Of an output exceeding 75 kW but not exceeding nn 375 kW
8 2 85.01.3400 Of an output exceeding 375 kW
9 1 85.01.4000 Other AC motors, single-phase
10 1 Other AC motors, multi-phase :
11 2 85.01.5100 Of an output not exceeding 750 Wamp;nbsp;
12 2 Of an output exceeding 750 W but not exceeding nn 75 kW :
13 3 AC motors with gear or speed converters :
14 4 85.01.5201 Of an output exceeding 750 W but not exceeding 15 kW
15 4 85.01.5202 Of an output exceeding 15 kW but not exceeding 75 kW
16 3 Other :
17 4 85.01.5203 Of an output exceeding 750 W but not exceeding 7.5 kW
18 4 85.01.5204 Of an output exceeding 7.5 kW but not exceeding 22 kW
19 4 85.01.5205 Of an output exceeding 22 kW but not exceeding 75 kW
20 2 85.01.5300 Of an output exceeding 75 kWamp;nbsp;
21 1 AC generators (alternators) :
22 2 85.01.6100 Of an output not exceeding 75 kVA
23 2 85.01.6200 Of an output exceeding 75 kVA but not exceeding nn 375 kVA
24 2 85.01.6300 Of an output exceeding 375 kVA but not exceeding 750 kVA
25 2 85.01.6400 Of an output exceeding 750 kVA
Комментарии:
1. спасибо за ваш ответ. что означает регулярное выражение «<[^<>] >» имею в виду ?
2. Я использую это регулярное выражение для удаления тегов HTML, но сохраняю содержимое между ними, потому
description$en
что в списке JSON всегда есть строка HTML.<
и>
являются буквальными символами.[^<>]
означает один или несколько символов, которые не<
являются или>
. @Frodo3. спасибо за эту часть. но похоже, что подуровни записаны неправильно для нескольких текстов. можете ли вы сказать мне, какую логику вы использовали для его поиска? @ekoam
4. Привет @Frodo, я рассматриваю подуровни как количество дочерних ветвей родительской ветви. Например, я рассматриваю «Другие двигатели постоянного тока; Генераторы постоянного тока», имеющие 4 подуровня: 1) Мощностью не более 750 Вт, 2) Мощностью более 750 Вт, но не более 75 кВт, 3) Мощностью более 75 кВт, но не более 375 кВт и 4)Мощности, превышающей 375 кВт, как показано на этом веб-сайте. Однако ваше изображение говорит мне, что оно имеет только 2. Возможно, наши определения смещены. Не могли бы вы уточнить свой?
5. Извините, что не было ясно в начале. Это концепция, используемая в области торговли. подуровни / отступы используются для определения уровня иерархии текста. Добавлены детали в OP и добавлено новое изображение с подуровнями, которое является ожидаемым результатом. Дайте мне знать, если вам нужна дополнительная информация. @ekoam