安装RSelenium包
install.packages("RSelenium")
启动Selenium服务器
- 在控制台输入
java -jar D:\R\library\Rwebdriver\selenium-server-standalone-3.7.1.jar以启动Selenium服务器。保持打开状态,可配合plantomjs、Chrome或Firefox等浏览器使用
- 本次案例选择chrome浏览器自动抓取,需要下载相应的浏览器驱动(参考Selenium环境配置第3部分)
思路
library(rvest)
library(stringr)
library(RSelenium)
remDr <- remoteDriver(browserName = "chrome")
base1 <- "https://hui.lianjia.com/ershoufang/"
base2 <- c("danshui", "huiyangqu", "nanzhanxincheng")
url <- paste(base1, base2, "/", sep = "")
LinkinfoFunc <- function(remDr, url) {
result <- data.frame()
remDr$open()
for (i in seq_along(url)) {
remDr$navigate(url[i])
j = 0
while (TRUE) {
j = j + 1
destination <- remDr$getPageSource()[[1]] %>% read_html()
link <- destination %>% html_nodes("li.clear div.title a") %>% html_attr("href")
pageinfo <- destination %>% html_nodes("div.house-lst-page-box") %>%
html_attr("page-data") %>% str_extract_all(., ":[\\d]+") %>%
unlist() %>% gsub(":", "", .)
totalpage <- pageinfo[1]
curpage <- pageinfo[2]
data <- data.frame(link, stringsAsFactors = FALSE)
result <- rbind(result, data)
if (curpage != totalpage) {
cat(sprintf("第【%d】个地区第【%d】页抓取成功", i, j), sep = "\n")
remDr$executeScript("arguments[0].click();",
list(remDr$findElement("css", "div.house-lst-page-box a.on+a")))
} else {
cat(sprintf("第【%d】个地区第【%d】页抓取成功", i, j), sep = "\n")
break
}
}
cat(sprintf("第【%d】个地区抓取成功", i), sep = "\n")
}
remDr$close()
cat("All work is done!", sep = "\n")
return(result)
}
HouseinfoFunc <- function(link) {
result <- data.frame()
for (i in seq_along(link)) {
destianation <- read_html(link[i], encoding = "UTF-8")
location <- destianation %>% html_nodes("a.no_resblock_a") %>% html_text()
unit <- destianation %>% html_nodes(".price span.unit") %>% html_text()
totalprice <- destianation %>% html_nodes(".price span.total:nth-child(1)") %>%
html_text() %>% paste(., unit, sep = "")
downpayment <- destianation %>% html_nodes(".taxtext span") %>% html_text() %>% .[1]
persquare <- destianation %>% html_nodes("span.unitPriceValue") %>% html_text()
area <- destianation %>% html_nodes(".area .mainInfo") %>% html_text()
title <- destianation %>% html_nodes(".title h1") %>% html_text()
subtitle <- destianation %>% html_nodes(".title div.sub") %>% html_text()
room <- destianation %>% html_nodes(".room .mainInfo") %>% html_text()
floor <- destianation %>% html_nodes(".room .subInfo") %>% html_text()
data <- data.frame(location, totalprice, downpayment, persquare,
area, title, subtitle, room, floor)
result <- rbind(result, data)
cat(sprintf("第【%d】条房屋链接抓取成功", i), sep = "\n")
}
cat("All work is done!", sep = "\n")
return(result)
}
linkinfo <- LinkinfoFunc(remDr, url) %>% unlist()
houseinfo <- HouseinfoFunc(linkinfo)
View(houseinfo)
write.table(houseinfo, row.names = FALSE, sep = ",", "houseinfo.csv")
- 查看数据

总结
- 本例使用chrome浏览器打开网页,因此不需要伪造User-Agent。如使用phantomjs无头浏览器,则要伪造一个User-Agent:
myheader <- list(phantomjs.page.settings.userAgent =
"Mozilla/5.0 (Windows NT 6.1; WOW64;
rv:29.0) Gecko/20120101 Firefox/29.0")
remDr <- remoteDriver(browserName = "phantomjs", extraCapabilities = myheader)
- 链家网的数据其实并不需要动用Selenium服务器,所有房屋信息在源代码中都能找到。另外,url的变化也十分有规律,最原始的方法是查看各个地区的页数,然后手动构造所有页数,例如,淡水共46页、惠阳区共4页、南站新城共27页:
base <- "https://hui.lianjia.com/ershoufang/"
url1 <- paste0(base, "danshui/pg", 1:46, "/")
url2 <- paste0(base, "huiyangqu/pg", 1:4, "/")
url3 <- paste0(base, "nanzhanxincheng/pg", 1:27, "/")
url <- c(url1, url2, url3)
这里主要用RSelenium包尝试点击下一页的功能,因为各地区总页数不一定总是46、4、27,如果手动构造,容易漏掉或重复抓取。模拟点击可以通过if函数判断当前页是否达到最后一页,yes则停止,no则继续点击。过程中遇到一些错误,并得到迂回解决:
【错误一】自动点击下一页出现问题,有两种解决办法:
- 一是直接点击“下一页”这个按钮(如果页面有这个按钮的话),直接找到这个按钮的css或xpath
- 二是点击“当前页+1”(如当前第1页,则直接点击第2页),相邻兄弟选择器(+):本例a.on是当前页,+a即下一页

【错误二】点击过程中,页面有无关的导航栏挡住“下一页”按钮,导致无法点击并报错,尝试两种办法:
- 一是换为phantomjs来驱动模拟点击,而非chrome
- 二是使用函数executeScript执行一个JavaScript片段
arguments[0].click();。该函数会将JavaScript片段视为参数来执行,而JavaScript片段可以返回首个(JavaScript中索引值是以0位基准)webElement,并实现点击。
由于基本没有设置拦截,数据抓取速度约1-2条/秒
参考资料:
RSelenium and Javascript
click on next button :rseleniun
左手用R右手Python系列——动态网页抓取与selenium驱动浏览器
|