#r #web-scraping #reddit
#r #очистка веб-страниц #Reddit
Вопрос:
Я пытаюсь выполнить webscrape из Reddit, используя R-пакет RedditExtractoR. В частности, я использую reddit_urls() для возврата результатов из Reddit с поисковым запросом «президент».
Сначала я создал объект links499
, который (должен) содержать URL-адреса на 499 страниц, содержащие термин «президент». Я отсортировал по комментариям.
links499 <- reddit_urls(search_terms = "president",
cn_threshold = 0,
page_threshold = 499,
sort_by = "comments",
wait_time = 2)
links499Com <- get_reddit(search_terms = "president",
cn_threshold = 0,
page_threshold = 499,
sort_by = "comments",
wait_time =2)
Каждый из этих объектов имел одинаковое количество уникальных заголовков URL (n= 239), и оба возвращали только URL с очень большим количеством комментариев (наименьший из которых был 12 378). Это имеет смысл, потому что я извлекаю URL-адреса из Reddit в порядке уменьшения количества комментариев.
# Have the same number of unique titles
unique(links499$title)
unique(links499Com$title)
# Both have minimum of 12378
min(links499$num_comments)
min(links499Com$num_comments)
Затем я хотел вернуть еще большее количество совпадающих URL-адресов для поискового запроса «президент» из Reddit. Я думал, что этого можно добиться простым увеличением page_threshold
параметра. Однако я (безуспешно) попробовал тот же код, только теперь выполнив поиск по URL-адресам на 1000 страниц.
links1000 <- reddit_urls(search_terms = "president",
cn_threshold = 0,
page_threshold = 1000,
sort_by = "comments",
wait_time = 2)
links1000Com <- get_reddit(search_terms = "president",
cn_threshold = 0,
page_threshold = 1000,
sort_by = "comments",
wait_time =2)
Я думал, что links1000
будет содержать URL-адреса с поисковым запросом «президент» с 1000 страниц с наибольшим количеством комментариев (тогда как links499
будет содержать URL-адреса с поисковым запросом «президент» с 499 страниц с наибольшим количеством комментариев). Однако links1000
и links499
были идентичны.
Более того, links1000Com
не удалось создать и выдал ошибку: URL 'https://www.reddit.com/r/politics/comments/dzd8lu/discussion_thread_fifth_democratic_presidential/.json?limit=500': status was 'Failure when receiving data from the peer'
.
Кажется, существует ограничение в 500 страниц.
Мой вопрос: как мне в следующий раз получить все URL-адреса (и связанные с ними комментарии)? Не только для 499 лучших страниц или 1000 лучших страниц, но продолжать до тех пор, пока не будут возвращены все URL-адреса с поисковым термином «президент» в Reddit?
Спасибо, что поделились любым советом.
*** РЕДАКТИРОВАТЬ ***
Как и было предложено, я добавляю воспроизводимый код ниже. Еще раз спасибо!
library(tidyverse)
library(RedditExtractoR)
links499 <- reddit_urls(search_terms = "president",
cn_threshold = 0, # minimum number of comments
page_threshold = 499,
sort_by = "comments",
wait_time = 2)
links499Com <- get_reddit(search_terms = "president",
cn_threshold = 0,
page_threshold = 499,
sort_by = "comments",
wait_time =2)
# Have the same number of unique titles (n=239)
length(unique(links499$title))
length(unique(links499Com$title))
# Both have minimum of 12378
min(links499Com$num_comments)
min(links499$num_comments)
links1000 <- reddit_urls(
search_terms = "president",
cn_threshold = 0, # minimum number of comments
page_threshold = 1000, # can probably get as many URLs as you want but you can only extract a certain amount of data at one time
sort_by = "comments",
wait_time = 2
)
links1000Com <- get_reddit(search_terms = "president",
cn_threshold = 0,
page_threshold = 1000,
sort_by = "comments",
wait_time =2 )
# Have the same number of unique titles (n=241)
length(unique(links1000$title))
length(unique(links1000Com$title))
# Both have minimum of 12378
min(links1000Com$num_comments)
min(links1000$num_comments)
Комментарии:
1. Текущий код находится в формате фрагмента и в нем отсутствуют необходимые вызовы библиотеки. Предложение. Где-нибудь в своем Q вы можете опубликовать полный код, который вы пробовали. Чтобы другие могли воспроизвести проблему, а также не повторять код. Я предлагаю добавить его в конце Q.
Ответ №1:
Итак, взглянув на код для get_reddit
и reddit_urls
, вы увидите, что get_reddit
это оболочка для reddit_urls
и что значения по умолчанию просто различаются между двумя функциями. get_reddit
, reddit_urls
.
Однако ответ на ваш вопрос таков: вы не можете получить более 1000 результатов по поисковому запросу.
Ограничения и предостережения
- Поисковые запросы могут быть заблокированы. Поиск по запросу «собаки» может возвращать результаты со словом «dog» в них.
- Результаты поиска ограничены 1000 результатами.
limit=500
Аргумент в вашем сообщении об ошибке относится к желаемому количеству возвращаемых записей, а не к желаемому количеству страниц. Способ, которым reddit выполняет разбивку на страницы, отличается от ожидаемого. В основном они отслеживают порядок сообщений, а затем, чтобы получить следующий набор сообщений (новую страницу), вы передаете идентификатор последнего сообщения в свой вызов. Я думаю, что reddit отслеживает отправителя вызова (ваш компьютер) и устанавливает ограничения на то, сколько он вернет.
Это описывает API reddit (в частности, before
и after
)
Вот ресурс на Python, который описывает ограничения на API reddit.
Редактировать:
Мне также непонятно, почему мы не получаем того количества результатов, о котором просили. Одна вещь, которую я заметил, это то, что Reddit, похоже, перестает выдавать ключи к дальнейшим результатам после определенного количества страниц. Не ясно, на чем это основано. Я написал некоторый код, чтобы проверить это и посмотреть, смогу ли я сам получить результаты:
search_query = "president"
number_of_pages = 10
results_holder <- data_frame(page = 1:number_of_pages, search = character(length = number_of_pages), titles = as.list(rep(1, number_of_pages)), url = as.list(rep(1, number_of_pages)))
first_search <- paste0("https://www.reddit.com/search/.json?q=",search_query,"amp;limit=1000amp;sort=comment")
tmp <- read_lines(first_search)
tmp2 <- jsonlite::fromJSON(tmp)
results_holder$search[1] <- first_search
results_holder$titles[[1]] <- tmp2$data$children$data$title
results_holder$url[[1]] <- tmp2$data$children$data$permalink
last_name <- tmp2$data$after
for(i in 2:number_of_pages){
new_search = paste0("https://www.reddit.com/search/.json?q=",search_query,"amp;limit=1000amp;sort=commentamp;after=",last_name)
tmp_loop <- read_lines(new_search)
tmp2_loop <- jsonlite::fromJSON(tmp_loop)
results_holder$search[i] <- new_search
results_holder$titles[[i]] <- tmp2_loop$data$children$data$title
results_holder$url[[i]] <- tmp2_loop$data$children$data$permalink
last_name <- tmp2_loop$data$after
Sys.sleep(5)
}
Исходя из этого, вы можете изучить объект results_holder$search
и увидеть, что в конечном итоге мы начнем все сначала с разбивки на страницы.
Что я вижу происходящее (и могу проверить, проделав то же самое в браузере), так это то, что reddit перестает выдавать значение для after
в файле json. Это значение, которое нам нужно для того, чтобы создать новую строку поиска и получить следующую страницу. Иногда я могу заставить его возвращать 3 страницы / ~ 250 результатов, прежде чем он начнет выдавать "after": null
Комментарии:
1. Спасибо @BrianLang. Я не видел этого раньше. Однако даже с этой информацией я все еще не уверен, почему
links1000
иlinks499
были идентичны в моем коде выше. Если ограничение равно 1000, не должноlinks1000
быть примерно в два раза длиннееlinks499
? Мне также интересно, есть ли способ запускать последовательные проверки с 1000 результатами (первая 1000, следующая 1000, следующая 1000 и т.д.)? Я думал, что это ожидание, для которого предназначенwait_time
параметр (для запуска следующихn
результатов поиска после требуемого периода ожидания, поскольку толькоn=1000
это может быть выполнено в данный момент времени).2. Да, это довольно странно. После просмотра кода пакета они, по сути, отправляют запросы страницы в R с некоторым промежутком времени
wait_time
между ними. Эти запросы являются последовательными и полагаются на переменную в возвращаемом файле jsonafter
для перехода на следующую страницу. Проблема, похоже, в том, что reddit готов обслуживать только определенное количество страниц, прежде чемafter
будет возвращен какnull
. Это, похоже, твердо на стороне reddit.