Очистка Goodreads с RSelenium: Выбор языка с помощью селектора css? - PullRequest
0 голосов
/ 16 января 2020

Я пытаюсь отсканировать отзывы Goodreads сценарием на R. Я добавил сценарий ниже, используя пример Pride & Prejudice . Сценарий работает фантастически. Тем не менее, я хотел бы иметь возможность выбрать язык, чтобы я мог, например, только английский / немецкий / ... обзоры. Я полагаю, что это возможно, используя технику, аналогичную той, которая использовалась внизу сценария, чтобы перейти на следующую страницу обзоров (NextPageButton <- remDr$findElement("css selector", ".next_page") NextPageButton$clickElement()).

Я новичок в этом, но я проверил html веб-страницы, и код, касающийся языкового фильтра, выглядит следующим образом (я пропустил некоторые опции для сокращения кода):

  <div class="reviewControls--left">
      <form class="reviewLanguageFilter" action="/book/reviews/1885" accept-charset="UTF-8" data-remote="true" method="get"><input name="utf8" type="hidden" value="&#x2713;" />
        <select name="language_code" id="language_code"><option value="">All Languages</option><option value="id">Bahasa Indonesia &lrm;(166)</option>
<option value="ca">Català &lrm;(7)</option>
<option value="da">Dansk &lrm;(14)</option>
<option value="de">Deutsch &lrm;(182)</option>
<option value="et">Eesti &lrm;(7)</option>
<option selected="selected" value="en">English &lrm;(50425)</option>
<option value="es">Español &lrm;(2408)</option>
<option value="fr">Français &lrm;(233)</option>
</select>
</form>    </div>

Я пробовал несколько вариантов, например

FilterSelection <- remDr$findElement("css selector", "language_code")
FilterSelection$clickElement()

или

FilterSelection <- remDr$findElement("css selector", "language_code", value = "All languages")
FilterSelection$clickElement()

Но они не работали. Может ли кто-нибудь помочь мне, показывая и объясняя, как я могу превратить это в работающий код? Заранее спасибо и всего наилучшего!

Сценарий:

library(data.table)   # Required for rbindlist
library(dplyr)        # Required to use the pipes %>% and some table manipulation commands
library(magrittr)     # Required to use the pipes %>%
library(rvest)        # Required for read_html
library(RSelenium)    # Required for webscraping with javascript
library(lubridate)    # Required to collect dates
library(stringr)
library(purrr)

options(stringsAsFactors = F) #needed to prevent errors when merging data frames

#Paste the GoodReads Url
url <- "https://www.goodreads.com/book/show/1885.Pride_and_Prejudice"

#Enter the number of review pages (manually check for now)
nPages = 10

#Set your browser settings
rD <- rsDriver(chromever = "79.0.3945.36")
remDr <- rD[["client"]]
remDr$setTimeout(type = "implicit", 2000)
remDr$navigate(url)

bookTitle = unlist(remDr$getTitle())
finalData = data.frame()

# Main loop going through the website pages
for(pageNumber in 1:nPages){



  #find a way to select the language of the reviews




  #Expand all reviews
  expandMore <- remDr$findElements("link text", "...more")
  sapply(expandMore, function(x) x$clickElement())

  #Extracting the reviews from the page
  reviews <- remDr$findElements("css selector", "#bookReviews .stacked")
  reviews.html <- lapply(reviews, function(x){x$getElementAttribute("outerHTML")[[1]]})
  reviews.list <- lapply(reviews.html, function(x){read_html(x) %>% html_text()} )
  reviews.text <- unlist(reviews.list)

  #Some reviews have only rating and no text, so we process them separately
  onlyRating = unlist(map(1:length(reviews.text), function(i) str_detect(reviews.text[i], "^\\\n\\\n")))

  #Full reviews
  if(sum(!onlyRating) > 0){

    filterData = reviews.text[!onlyRating]
    fullReviews = purrr::map_df(seq(1, length(filterData), by=2), function(i){
      review = unlist(strsplit(filterData[i], "\n"))

      data.frame(
        date = mdy(review[2]), #date
        username = str_trim(review[5]), #user
        rating = str_trim(review[9]), #overall
        comment = str_trim(review[12]) #comment
      )
    })

    #Add review text to full reviews
    fullReviews$review = unlist(purrr::map(seq(2, length(filterData), by=2), function(i){
      str_trim(str_remove(filterData[i], "\\s*\\n\\s*\\(less\\)"))
    }))

  } else {
    fullReviews = data.frame()
  }


  #partial reviews (only rating)
  if(sum(onlyRating) > 0){

    filterData = reviews.text[onlyRating]
    partialReviews = purrr::map_df(1:length(filterData), function(i){
      review = unlist(strsplit(filterData[i], "\n"))

      data.frame(
        date = mdy(review[9]), #date
        username = str_trim(review[4]), #user
        rating = str_trim(review[8]), #overall
        comment = "",
        review = ""
      )
    })

  } else {
    partialReviews = data.frame()
  }

  finalData = rbind(finalData, fullReviews, partialReviews)

  NextPageButton <- remDr$findElement("css selector", ".next_page")
  NextPageButton$clickElement()

  message(paste("PAGE", pageNumber, "of", nPages, "Processed"))
  Sys.sleep(4)
}   
#end of the main loop

#Replace missing ratings by 'not rated'
finalData$rating = ifelse(finalData$rating == "", "not rated", finalData$rating)

#Stop server
rD[["server"]]$stop()

#set directory to where you wish the file to go
getwd()
setwd("")

#Write results
write.csv(finalData, paste0(bookTitle, ".csv"), row.names = F)
...