Web scraping em R: Dois Por Um

Web scraping em R: Dois Por UmGabriela Kishida KoreedaBlockedUnblockFollowFollowingMay 6Dois por um é um livrinho de ofertas para a cidade de São Paulo.

Inclui, principalmente, restaurantes mas também é possível encontrar spas e até um motel.

Como o nome já diz, nos estabelecimentos selecionados você leva dois (pratos, lanches, massagens, etc…) por um.

Eu sempre quis fazer um Webscrapping e escolhi esse site por sem bem simples e eu ter interesse nas informações coletadas.

Tem dois objetivos que eu queria atingir com esse programa, sendo eles:Criar um mapa com todas as ofertas;Cruzar as informações com a base de algum cartão de benefício alimentício (VR, Ticket, Sodexo, Alelo).

Isso ficará para o próximo artigo.

BibliotecasAs bibliotecas a serem utilizadas são:httr: utilização na coleta de informações da página web no formato html;xml2: manipulação de arquivos xml;rvest: auxílio na coleta de informações da página web;leaflet: criação de mapas;stringr: manipulação de strings;htmlwidgets: criação de objetos html;ScrapingAo entrar no site https://www.

doisporum.

net, vemos que todos os estabelecimentos estão representados por quadradinhos e logo ao apertar um deles, aparece uma caixa com mais informações, que também podem ser encontradas em uma página individual de cada uma das ofertas, com a extensão /home/details/<id>.

Dessa forma, é necessário obter o id de cada uma para poder acessar essas páginas.

A primeira coisa a se fazer é puxar os dados do site, isso é feito com o método GET que retornará o arquivo html da página requisitada.

Após isso, utilizamos a função read_html que converterá para um arquivo XML que facilitará a busca dos objetos.

Utilizamos então a função html_nodes especificando various como a classe dos objetos que estamos buscando, para então selecionar apenas os links especificados pelo atributo href.

Isso nos retornará um vetor contendo as urls para a página de cada oferta.

dois_um_url <- "https://www.

doisporum.

net"dois_um <- httr::GET(dois_um_url) %>% httr::content('text') %>% xml2::read_html() %>% rvest::html_nodes(".

various") %>% rvest::html_attr("href")Com base nas urls, é necessário fazer um loop sobre esse vetor afim de acessar cada página e coletar o endereço de cada estabelecimento.

Isso é feito novamente com o método GET para acessar a página e convertendo para um arquivo XML.

Então, pela tag h1 sabemos qual o nome do lugar e pela tag p dentro do div de classe refdesc, as informações como: um pequeno resumo, telefone, site e endereço(s).

Como para alguns lugares, o endereço se encontrava na última linha e para outros, na penúltima, no dataframe criado para armazenamento das informações, foi mantido tanto a última quanto a penúltima linha.

Os dados foram salvos em um arquivo csv.

enderecos <- data.

frame("Nome" = numeric(0), "Endereço" = numeric(0), stringsAsFactors = F)for (url in dois_um) { page <- httr::GET(paste0(dois_um_url, url)) %>% httr::content('text') %>% xml2::read_html()nome <- page %>% html_nodes("h1") %>% html_text()end <- page %>% html_nodes(".

refdesc p") %>% html_text()enderecos <- rbind(enderecos, data.

frame("Nome" = nome, "Endereço" = end[length(end)], "Endereço 2" = end[length(end) – 1], stringsAsFactors = F))}write.

csv(enderecos, file = "enderecos.

csv", row.

names = F)MapaCom base nos endereços obtidos na seção anterior, é necessário fazer uma limpeza de forma a manter apenas os dados relevantes.

Primeiro, juntamos as colunas Endereço e Endereço.

2.

Como é possível perceber que o telefone do estabelecimento sempre se encontra logo após o endereço, se ele não for encontrado na coluna Endereço, então estará na coluna Endereço.

2.

enderecos$Endereço[grep("tel|Tel|(11)|R.

", enderecos$`Endereço`, invert = T)] <- enderecos$`Endereço.

2`[grep("tel|Tel|(11)|R.

", enderecos$`Endereço`, invert = T)]enderecos$Endereço.

2 <- NULLApós isso, é preciso remover os telefones, e-mails e outras informações irrelevantes que se encontram após o endereço, ou seja, após São Paulo — SP.

Com o uso da biblioteca stringr fica fácil a manipulação de strings ainda mais com o uso do pipe (%>%).

ende <- enderecos$Endereço %>% str_remove_all("(Tel:|Tel.

:|Telefone:)|[(11)]S+s+d{4}(s+|S+)d{4}") %>% str_remove_all("w{3}.

(.

*)") %>% str_remove_all(".

com") %>% str_remove_all(".

net") %>% str_remove(".

br") %>% str_remove_all("(?<=(São Paulo – SP))(.

*)|(?<=(São Paulo SP))(.

*)")Muitos estabelecimentos têm mais de um endereço cadastrado e estão separados por uma barra (/), outros não tem nenhuma separação, nesses casos foi inserido para facilitar a divisão.

Assim, foi criado um novo data frame com os endereços limpos e, posteriormente, removidos algumas ocorrências que não fazem sentido.

ende[67] <- sub("(56)", "1/", ende[67])ende[67] <- sub("(387)", "1/", ende[67])x <- strsplit(ende, "/")y <- sapply(x, length)enderecos <- data.

frame("Nome" = rep(enderecos$Nome, y), "Endereço" = unlist(x), stringsAsFactors = F)enderecos <- enderecos[-c(44, 127, 155, 156), ]Para poder criar o mapa pelo leaflet, é preciso ter as coordenadas de latitude e longitude de cada estabelecimento.

Esses dados podem ser adquiridos pela API do site http://www.

mapquestapi.

com.

Você pode se cadastrar gratuitamente e fazer 15,000 requisições por mês sem custo.

Assim, é preciso adequar os endereços para serem inseridos na url da API.

Primeiro, os bairros que estão no começo dos endereços e seguidos por dois pontos foram movidos para depois do número do estabelecimento.

Depois, foi adicionado a string “Sao Paulo SP” para os lugares que não tinham essa informação.

Depois, retirados “-”, “:”, “.

” e “,”.

E R.

, Av.

e Dr.

foram substituídos por Rua, Avenida e Doutor respectivamente.

Posteriormente, foram mantido apenas os dados que começassem com Rua, Alameda, Praça, Largo, Avenida, sendo retiradas as informações sobre andar, piso e CEP (8 números).

Alguns casos especiais não estavam funcionando devido ao bairro especificado no endereço como Parque Ibirapuera, Cidade Jardim, Brooklin Novo e Centro, logo esses foram removidos ou substituídos.

E por último, os espaços extras foram eliminados.

enderecos$Endereço[grepl(":", enderecos$Endereço)] <- paste(str_remove(enderecos$Endereço[grepl(":", enderecos$Endereço)], ".

*:"), str_extract(enderecos$Endereço[grepl(":", enderecos$Endereço)], ".

*:"))enderecos$Endereço[!grepl("SP", enderecos$Endereço)] <- enderecos$Endereço[!grepl("SP", enderecos$Endereço)] %>% str_remove("-") %>% str_c(" Sao Paulo SP")enderecos$Endereço <- enderecos$Endereço %>% str_remove_all(":") %>% str_remove_all("-") %>% str_remove_all(",") %>% str_replace("R.

", "Rua ") %>% str_replace("Av.

", "Avenida ") %>% str_replace("Dr.

", "Doutor ") %>% str_remove_all(".

") %>% str_extract("(Rua).

*|(Alameda).

*|(Praca).

*|(Largo).

*|(Avenida).

*") %>% str_remove("d+º andar") %>% str_remove("Piso d+") %>% str_remove("Parque do Ibirapuera ") %>% str_replace("Brooklin Novo", "Cidade Moncoes") %>% str_replace("Cidade Jardim", "Morumbi") %>% str_replace("Centro", "República") %>% str_replace("VN", "Vila Nova") %>% str_replace("Min", "Ministro") %>% str_remove("d{8}") %>% str_squish()As ocorrências cujos endereços resultaram em NA foram removidos.

E para dois casos específicos foi necessário fazer uma manipulação personalizada pois, por algum motivo, o maprequest não estava fornecendo a localização correta.

enderecos <- enderecos[!is.

na(enderecos$Endereço), ]enderecos$Endereço[127] <- str_remove(enderecos$Endereço[127], " d{1} .

*USP")enderecos$Endereço[52] <- "Instituto Tomie Ohtake rua corope 88"Então, foi utilizada a função URLencode para converter as strings em um formato url.

E os espaços, codificados como “%20” foram convertidos para “+”.

enderecos$url <- unname(sapply(enderecos$Endereço, URLencode))enderecos$url <- gsub("%20", "+", enderecos$url)Podemos então fazer a requisição pela API de cada um dos lugares especificando a key de acesso do maprequest, o endereço e limitando o resultado a apenas um.

Os dados de latitude e longitude são então anexados ao data frame principal.

url <- paste0('http://www.

mapquestapi.

com/geocoding/v1/address?key=', key, '&location=', enderecos$url, "+brasil&maxResults=1")latlong <- lapply(url, function(x) content(GET(x))$results[[1]]$locations[[1]]$latLng)latlong <- data.

frame(matrix(unlist(latlong), nrow=length(latlong), byrow=T))names(latlong) <- c("Lat", "Long")enderecos <- cbind(enderecos, latlong)Agora, finalmente, podemos criar o mapa no leaflet e salvar como um arquivo html.

map <- leaflet(enderecos) %>% addTiles() %>% addControl(paste("Dois por Um <br> Quantidade de Ofertas:", nrow(enderecos)), position = "topright") %>% addAwesomeMarkers(~Long, ~Lat, popup=~paste0("Loja: ", Nome, "<br>", "Endereço: ", `Endereço`))saveWidget(map, "dois-por-um_2.

html")Ao analisar de perto alguns dos pontos marcados, é possível perceber que não estão com a localização exata.

Mas numa análise geral nenhum dos locais está muito longe do endereço correto.

ConclusãoO processo inteiro demorou mais do que o esperado devido a principalmente à API do maprequest não ser muito inteligente (pelo menos para endereços brasileiros), sendo necessário vários ajustes para poder fornecer as informações corretas.

Primeiramente, havia sido considerado o uso da biblioteca RSelenium para extrair as informações de latitude e longitude do site https://www.

latlong.

net/, porém ele permite apenas 25 requisições por dia, sendo inviável nesse caso.

De qualquer modo, por meio desse projeto pude aprender muito sobre regular expressions e manipulação de strings.

Além de preparar os dados necessários para a próxima etapa: cruzamento de informações com o banco de dados de VR, Ticket, Alelo ou Sodexo (ainda estou pesquisando).

O código completo pode ser encontrado aqui: https://github.

com/gabrielakoreeda/dois-por-um/tree/masterReferênciasdois por um – São Paulo a dois, pelo preço de um'dois por um' é o melhor presente para você comer bem, se divertir em São Paulo a dois, descobrindo lugares pela cidade…www.

doisporum.

netXML File Extension – What is an .

xml file and how do I open it?Learn about .

XML files and view a list of programs that open them.

fileinfo.

comMapQuest Development and Documentation – Getting StartedThe portal for developers to use MapQuest APIs.

Find documentation to use our geo-spatial APIs and make maps using our…www.

mapquestapi.

com.

. More details

Leave a Reply