使用 R 进行网页抓取(抓取隐藏数字 "Click here to show number" )
Web scraping with R (Scrape Hidden Number "Click here to show number" )
作为数据科学团队的实习生,我的任务是使用 R 找到一种自动收集房地产广告网站上特定数据的方法。
感谢 post (Web scraping with R over real estate ads) 中给出的答案和代码中的一些更改,我设法完成了我想要的任务。但我的问题是我无法抓取 phone 号码。我尝试了几件事但没有成功。
我想做与之前 post 完全相同的事情,但使用 phone 数字作为新变量。
这是广告的详细信息:https://www.leboncoin.fr/ventes_immobilieres/1074663461.htm?ca=13_s 我的变量是:价格 ("Prix")、城市 ("Ville")、表面 ("surface" )、"GES, the "Classe énergie"、房间数量 ("Pièces") 和 phone 数量,以及广告中显示的图片数量。
我注意到答案中给出的代码不再有效,因为在提出问题时,网站不安全 (http)。今天它包括开头 'https'。这就是我对代码进行一些更改的原因。
我是 R 的初学者,非常感谢任何帮助(抱歉我的英语不好)。
get_ad_links = function(page){
require(rvest)
# construct url to page (!when running the code put the url in 1 line!)
url_base = "https://www.leboncoin.fr/ventes_immobilieres/offres/
languedoc_roussillon/pyrenees_orientales"
url = paste(url_base, "?o=", page,"&ret=1&ret=2&f=p", sep = "")
page = read_html(url)
# extract links to ads on page
a="//*/section/section/ul/li["
b="]/a/@href"
t =lapply(1:30, function(i) paste(a,i,b, sep = ""))
ad_links = sapply(1:30,function(i) { page %>%
html_node(xpath=as.character(t[i])) %>% html_text()})
return(ad_links)
}
# Function to Get Ad Details by Ad URL
get_ad_details = function(ad_url){
require(rvest)
# parse ad url to html tree
doc = read_html(paste("https:",ad_url,sep=""))
# extract labels and values using xpath expression
pattern<- "</?\w+((\s+\w+(\s*m\s*(?:\".*?
\"|'.*?'[^'\">\s]+))?)+\s*|\s*)/?>"
prix = doc %>%
html_node(xpath="//section/section/section[2]/div[4]/h2/span[2]") %>%
html_text()
PRIX = stringr::str_replace_all(prix,pattern,"")
PRIX =stringr::str_wrap(PRIX)
ville = doc %>%
html_node(xpath="//section/section/section[2]/div[5]/h2/span[2]") %>%
html_text()
VILLE = stringr::str_replace_all(ville,pattern,"")
VILLE = stringr::str_wrap(VILLE)
surface = doc %>%
html_node(xpath="//section/section/section[2]/div[8]/h2/span[2]") %>%
html_text()
SURFACE = stringr::str_replace_all(surface,pattern,"")
SURFACE = stringr::str_wrap(SURFACE)
pieces = doc %>%
html_node(xpath="//section/section/section[2]/div[7]/h2/span[2]") %>%
html_text()
PIECES = stringr::str_replace_all(pieces,pattern,"")
PIECES = stringr::str_wrap(PIECES)
type = doc %>%
html_node(xpath="//section/section/section[2]/div[6]/h2/span[2]") %>%
html_text()
TYPE_BIEN = stringr::str_replace_all(type,pattern,"")
TYPE_BIEN = stringr::str_wrap(TYPE_BIEN)
ges = doc %>%
html_node(xpath="//section/section/section[2]/div[9]/h2/span[2]") %>%
html_text()
GES = stringr::str_replace_all(ges,pattern,"")
GES = stringr::str_wrap(GES)
values = c(PRIX, VILLE,SURFACE,PIECES,TYPE_BIEN,GES)
# convert to data frame and add labels
mydf = as.data.frame(t(values))
names(mydf)= c("PRIX", "VILLE","SURFACE","PIECES" ,"TYPE_BIEN","GES")
return(mydf)
}
ad_links = get_ad_links(page = 1)
# grab ad details for first 30 links from page 1
require(plyr)
ad_details = ldply(ad_links[1:30], get_ad_details, .progress = 'text')
这里的问题是 phone 数字位于一个按钮后面,必须先单击该按钮才能显示该数字。这样做是为了防止网络抓取工具获取这些 phone-numbers.
使用rvest
无法点击网站。但是,您可以使用 RSelenium
研究另一种方法。此方法使用网络浏览器 docker,它的工作方式与普通浏览器一样,但可以通过 R 命令进行引导。
最后我设法找到了使用 Rselenium 的解决方案,这里是函数 get_phone_number,它给出了一个数据帧,其中广告 link 作为 ID 和我匹配的 phone 数字使用之前创建的数据框。
但我遇到了一个新问题,实际上当我检索 4 或 5 个 phone 号码时,我的 IP 地址被阻止了。此外,当我使用不在法国的 VPN 时,phone 号码在我点击它后不会出现。
那么,如何在每次点击或任何其他想法后动态更改我的 IP 地址(仅限法国)?
x<- c("RSelenium","rvest","plyr")
lapply(x, require, character.only = TRUE)
wdman::selenium(verbose = FALSE)
remDr <- remoteDriver(port = 4567L, browserName = "phantomjs")
remDr$open()
# Function to Get the phone number by Ad URL
get_ad_phoneNumber = function(ad_url){
# put the url as ID to match later with the data frame created previously
Id = ad_url
# go to the url
remDr$navigate(ad_url)
Sys.sleep(5) # wait until the page stop loading
# find the phone number's button
webElem <- remDr$findElement(using = 'css selector', value = 'aside > div >
div.box-grey-light.mbs.align-center > div > button')
Sys.sleep(5) # wait until the page stop loading
webElem$clickElement() # click on the the button
Sys.sleep(5) # wait until the page stop loading
#find the phone number after the click
webElem <- remDr$findElement(using = 'xpath', value =
'//aside/div/div[1]/div/span/a')
# extract the phone as a string character
phoneNumber=webElem$getElementText()
values = c(Id,phoneNumber)
# convert to data frame and add labels
mydf = as.data.frame(t(values))
names(mydf)= c("ID","PhoneNumber")
return(mydf)
}
这就是我在早期编程时想到的。
现在看,我对流程和评论的缺乏感到畏缩。但它奏效了。
请让我知道它是否有效?我是 Whosebug 的新手。
Shownumbers <- function(k){
for (i in k:k){
url <- paste0("https://www.yellowpages.co.za/search?what=travel&pg=")
webpage_new <- read_html(url)
show_html <- html_nodes(webpage_new , ".idShowNumber")
show <- html_text(show_html)
show <- as.character(sub(paste("\n\t\t\t\t\t\t\t\t\t\t") , "" ,
show))
show <- as.character(replace(show , as.character("\") , ""))
show_base <- as.data.frame(show)
show_final <- show_base
paste0(i)
}
paste0(url,k)
}
Shownumbers(1)
for(d in 1:135){
url <- paste0("https://www.yellowpages.co.za/search?what=travel&pg=")
if(d ==1){
Shownumbers(d)
webpage_new <- read_html(url)
no_html <- html_nodes(webpage_new , ".yext-phone")
no <- html_text(no_html)
no <- as.character(sub(paste("\n\t\t\t\t\t\t\t\t\t\t") , "" , no))
no <- as.character(replace(no , as.character("\") , ""))
no_base <- as.data.frame(no)
no_final <- no_base
} else {
Shownumbers(d)
webpage_new <- paste0(url,d)
no_read <- read_html(webpage_new)
no_html <- html_nodes(no_read , ".yext-phone")
no <- html_text(no_html)
no <- as.character(sub(paste("\n\t\t\t\t\t\t\t\t\t\t") , "" , no))
no <- as.character(replace(no , as.character("\") , ""))
no_base <- as.data.frame(no)
no_final <- rbind(no_final,no_base)
}
paste0(d)
}
no_final <- unique(no_final)
作为数据科学团队的实习生,我的任务是使用 R 找到一种自动收集房地产广告网站上特定数据的方法。
感谢 post (Web scraping with R over real estate ads) 中给出的答案和代码中的一些更改,我设法完成了我想要的任务。但我的问题是我无法抓取 phone 号码。我尝试了几件事但没有成功。
我想做与之前 post 完全相同的事情,但使用 phone 数字作为新变量。
这是广告的详细信息:https://www.leboncoin.fr/ventes_immobilieres/1074663461.htm?ca=13_s 我的变量是:价格 ("Prix")、城市 ("Ville")、表面 ("surface" )、"GES, the "Classe énergie"、房间数量 ("Pièces") 和 phone 数量,以及广告中显示的图片数量。
我注意到答案中给出的代码不再有效,因为在提出问题时,网站不安全 (http)。今天它包括开头 'https'。这就是我对代码进行一些更改的原因。
我是 R 的初学者,非常感谢任何帮助(抱歉我的英语不好)。
get_ad_links = function(page){
require(rvest)
# construct url to page (!when running the code put the url in 1 line!)
url_base = "https://www.leboncoin.fr/ventes_immobilieres/offres/
languedoc_roussillon/pyrenees_orientales"
url = paste(url_base, "?o=", page,"&ret=1&ret=2&f=p", sep = "")
page = read_html(url)
# extract links to ads on page
a="//*/section/section/ul/li["
b="]/a/@href"
t =lapply(1:30, function(i) paste(a,i,b, sep = ""))
ad_links = sapply(1:30,function(i) { page %>%
html_node(xpath=as.character(t[i])) %>% html_text()})
return(ad_links)
}
# Function to Get Ad Details by Ad URL
get_ad_details = function(ad_url){
require(rvest)
# parse ad url to html tree
doc = read_html(paste("https:",ad_url,sep=""))
# extract labels and values using xpath expression
pattern<- "</?\w+((\s+\w+(\s*m\s*(?:\".*?
\"|'.*?'[^'\">\s]+))?)+\s*|\s*)/?>"
prix = doc %>%
html_node(xpath="//section/section/section[2]/div[4]/h2/span[2]") %>%
html_text()
PRIX = stringr::str_replace_all(prix,pattern,"")
PRIX =stringr::str_wrap(PRIX)
ville = doc %>%
html_node(xpath="//section/section/section[2]/div[5]/h2/span[2]") %>%
html_text()
VILLE = stringr::str_replace_all(ville,pattern,"")
VILLE = stringr::str_wrap(VILLE)
surface = doc %>%
html_node(xpath="//section/section/section[2]/div[8]/h2/span[2]") %>%
html_text()
SURFACE = stringr::str_replace_all(surface,pattern,"")
SURFACE = stringr::str_wrap(SURFACE)
pieces = doc %>%
html_node(xpath="//section/section/section[2]/div[7]/h2/span[2]") %>%
html_text()
PIECES = stringr::str_replace_all(pieces,pattern,"")
PIECES = stringr::str_wrap(PIECES)
type = doc %>%
html_node(xpath="//section/section/section[2]/div[6]/h2/span[2]") %>%
html_text()
TYPE_BIEN = stringr::str_replace_all(type,pattern,"")
TYPE_BIEN = stringr::str_wrap(TYPE_BIEN)
ges = doc %>%
html_node(xpath="//section/section/section[2]/div[9]/h2/span[2]") %>%
html_text()
GES = stringr::str_replace_all(ges,pattern,"")
GES = stringr::str_wrap(GES)
values = c(PRIX, VILLE,SURFACE,PIECES,TYPE_BIEN,GES)
# convert to data frame and add labels
mydf = as.data.frame(t(values))
names(mydf)= c("PRIX", "VILLE","SURFACE","PIECES" ,"TYPE_BIEN","GES")
return(mydf)
}
ad_links = get_ad_links(page = 1)
# grab ad details for first 30 links from page 1
require(plyr)
ad_details = ldply(ad_links[1:30], get_ad_details, .progress = 'text')
这里的问题是 phone 数字位于一个按钮后面,必须先单击该按钮才能显示该数字。这样做是为了防止网络抓取工具获取这些 phone-numbers.
使用rvest
无法点击网站。但是,您可以使用 RSelenium
研究另一种方法。此方法使用网络浏览器 docker,它的工作方式与普通浏览器一样,但可以通过 R 命令进行引导。
最后我设法找到了使用 Rselenium 的解决方案,这里是函数 get_phone_number,它给出了一个数据帧,其中广告 link 作为 ID 和我匹配的 phone 数字使用之前创建的数据框。
但我遇到了一个新问题,实际上当我检索 4 或 5 个 phone 号码时,我的 IP 地址被阻止了。此外,当我使用不在法国的 VPN 时,phone 号码在我点击它后不会出现。
那么,如何在每次点击或任何其他想法后动态更改我的 IP 地址(仅限法国)?
x<- c("RSelenium","rvest","plyr")
lapply(x, require, character.only = TRUE)
wdman::selenium(verbose = FALSE)
remDr <- remoteDriver(port = 4567L, browserName = "phantomjs")
remDr$open()
# Function to Get the phone number by Ad URL
get_ad_phoneNumber = function(ad_url){
# put the url as ID to match later with the data frame created previously
Id = ad_url
# go to the url
remDr$navigate(ad_url)
Sys.sleep(5) # wait until the page stop loading
# find the phone number's button
webElem <- remDr$findElement(using = 'css selector', value = 'aside > div >
div.box-grey-light.mbs.align-center > div > button')
Sys.sleep(5) # wait until the page stop loading
webElem$clickElement() # click on the the button
Sys.sleep(5) # wait until the page stop loading
#find the phone number after the click
webElem <- remDr$findElement(using = 'xpath', value =
'//aside/div/div[1]/div/span/a')
# extract the phone as a string character
phoneNumber=webElem$getElementText()
values = c(Id,phoneNumber)
# convert to data frame and add labels
mydf = as.data.frame(t(values))
names(mydf)= c("ID","PhoneNumber")
return(mydf)
}
这就是我在早期编程时想到的。
现在看,我对流程和评论的缺乏感到畏缩。但它奏效了。 请让我知道它是否有效?我是 Whosebug 的新手。
Shownumbers <- function(k){
for (i in k:k){
url <- paste0("https://www.yellowpages.co.za/search?what=travel&pg=")
webpage_new <- read_html(url)
show_html <- html_nodes(webpage_new , ".idShowNumber")
show <- html_text(show_html)
show <- as.character(sub(paste("\n\t\t\t\t\t\t\t\t\t\t") , "" ,
show))
show <- as.character(replace(show , as.character("\") , ""))
show_base <- as.data.frame(show)
show_final <- show_base
paste0(i)
}
paste0(url,k)
}
Shownumbers(1)
for(d in 1:135){
url <- paste0("https://www.yellowpages.co.za/search?what=travel&pg=")
if(d ==1){
Shownumbers(d)
webpage_new <- read_html(url)
no_html <- html_nodes(webpage_new , ".yext-phone")
no <- html_text(no_html)
no <- as.character(sub(paste("\n\t\t\t\t\t\t\t\t\t\t") , "" , no))
no <- as.character(replace(no , as.character("\") , ""))
no_base <- as.data.frame(no)
no_final <- no_base
} else {
Shownumbers(d)
webpage_new <- paste0(url,d)
no_read <- read_html(webpage_new)
no_html <- html_nodes(no_read , ".yext-phone")
no <- html_text(no_html)
no <- as.character(sub(paste("\n\t\t\t\t\t\t\t\t\t\t") , "" , no))
no <- as.character(replace(no , as.character("\") , ""))
no_base <- as.data.frame(no)
no_final <- rbind(no_final,no_base)
}
paste0(d)
}
no_final <- unique(no_final)