Qual filme devo assistir durante o bloqueio?

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br


[Esteartigofoipublicadopelaprimeiravezem[Thisarticlewasfirstpublishedon R on Tea & Stats, e gentilmente contribuiu para os R-blogueiros]. (Você pode relatar um problema sobre o conteúdo desta página aqui)


Deseja compartilhar seu conteúdo com R-blogueiros? clique aqui se você tiver um blog ou aqui se não tiver.

Meu irmão escreveu para mim esta semana com uma tarefa interessante:

Tenho uma lista de filmes que anotei sempre que vi uma boa crítica.
Mas tem centenas de anos e nunca me lembro o que é um filme em seu título e não posso me incomodar em procurá-lo sempre.
Alguma chance de você poder escrever um script que faça referência cruzada de uma pontuação do Rotten Tomatoes e uma rápida sinopse para que eu possa navegar mais facilmente na lista?

Bem simples, e a solicitação coincidiu com uma interrupção na VPN no trabalho, então eu tive um tempo livre.
Vou demonstrar como lidei com essa tarefa em R, caso isso ajude qualquer pessoa cujos membros da família estejam ficando loucos em quarentena.

Em busca de APIs

A primeira coisa que fiz foi verificar se o Rotten Tomatoes tinha uma interface de programação de aplicativos (API) existente que me permitisse acessar o banco de dados de classificações de filmes.
Acontece que eles realmente têm um, mas é voltado para pessoas que desenvolvem aplicativos e sites reais, em vez de meros membros mortais do público.
Otimisticamente, solicitei uma chave de API, mas no momento em que escrevi o Rotten Tomatoes não me responderam.

Não se preocupe!
Posso apenas colocar meu chapéu tricotado e raspar as informações do site público.

Agora, não sabemos necessariamente o URL de todos os filmes do Rotten Tomatoes com base em seu título, pois pode haver vários filmes com o mesmo título – como remakes e adaptações de livros – ou o filme pode não ser indexado pelo Rotten Tomatoes em todos.
Portanto, para obter a página de um filme, podemos usar a função de pesquisa do site e retornar o resultado principal.

Normalmente, para procurar um filme no Rotten Tomatoes, você acessa um URL do formulário

https://www.rottentomatoes.com/search?search=%s

substituindo %s com sua consulta de pesquisa e você vê algo assim no seu navegador:

Página de resultados de pesquisa para 'The Good, The Bad and the Ugly' on Rotten Tomatoes

Então, na minha opinião, o fluxo de trabalho seria uma simples questão de:

  1. Pesquise o filme usando um URL como acima
  2. Raspe a página de resultados da pesquisa para obter um link para o filme
  3. Raspe a página do filme para obter a classificação e a sinopse
Leia Também  Como verificar sua necessidade de seguro?

Infelizmente, o site Rotten Tomatoes é configurado, deliberadamente ou não, para que você não possa fazer isso programaticamente.
Embora você possa tentar fazer essa consulta de pesquisa a partir de R, por exemplo:

rt_lookup <- function(film) {
  query <- URLencode(film)
  url <- sprintf('https://www.rottentomatoes.com/search?search=%s', query)
  httr::GET(url)
}
request <- rt_lookup('The Good, the Bad and the Ugly')

o resultado request não contém nenhum resultado de filme, pois no site eles parecem ser gerados pelo código JavaScript que só é executado se você estiver acessando a página em um navegador da Web real (ou seja, não um robô).
Provavelmente existe uma maneira de contornar isso, simulando uma sessão do navegador usando RSelenium ou similar, mas parecia muito complicado para mim.

Em vez disso, procurei outras fontes de classificações de filmes.
Meu primeiro pensamento foi no site Metacritic, mas o site deles é ainda mais hostil ao robô do que o Rotten Tomatoes.
Eu tentei consultá-lo com código muito semelhante ao anterior:

mc_lookup <- function(film) {
  string <- URLencode(film)
  url <- sprintf('https://www.metacritic.com/search/all/%s/results', string)
  httr::GET(url)
}
request <- mc_lookup('The Good, the Bad and the Ugly')

e não apenas não obtemos resultados úteis, mas o servidor nos bloqueia completamente com um erro 403 (acesso proibido).
É como se as pessoas que criam esses sites preferissem que acessássemos o site em um navegador, presumivelmente para que possam nos servir anúncios ou outros serviços e ganhar a vida.

Implacável, eu me virei para a robusta informação do filme, o Internet Movie Database (IMDb).
Talvez seja um site antigo ou talvez não se importe com robôs, mas este é muito mais acessível.
Podemos fazer uma consulta de pesquisa na IMDb usando

imdb_lookup <- function(film) {
  string <- gsub(' ', '+', film)
  url <- sprintf('https://www.imdb.com/find?s=tt&q=%s&ref_=nv_sr_sm', string)
  httr::GET(url)
}
request <- mc_lookup('The Good, the Bad and the Ugly')

que recupera programaticamente o conteúdo da página a seguir.
Observe que não há classificações ou resumos exibidos na página de resultados; portanto, precisamos seguir o link para a página de cada filme para obter essas informações.

Página de resultados de pesquisa para 'The Good, The Bad and the Ugly' no IMDb

Resultados de raspagem

Estamos interessados ​​apenas em um filme por consulta, não nos 200 retornados.
Uma decisão pragmática é apenas escolher o resultado principal, que geralmente corresponde ao filme mais popular com esse título.
(Se estamos buscando uma edição menos popular, sempre podemos incluir o ano no título do filme, aumentando a probabilidade de a versão desejada ser o principal resultado.)

No IMDb, visualize a página de resultados de pesquisa no inspetor de elementos do seu navegador e você verá que ela possui uma estrutura HTML como esta:

Leia Também  Planejamento de patrimônio familiar: Grampy Larry's Take
cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br

...

A análise desta tabela é fácil com o rvest pacote.
A função a seguir localiza e extrai o primeiro hiperlink com a classe result_text no findList tabela e solicita a página correspondente.

library(rvest)
get_first_imdb_result <- function(imdb_results) {
  if (httr::http_error(imdb_results)) return(NA)
  film_path %
    read_html() %>%
    html_node('table.findList .result_text a') %>%
    html_attr('href')
  if (is.na(film_path)) return(NA)
  url <- paste0('https://imdb.com', film_path)
  httr::GET(url)
}

Se quiséssemos extrair todos links na tabela, usaríamos a função html_nodes, ao invés de html_node, que apenas retorna o primeiro.

Em geral, não podemos supor que antes nosso chamado para imdb_lookup sempre retornará resultados, no entanto, porque poderíamos ter passado uma consulta de pesquisa inválida ou o servidor da IMDb poderia se tornar sábio com nosso comportamento robótico (o que certamente está violando os termos de uso desse site) e bloquear a solicitação (como o Metacritic).
Assim, incluímos retorno NA se a página de pesquisa não foi encontrada.
Além disso, a página pode ser encontrada, mas não contém resultados; nesse caso, também retornamos NA.
Isso é para evitar erros quando processamos muitos filmes por vez.
É algo que você sempre deve considerar ao consultar dados em um servidor ou rede fora do seu controle.

A função acima solicita a página de filme IMDb vinculada aos resultados da pesquisa.
Por exemplo:

Página da IMDb para 'O Bom, O Ruim e o Feio' (1966)

Quase lá.
Agora só precisamos raspar as informações principais desta página:

  • Título (que pode ser diferente da nossa consulta de pesquisa)
  • Classificação da IMDb
  • Breve descrição do filme
  • Metascore

Curiosamente, acabamos obtendo pontuações do Metacritic indiretamente raspando a IMDb, mesmo que não seja possível raspar as mesmas no site da Metacritic.

Dê uma olhada na página com um inspetor de elementos para encontrar os elementos HTML necessários.
Para as quatro informações acima, podemos selecioná-las usando

  • .title_wrapper h1
  • .imdbRating .ratingValue span
  • .summary_text
  • .metacriticScore span

Eu escrevi a seguinte função para extrair o mesmo.
A função R básica trimws é especialmente útil para se livrar de qualquer espaço em branco incômodo no início e no final do conteúdo da página.

extract_imdb_info <- function(request) {
  page <- title <- metascore <- rating <- synopsis <- NA
  if (!is.na(request[[1]]))
    if (!httr::http_error(request))
      page <- xml2::read_html(request)
  if (!is.na(page)) {
    title % html_text %>% trimws
    metascore % html_text
    rating % html_text
    synopsis % html_text %>% trimws
  }
  c(title = title,
    metascore = metascore,
    imdb_rating = rating,
    synopsis = synopsis)
}

Mais uma vez, não podemos assumir que as duas funções anteriores nos passaram páginas da web válidas, então NA é retornado se o request é também NA ou é um erro HTTP.
As informações finais são retornadas como um vetor nomeado.
Agora temos tudo o que precisamos para analisar uma lista de muitos filmes.

Juntando tudo

Este é o meu script final, rodando em uma lista de exemplos de filmes (incluindo um que eu esperaria retornar um erro em algum momento, se não tivesse projetado o código para lidar com esses casos).

films <- c('The Matrix', 'Citizen Kane', 'Zootropolis',
           'The Good, The Bad And The Ugly', 'Her', 'Inception', 'Bladerunner',
           'How to train your dragon', 'A Film That Does Not Really Exist')

search_queries <- lapply(films, imdb_lookup)
film_pages <- lapply(search_queries, get_first_imdb_result)
film_info <- lapply(film_pages, extract_imdb_info)

results <- tibble::tibble(film = films, info = film_info)
results <- tidyr::unnest_wider(results, info)

E o resultado?
Um quadro de dados organizado de filmes, títulos, resumos e classificações.
E todos os filmes que não puderam ser encontrados no banco de dados de filmes simplesmente mostram NA.

# A tibble: 9 x 5
  film              title              metascore imdb_rating synopsis                                         
                                                                                     
1 The Matrix        The Matrix (1999)  73        8.7         A computer hacker learns from mysterious rebels ~
2 Citizen Kane      Citizen Kane (194~ 100       8.3         Following the death of publishing tycoon Charles~
3 Zootropolis       Zootropolis (2016) 78        8.0         In a city of anthropomorphic animals, a rookie b~
4 The Good, The Ba~ The Good, the Bad~ 90        8.8         A bounty hunting scam joins two men in an uneasy~
5 Her               Her (2013)         90        8.0         In a near future, a lonely writer develops an un~
6 Inception         Inception (2010)   74        8.8         A thief who steals corporate secrets through the~
7 Bladerunner       Blade Runner (198~ 84        8.1         A blade runner must pursue and terminate four re~
8 How to train you~ How to Train Your~ 75        8.1         A hapless young Viking who aspires to hunt drago~
9 A Film That Does~ NA                 NA        NA          NA                                               

As pontuações de classificação são inicialmente vetores de caracteres, mas você pode convertê-los em numéricos.
Exporte-o para um arquivo csv e você pode pesquisar e classificá-lo para o conteúdo do seu coração.

Espero que isto ajude!

var vglnk = {key: '949efb41171ac6ec1bf7f206d57e90b8'};

(função (d, t) {
var s = d.createElement
s.src = '//cdn.viglink.com/api/vglnk.js';
var r = d.getElementsByTagName
} (documento, 'script'));

Para Deixe um comentário para o autor, siga o link e comente no blog: R on Tea & Stats.

R-bloggers.com oferece atualizações diárias por email sobre notícias e tutoriais do R sobre o aprendizado do R e muitos outros tópicos. Clique aqui se você deseja publicar ou encontrar um emprego em ciência da dados / R.


Deseja compartilhar seu conteúdo com R-blogueiros? clique aqui se você tiver um blog ou aqui se não tiver.



cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br
The Good, the Bad and the Ugly (1966)