从R中从网站抓取的段落文本创建数据框

时间:2019-08-22 19:42:56

标签: r web-scraping tidyverse rvest

我正在尝试抓取一个网站,该网站包含我在段落中想要的许多不同信息。我使它可以完美工作...但是,我不知道如何分解文本并创建数据框。

网站: Website I want Scraped

代码:

library(rvest)
url <- "https://www.state.nj.us/treasury/administration/statewide-support/motor-fuel-locations.shtml"

#Reading the HTML code from the website
webpage <- read_html(url)


p_nodes<-webpage%>%
  html_nodes(xpath = '//p')%>%
  html_text()

#replace multiple whitespaces with single space
p_nodes<- gsub('\\s+',' ',p_nodes)
#trim spaces from ends of elements
p_nodes <- trimws(p_nodes)
#drop blank elements
p_nodes <- p_nodes[p_nodes != '']

我希望数据框如何显示:

enter image description here

我不确定这是否可能。我试图分别提取每条信息,然后像这样制作数据框,但是由于大多数信息都存储在p标记中,因此它不起作用。我将不胜感激。谢谢!

2 个答案:

答案 0 :(得分:1)

概念验证(基于我在评论中写的内容):

代码

lapply(c('data.table', 'httr', 'rvest'), library, character.only = T)

tags <- 'tr:nth-child(6) td , tr~ tr+ tr p , td+ p'
burl <- 'https://www.state.nj.us/treasury/administration/statewide-support/motor-fuel-locations.shtml'

url_text <- read_html(burl)

chunks <- url_text %>% html_nodes(tags) %>% html_text()

coordFunc <- function(chunk){
  patter_lat <- 'Longitude:.*(-[[:digit:]]{1,2}.[[:digit:]]{0,15})'
  ret <- regmatches(x = chunk, m = regexec(pattern = patter_lat, text = chunk))
  return(ret[[1]][2])
}

longitudes <- as.numeric(unlist(lapply(chunks, coordFunc)))

输出

# using 'cat' to make the output easier to read 
> cat(chunks[14])
Mt.    Laurel DOT
                  Rt. 38, East
                  1/4 mile East of Rt. 295
                  Mt. Laurel Open 24 Hrs
                  Unleaded / Diesel
                  856-235-3096Latitude:  39.96744662Longitude: -74.88930386 


> longitudes[14]
[1] -74.8893

如果您不强迫longitudes成为numeric,则会得到:

longitudes <- (unlist(lapply(chunks, coordFunc)))
> longitudes[14]
[1] "-74.88930386"

我选择了经度作为概念验证,但是您可以修改函数以在单个调用中提取所有相关位。为了获得正确的tag,您可以使用SelectorGadget扩展程序(在Chrome浏览器中对我来说效果很好)。通常,大多数浏览器都允许您“检查元素”以获取html标签。该函数可以将提取的值返回到data.table中,然后可以使用rbindlist将其合并为一个值。

您甚至可以通过编程方式推进页面以抓取整个网站-请务必查看使用政策(通常不赞成或仅限于抓取网站)。

修改

文本在整个网页中的结构不同,因此您需要花费更多时间检查可能发生的异常。

这是一个新功能,用于将每个块解析为单独的行,然后您可以尝试使用其他正则表达式来获取所需的内容。

newfunc <- function(chunk){
  # Each chunk is a couple of lines. First, we split at '\r\n' using strsplit
  # the output is a list so we use 'unlist' to get a vector 
  # then use 'trimws' to remove whitespace around it - try out each of these functions
  # separately to understand what is going on. The final output here is a vector. 
  txt <- trimws(unlist(strsplit(chunk, '\r\n'))) 
  return(txt)
}

这将返回每个块中包含的“文本”作为单独行的向量。看一下前20个块中的行数,您会发现它是不同的:

> unlist(lapply(chunks[1:20], function(z) length(newfunc(z))))
 [1] 5 6 5 7 5 5 5 5 5 4 1 6 6 6 5 1 1 1 5 6

解决此问题的一种好方法是根据每个块中的文本行数(例如在newfunc中,您可以添加:

if(length(txt) == 1){
return(NULL)
}

这是因为这是针对其中没有任何文本的条​​目的。由于这是概念验证,因此我没有检查所有条目,但是有一些简单的逻辑:

  1. 第一行通常是名称
  2. 坐标在最后一行
  3. 燃料可以是unleadeddiesel。您可以在这两个字符串上grep来查看每个仓库提供的内容。例如grepl('diesel', newfunc(chunks[12]))
  4. 另一种方法是使用一组不同的html标签,例如所有协调和开放时间均以黑体显示,并带有标签strong。您可以分别提取它们,然后使用正则表达式获取所需的内容。
  5. 您可以搜索24(Hrs|Hours),以首先提取所有24小时开放的网站,然后对其余部分使用选择性的regex,以获取其运行时间。

对于大多数网络抓取,没有简单容易的答案,您必须找到模式,然后基于此模式应用一些逻辑。只有在结构最完整的网站上,您才能找到适用于整个页面/范围的内容。

答案 1 :(得分:0)

您可以使用tidyverse程序包(stringr,tibble,purrr)

library(rvest)
library(tidyverse)
url <- "https://www.state.nj.us/treasury/administration/statewide-support/motor-fuel-locations.shtml"
#Reading the HTML code from the website
webpage <- read_html(url)
p_nodes<-webpage%>%
  html_nodes(xpath = '//p')%>%
  html_text()
# Split on new line
l = p_nodes %>% stringr::str_split(pattern = "\r\n")
var1 = sapply(l, `[`, 1) # replace var by the name you want
var2 = sapply(l, `[`, 2)
var3 = sapply(l, `[`, 3)
var4 = sapply(l, `[`, 4)
var5 = sapply(l, `[`, 5)
t = tibble(var1,var2,var3,var4,var5) # make tibble
t = t %>% filter(!is.na(var2)) # delete useless lines
purrr::map_dfr(t,trimws) # delete blanks