Как извлечь ключевые слова из URL-адреса страницы результатов поиска Google?

Одна из переменных в моем наборе данных содержит URL-адреса страниц результатов поиска Google. Я хочу извлечь ключевые слова для поиска из этих URL.

Пример набора данных:

keyw <- structure(list(user = structure(c(1L, 1L, 1L, 2L, 2L, 2L), .Label = c("p1", "p2"), class = "factor"),
                   url = structure(c(3L, 5L, 4L, 1L, 2L, 6L), .Label = c("https://www.google.nl/search?q=five+fingers&ie=utf-8&oe=utf-8&gws_rd=cr,ssl&ei=kERoVbmMO6fp7AaGioCYAw", "https://www.google.nl/search?q=five+fingers&ie=utf-8&oe=utf-8&gws_rd=cr,ssl&ei=kERoVbmMO6fp7AaGioCYAw#safe=off&q=five+short+fingers+", "https://www.google.nl/search?q=high+five&ie=utf-8&oe=utf-8&gws_rd=cr,ssl&ei=bENoVZSqL4ON7Qb5wIDIDg", "https://www.google.nl/search?q=high+five&ie=utf-8&oe=utf-8&gws_rd=cr,ssl&ei=bENoVZSqL4ON7Qb5wIDIDg#safe=off&q=high+five+with+a+chair", "https://www.google.nl/search?q=high+five&ie=utf-8&oe=utf-8&gws_rd=cr,ssl&ei=bENoVZSqL4ON7Qb5wIDIDg#safe=off&q=high+five+with+handshake", "https://www.youtube.com/watch?v=6HOallAdtDI"), class = "factor")), 
              .Names = c("user", "url"), class = "data.frame", row.names = c(NA, -6L))

До сих пор мне удалось извлечь части ключевых слов поиска из URL-адресов с помощью:

keyw$words <- sapply(str_extract_all(keyw$url, 'q=([^&#]*)'),paste, collapse=",")

Однако это все еще не дает мне желаемого результата. Вышеприведенный код дает следующий результат:

> keyw$words
[1] "q=high+five"                           
[2] "q=high+five,q=high+five+with+handshake"
[3] "q=high+five,q=high+five+with+a+chair"  
[4] "q=five+fingers"                        
[5] "q=five+fingers,q=five+short+fingers+"  
[6] ""                                      

Есть три проблемы с этим выходом:

  • Мне нужны только слова в виде строки. Вместо q=high+five мне нужно high,five.
  • Как показывают строки 2, 3 и 5, URL иногда содержит две части с ключевыми словами поиска. Поскольку первая часть - это просто ссылка на предыдущий поиск, мне нужен только второй поисковый запрос.
  • Если URL-адрес не является URL-адресом поисковой страницы Google, он должен вернуть NA

Желаемый результат должен быть:

> keyw$words
[1] "high,five"                           
[2] "high,five,with,handshake"
[3] "high,five,with,a,chair"  
[4] "five,fingers"                        
[5] "five,short,fingers"
[6] NA

Как это решить?

Ответ 1

Еще одно обновление после комментария (выглядит слишком сложно, но это лучшее, что я могу достичь на этом этапе:)):

keyw$words <- sapply(str_extract_all(str_extract(keyw$url,"https?:[/]{2}[^/]*google.*[/].*"),'(?<=q=|[+])([^$+#&]+)(?!.*q=)'),function(x) if(!length(x)) NA else paste(x,collapse=","))
> keyw$words
[1] "high,five"                "high,five,with,handshake" "high,five,with,a,chair"   "five,fingers"            
[5] "five,short,fingers"       NA             

Это изменение является фильтром при вводе в str_extract_all, измененным из полного вектора на "фильтрованный", чтобы соответствовать регулярному выражению, любое регулярное выражение может идти туда, чтобы соответствовать более или менее точно, что вы хотите.

Здесь регулярное выражение:

  • http litteraly http
  • s? 0 или 1 с
  • [/]{2} ровно две слэши (используя класс символов, избегая необходимости уродливой конструкции \\/ и читайте вещи более читабельными
  • [^/]* любое количество символов без косой черты
  • google.*[/] соответствует litteraly google, за которым следует что-либо до последнего /
  • .* наконец-то совпадет с чем-то или нет после последней косой черты

Замените * на +, где бы вы ни хотели, чтобы параметр (+ требовал, чтобы предыдущий символ присутствовал хотя бы один раз)


Обновление, сильно вдохновленное @BrodieG, вернет NA, если нет совпадения, но будет по-прежнему соответствовать любому сайту, если там q= в параметрах.

По-прежнему с тем же методом:

> keyw$words <- sapply(str_extract_all(keyw$url,'(?:(?<=q=|\\+)([^$+#&]+)(?!.*q=))'),function(x) if(!length(x)) NA else paste(x,collapse=","))
> keyw$words
[1] "high,five"                "high,five,with,handshake" "high,five,with,a,chair"  
[4] "five,fingers"             "five,short,fingers"       NA         

Демо-версия Regex

(Lookbehind (?<=) убедитесь, что q = или + где-то перед словом и отрицательный lookahead (?!) убедитесь, что мы не можем найти q = до конца строки.

Класс символов запрещает знак + останавливаться на каждом слове.

Ответ 2

Или, может быть, это

gsub("\\+", ",", gsub(".*q=([^&#]*[^+&]).*", "\\1", keyw$url))
# [1] "high,five"                "high,five,with,handshake" "high,five,with,a,chair"  
# [4] "five,fingers"             "five,short,fingers"  

Ответ 3

Обновление (заимствование части регулярного выражения от Дэвида):

dat <- as.character(keyw$url)
pat <- "^https://www\\.google\\.nl/.*\\bq=([^&]*[^&+]).*"
sapply(
  regmatches(dat, regexec(pat, dat)),
  function(x) if(!length(x)) NA else gsub("\\+", ",", x[[2]])
)

Выдает:

[1] "high,five"                "high,five,with,handshake" "high,five,with,a,chair"  
[4] "five,fingers"             "five,short,fingers"       NA   

Использование:

pat <- "^https://www\\.google.(?:com?.)?[a-z]{2,3}/.*\\b?q=([^&]*[^&+]).*"

учитывает все специфические для Google домены (источник)


Или:

gsub("\\+", ",", sub("^.*\\bq=([^&]*).*", "\\1", keyw$url))

Выдает:

[1] "high,five"                "high,five,with,handshake" "high,five,with,a,chair"  
[4] "five,fingers"             "five,short,fingers,"     

Здесь мы используем жадность, чтобы убедиться, что мы пропустим все до последней части q=..., а затем используем стандартный трюк sub/\\1 для захвата того, что мы хотим. Наконец, замените + на ,.

Ответ 4

Там должен быть более чистый способ, но может быть что-то вроде:

sapply(strsplit(keyw$words, "q="), function(x) {
  x <- if (length(x) == 2) x[2] else x[3]
  gsub("+", ",", gsub("\\+$", "", x), fixed = TRUE)
})
# [1] "high,five"                "high,five,with,handshake" "high,five,with,a,chair"  
# [4] "five,fingers"             "five,short,fingers" 

Все в одном:

keyw$words <- sapply(str_extract_all(keyw$url, 'q=([^&#]*)'),function(x) {
  x <- if (length(x) == 2) x[2] else x[1]
  x <- gsub("+", ",", gsub("\\+$", "", x), fixed = TRUE)
  gsub("q=","",x, fixed = TRUE)
})

Ответ 5

Я бы попробовал:

x<-as.character(keyw$url)
vapply(regmatches(x,gregexpr("(?<=q=)[^&]+",x,perl=TRUE)),
       function(y) paste(unique(unlist(strsplit(y,"\\+"))),collapse=","),"")
#[1] "high,five"                "high,five,with,handshake"
#[3] "high,five,with,a,chair"   "five,fingers"            
#[5] "five,fingers,short"