13

我有一个要解析和规范化的 url 列表。

我希望能够将每个地址分成几部分,以便我可以将“www.google.com/test/index.asp”和“google.com/somethingelse”识别为来自同一个网站。

4

6 回答 6

12

由于parse_url()无论如何都使用正则表达式,我们不妨重新发明轮子并创建一个正则表达式替换,以构建一个甜蜜而花哨的gsub调用。

让我们来看看。一个 URL 由一个协议、一个“netloc”组成,它可能包括用户名、密码、主机名和端口组件,以及我们很乐意剥离的其余部分。让我们首先假设没有用户名、密码或端口。

  • ^(?:(?:[[:alpha:]+.-]+)://)?将匹配协议标头(从 复制parse_url()),如果我们找到它,我们将删除它
  • 此外,潜在的www.前缀被剥离,但未被捕获:(?:www\\.)?
  • 后面的斜线之前的任何内容都是我们的完全限定主机名,我们会捕获它:([^/]+)
  • 其余的我们忽略:.*$

现在我们把上面的正则表达式拼在一起,主机名的提取就变成了:

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 的用于解析 URL 的正则表达式。但是,对于家庭使用,以上内容就足够了:

> 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"       
于 2013-06-25T00:50:58.643 回答
11

可以使用R包httr的功能

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

您可以在此处获取更多详细信息:http: //cran.r-project.org/web/packages/httr/httr.pdf

于 2013-06-24T21:43:01.720 回答
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                   
于 2016-01-17T13:58:48.110 回答
4

我会放弃一个包并为此使用正则表达式。

编辑在 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="

这可能需要根据数据的结构进行扩展。

于 2013-06-24T21:38:08.143 回答
3

www.基于 R_Newbie 的回答,这里有一个函数,它将从 URL(向量)中提取服务器名称,如果存在前缀,则剥离它,并优雅地忽略丢失的协议前缀。

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。正则表达式的/?and(?: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"       
于 2013-06-24T22:56:36.223 回答
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" 
于 2013-06-25T04:02:05.317 回答