2013-06-24 9 views
13

У меня есть список URL-адресов, которые я хотел бы проанализировать и нормализовать.Есть ли у R какой-либо пакет для разбора частей URL-адреса?

Я хотел бы иметь возможность разделить каждый адрес на части, чтобы я мог идентифицировать «www.google.com/test/index.asp» и «google.com/somethingelse» как находящиеся на одном и том же сайте.

+2

Какой у вас предполагаемый выход? – Thomas

+0

Идеальный случай был бы тем, что разделяет такие вещи, как [tldextract] (https://pypi.python.org/pypi/tldextract), но если это не доступно, я хотел бы вернуть строку до конца домена верхнего уровня (например, .com или .edu). Предпочтительно, он также удалит http: // и www. и другие префиксы, подобные этому. –

+0

Не могли бы вы дать нам пример вывода того, что вы ожидаете от своего примера, вместо того, чтобы давать нам URL для синтаксического анализа и чтения. –

ответ

10

Поскольку parse_url() использует регулярные выражения в любом случае, мы можем также изобрести колесо и создать регулярное выражение замену для того, чтобы построить сладкий и фантазии gsub вызова.

Давайте посмотрим. URL-адрес состоит из протокола, «netloc», который может включать имя пользователя, пароль, имя хоста и компоненты порта, а также остаток, который мы счастливо убираем. Предположим, что сначала нет ни имени пользователя, ни пароля, ни порта.

  • ^(?:(?:[[:alpha:]+.-]+)://)? будет соответствовать заголовок протокола (скопированный из parse_url()), мы вскрышных это далеко, если мы находим
  • Кроме того, потенциальный www. префикс отбрасываются, но не захватили: (?:www\\.)?
  • Anything вверх к последующему слэш будет наше полное имя хоста, которое мы фиксируем: ([^/]+)
  • остальное мы игнорируем: .*$

Теперь мы подключить вместе регулярные выражения выше, и извлечение имени хоста становится:

PROTOCOL_REGEX <- "^(?:(?:[[:alpha:]+.-]+)://)?" 
PREFIX_REGEX <- "(?:www\\.)?" 
HOSTNAME_REGEX <- "([^/]+)" 
REST_REGEX <- ".*$" 
URL_REGEX <- paste0(PROTOCOL_REGEX, PREFIX_REGEX, HOSTNAME_REGEX, REST_REGEX) 
domain.name <- function(urls) gsub(URL_REGEX, "\\1", urls) 

Изменить имя хоста регулярное выражение включает (но не захват) порт:

HOSTNAME_REGEX <- "([^:/]+)(?::[0-9]+)?" 

и так далее, и и так далее, пока мы наконец не достигнем RFC-compliant regular expression for parsing URLs. Тем не менее, для домашнего использования, выше должно хватить:

> domain.name(c("test.server.com/test", "www.google.com/test/index.asp", 
       "http://test.com/?ex")) 
[1] "test.server.com" "google.com"  "test.com"  
+2

Преимущество использования кода в пакете состоит в том, что он поставляется с модульными тестами, и вы можете записывать отчеты об ошибках, а кто-то другой может исправить ошибку. – hadley

+0

@hadley: Спасибо, что комментировали это. Тем не менее, я не нашел модульные тесты для 'parse_url'. Если они были доступны, 'parse_url' можно было бы переписать так, чтобы одно регулярное выражение использовалось для захвата всех частей URL-адреса. - По замыслу, что префикс протокола является обязательным для 'parse_url'? – krlmlr

+0

Да, я должен был сказать, что преимущество пакета заключается в том, что он должен иметь модульные тесты. Патчи приветствуются;) Я бы сказал, что текущий ответ верен, когда схема опущена - если вы использовали этот URL-адрес на веб-странице, это не приведет вас к google.com. – hadley

4

Я бы отказался от пакета и использовал для этого регулярное выражение.

EDIT переформулируется после робота атаки Dason ...

x <- c("talkstats.com", "www.google.com/test/index.asp", 
    "google.com/somethingelse", "www.stackoverflow.com", 
    "http://www.bing.com/search?q=google.com&go=&qs=n&form=QBLH&pq=google.com&sc=8-1??0&sp=-1&sk=") 

parser <- function(x) gsub("www\\.", "", sapply(strsplit(gsub("http://", "", x), "/"), "[[", 1)) 
parser(x) 

lst <- lapply(unique(parser(x)), function(var) x[parser(x) %in% var]) 
names(lst) <- unique(parser(x)) 
lst 

## $talkstats.com 
## [1] "talkstats.com" 
## 
## $google.com 
## [1] "www.google.com/test/index.asp" "google.com/somethingelse"  
## 
## $stackoverflow.com 
## [1] "www.stackoverflow.com" 
## 
## $bing.com 
## [1] "http://www.bing.com/search?q=google.com&go=&qs=n&form=QBLH&pq=google.com&sc=8-1??0&sp=-1&sk=" 

Это, возможно, потребуется расширить в зависимости от структуры данных.

+0

Кто-то на самом деле создал для URL-адресов [RFC-совместимое регулярное выражение] (http://stackoverflow.com/a/190405/946850). Это не для слабонервных, и здесь должен быть предпочтительным выделенный парсер URL ... – krlmlr

+0

Возможно, вы правы, но это решение не использует R. –

+2

'x <-" http://www.bing. com/search? q = google.com & go = & qs = n & form = QBLH & pq = google.com & sc = 8-10 & sp = -1 & sk = "' Вы только что определили bing как google. – Dason

10

Вы можете использовать функцию пакета R HTTR

parse_url(url) 
>parse_url("http://google.com/") 

Вы можете получить более подробную информацию здесь: http://cran.r-project.org/web/packages/httr/httr.pdf

+1

Не могли бы вы предоставить пример вывода для одного из URL-адресов OP предоставил? – krlmlr

+1

Это получает тонну upvotes, поэтому я должен что-то упускать. Как это может помочь определить, какие URL-адреса принадлежат вместе? –

+0

'parse_url (" www.google.com/test/index.asp ") $ path 'дает результат ' 'www.google.com/test/index.asp" ' , что не очень полезно. –

3

Опираясь на ответ R_Newbie, вот это функция, которая будет извлекать имя сервера с помощью (вектора) URL-адресов, удаляя префикс www., если он существует, и изящно игнорирует отсутствующий префикс протокола.

domain.name <- function(urls) { 
    require(httr) 
    require(plyr) 
    paths <- laply(urls, function(u) with(parse_url(u), 
              paste0(hostname, "/", path))) 
    gsub("^/?(?:www\\.)?([^/]+).*$", "\\1", paths) 
} 

parse_url функция используется для извлечения path аргумента, который дополнительно обрабатывается gsub. /? и (?:www\\.)? части регулярного выражения будут соответствовать необязательной ведущей косой чертой, за которой следует необязательный www., а [^/]+ соответствует всем, что есть после этого, но до первой косой черты - это захватывается и эффективно используется в тексте замены вызова gsub.

> domain.name(c("test.server.com/test", "www.google.com/test/index.asp", 
       "http://test.com/?ex")) 
[1] "test.server.com" "google.com"  "test.com"  
+0

В этом есть тонна дополнительных накладных расходов в том, что 'parse_url' генерирует больший список информации, чем тот, который необходим, и выход еще нуждается в регулярном выражении. Я действительно думаю, что подход perl, о котором вы говорили, может быть полезен. –

2

Если вы хотите tldextract один вариант будет использовать версию на AppEngine

require(RJSONIO) 
test <- c("test.server.com/test", "www.google.com/test/index.asp", "http://test.com/?ex") 
lapply(paste0("http://tldextract.appspot.com/api/extract?url=", test), fromJSON) 
[[1]] 
    domain subdomain  tld 
"server" "test"  "com" 

[[2]] 
    domain subdomain  tld 
"google"  "www"  "com" 

[[3]] 
    domain subdomain  tld 
    "test"  ""  "com" 
+0

Это умный, я раньше этого не видел. –

5

Там также urltools пакет, в настоящее время, что бесконечно быстрее:

urltools::url_parse(c("www.google.com/test/index.asp", 
         "google.com/somethingelse")) 

##     scheme   domain port   path parameter fragment 
## 1  www.google.com  test/index.asp     
## 2   google.com  somethingelse     
+1

Это действительно намного лучше, чем httr :: url_parse, не только для быстрой скорости, но и для векторизации (не нужно использовать * применять) – haddr