2015-01-21 1 views
2

Я пытаюсь выполнить следующую задачу в R. Этот веб-сайт предоставляет статистику уровня подрайона (в таблицах) по сельскохозяйственным данным в Индии: http://agcensus.dacnet.nic.in/tehsilsummarytype.aspx Я понимаю, что это называется динамической формой, поскольку изменения параметров зависят от сделанных записей. В частности, я хотел бы загрузить таблицы для нравлюсь:R - веб-скребковая динамическая форма с входами

  1. государства = Андхра-Прадеш
  2. район = Адилабад, Anantapur, Kadapa, ... (8 всего)
  3. Техсилы = Mancherial, Kasipet (это только 2 примеры для района = Адилабад, всего 158)

Тогда я хочу «Среднее количество холдингов по размеру» для всех социальных групп, всех полов и Всего.

Основываясь на этом сообщении What if I want to web scrape with R for a page with parameters? Я думаю, что путь к использованию - использовать getHTMLFormDescription(). Однако, поскольку моя форма динамична, я не могу следовать маршруту, который был предложен в другом сообщении. Линия createFunction() возвращает ошибку: "* Ошибка в writeFunction (formDescription, символ(), URL, жулик, многословен = многословным,: Вы должны предоставить описание формы здесь См getFormDescription().."

В пакет RHTMLForms, который можно загрузить с веб-страницы omegahat, есть эта функция, которая (как следует из названия) должны делать то, что мне нужно:

function function(desc, omit = character(), drop = TRUE, ..., verbose = FALSE) { 
# Discard the elements that we are omitting. 
if(length(omit)) { 
    idx = match(omit, names(desc$elements), 0) 
    k = class(desc$elements) 
desc$elements <- desc$elements[-idx] 
class(desc$elements) = k } 

# If no more elements left as a result of omitting them, just return the description 
# as there are definitely no more dynamic components left. 
if(length(desc$elements) == 0) 
return(desc) 

    # Now find the dynamic components. 
dyn = sapply(desc$elements, inherits, "DynamicHTMLFormElement") 
if(!any(dyn)) 
return(desc) 

pivot = desc$elements[[min(which(dyn))]] 

# We will need to submit the form for each value of this dynamic element, so 
    # get the URI. If the URI changes depending on the value, we are out of  luck!! 
url = mergeURI(URI(desc$formAttributes["action"]), URI(desc$url)) 

# Prepare the return value with the pivot information and we will build up 
# the branches by looping over the possible values. 
descriptions = list(elementName = pivot$name, 
       description = pivot, 
       values = list()) 

omit = c(omit, pivot$name) 

for(i in names(pivot$options)) { 
    # Create the arguments for the submission. We may need to include them all. 
args = list(i) 
names(args)[1] = pivot$name 

if(verbose) 
    cat("Checking ", pivot$name, " - option", i, "\n") 

    #XX we may need to provide all the arguments rather than just this one. 
    # or perhaps cumulate them for the elements we have already deal with. 
    # We have the defaults and the possible values from the original description. 
page = formQuery(args, toString(url), desc, .checkArgs = FALSE, ...) 
    # Make certain that we turn the checkDynamic off here to avoid recursively. 
tmp = getHTMLFormDescription(page, asText = TRUE, handlers = multiFormElementHandlers(url, checkDynamic = FALSE)) 
tmp = getDynamicHTMLFormDescription(tmp, omit = omit) 

    # Now remove the elements that we are omitting. This leaves a subset of the form. 
if(drop) { 
    idx = match(omit, names(tmp$elements), 0) 

    if(any(is.na(idx))) { 
     k = class(tmp$elements) 
     tmp$elements = tmp$elements[is.na(idx)] 
     class(tmp$elements) = k 
    } 

    class(tmp) <- c("HTMLFormSubset", class(tmp))   
} 

descriptions$values[[i]] = tmp 
} 

class(descriptions) <- c("DynamicFormElementPath") 

descriptions 
} 

Однако, я не могу получить эту работу ни один - call getDynamicHTMLFormDescription («http://agcensus.dacnet.nic.in/tehsilsummarytype.aspx») дает «Ошибка в desc $ elements: оператор $ недействителен для атомных векторов».

Кто-нибудь посоветует, как это сделать? Как только у меня есть способ заполнить форму и получить доступ к таблице для каждого подрайона (tahsil), я знаю, как получить данные в форме. Это действительно только то, что R заполняет эту (конкретную) форму.

Любая помощь приветствуется! Michael Kaiser (штатный научный сотрудник, UCSD)

+0

При выборе «Андхра-Прадеш» выпадающее меню «Район» показывает 23 записи, а не 8, как вы упомянули выше. Было ли это опечаткой или вас интересуют 8 конкретных районов из этих 23? – alex23lemm

+0

Жаль об этом - я должен был быть более конкретным. Да, меня интересуют 8 конкретных из этих 23 районов. –

ответ

4

Вот решение, используя RSelenium для загрузки данных для

  1. государства = Андхра-Прадеш
  2. район = Adilabadt
  3. Техсил = Mancherial
  4. Таблицы = Средний размер операционного холдинга по размерной группе

В остальных полях используются параметры ввода по умолчанию.

library(RSelenium) 
library(XML) 
library(magrittr) 

# Start Selenium Server -------------------------------------------------------- 

checkForServer() 
startServer() 
remDrv <- remoteDriver() 
remDrv$open() 


# Simulate browser session and fill out form ----------------------------------- 

remDrv$navigate('http://agcensus.dacnet.nic.in/tehsilsummarytype.aspx') 
remDrv$findElement(using = "xpath", 
        "//select[@name = '_ctl0:ContentPlaceHolder1:DropDownList1']/option[@value = '1a']")$clickElement() 
remDrv$findElement(using = "xpath", 
        "//select[@name = '_ctl0:ContentPlaceHolder1:DropDownList9']/option[@value = '19']")$clickElement() 
remDrv$findElement(using = "xpath", 
        "//option[@value = '33']")$clickElement() 
remDrv$findElement(using = "xpath", 
        "//select[@name = '_ctl0:ContentPlaceHolder1:DropDownList3']/option[@value = '4']")$clickElement() 
# Click submit 
remDrv$findElement(using = "xpath", 
        "//input[@value = 'Submit']")$clickElement() 


# Retrieve and download results ------------------------------------------------ 

table <- remDrv$getPageSource()[[1]] %>% 
    htmlParse %>% 
    readHTMLTable %>% 
    extract2(4) 

remDrv$quit() 
remDrv$closeServer() 

head(table) 

#  V1      V2      V3 
# 1 SI No. Size of Holding(in ha.) Institutional Holdings 
# 2 (1)      (2)     (3) 
# 3  1    MARGINAL      0 
# 4  2     SMALL      0 
# 5  3    SEMIMEDIUM      0 
# 6  4     MEDIUM      0 

Однако статическое решение выше отвечает только части ваши вопросы, а именно: как заполнить веб-форму с помощью Р.

Коварное на вашей веб-странице, что значения в различном падении -down меню зависят друг от друга.

Ниже вы найдете решение, в котором учитываются эти зависимости, без необходимости знать соответствующие идентификационные данные района и tehsils.

Код ниже данных загрузки для

  1. государства = GOA
  2. Таблицы = Средний размер оперативной придерживая Размер группы

включая все районы и все tehsils. Я использовал GOA в качестве основного якоря, но вы можете легко выбрать другое состояние по вашему выбору.

library(RSelenium) 
library(XML) 
library(dplyr) 
library(magrittr) 

# Start Selenium Server -------------------------------------------------------- 

checkForServer() 
startServer() 
remDrv <- remoteDriver() 
remDrv$open() 


# Simulate browser session and fill out form ----------------------------------- 

remDrv$navigate('http://agcensus.dacnet.nic.in/tehsilsummarytype.aspx') 

# Select 27a == GOA as the anchor 
remDrv$findElement(using = "xpath", 
        "//select[@name = '_ctl0:ContentPlaceHolder1:DropDownList1']/option[@value = '27a']")$clickElement() 
# Select 4 == Average Size of Operational Holding by Size Group 
remDrv$findElement(using = "xpath", 
        "//select[@name = '_ctl0:ContentPlaceHolder1:DropDownList3']/option[@value = '4']")$clickElement() 

# Get all district IDs and the respective names belonging to GOA 
district_IDs <- remDrv$findElements(using = "xpath", 
           "//select[@name = '_ctl0:ContentPlaceHolder1:DropDownList9']/option") %>% 
    lapply(function(x){x$getElementAttribute('value')}) %>% 
    unlist 

district_names <- remDrv$findElements(using = "xpath", 
            "//select[@name = '_ctl0:ContentPlaceHolder1:DropDownList9']/option") %>% 
    lapply(function(x){x$getElementText()}) %>% 
    unlist 


# Retrieve and download results ------------------------------------------------ 

result <- data.frame(district = character(), teshil = character(), 
        V1 = character(), V2 = character(), V3 = character()) 

for (i in seq_along(district_IDs)) { 

    remDrv$findElement(using = "xpath", 
        paste0("//select[@name = '_ctl0:ContentPlaceHolder1:DropDownList9']/option[@value = ", 
          "'", district_IDs[i], "']"))$clickElement() 
    Sys.sleep(2) 

    # Get all tehsil IDs and names from the currently selected district 
    tehsil_IDs <- remDrv$findElements(using = "xpath", 
        "//div[@id = '_ctl0_ContentPlaceHolder1_Panel4']/select/option") %>% 
    lapply(function(x){x$getElementAttribute('value')}) %>% 
    unlist 

    tehsil_names <- remDrv$findElements(using = "xpath", 
                "//div[@id = '_ctl0_ContentPlaceHolder1_Panel4']/select/option") %>% 
    lapply(function(x){x$getElementText()}) %>% 
    unlist 

    for (j in seq_along(tehsil_IDs)) { 

    remDrv$findElement(using = "xpath", 
         paste0("//div[@id = '_ctl0_ContentPlaceHolder1_Panel4']/select/option[@value = ", 
           "'", tehsil_IDs[j], "']"))$clickElement() 
    Sys.sleep(2) 

    # Click submit and download data of the selected tehsil 
    remDrv$findElement(using = "xpath", 
         "//input[@value = 'Submit']")$clickElement() 
    Sys.sleep(2) 

    # Download data for current tehsil 
    tehsil_data <- remDrv$getPageSource()[[1]] %>% 
     htmlParse %>% 
     readHTMLTable %>% 
     extract2(4) %>% 
     extract(c(-1, -2),) 

    result <- data.frame(district = district_names[i], tehsil = tehsil_names[j], 
         tehsil_data) %>% rbind(result, .) 

    remDrv$goBack() 
    Sys.sleep(2) 
    } 
} 

remDrv$quit() 
remDrv$closeServer() 

result %<>% as_data_frame %>% 
    rename(
    si_no = V1, 
    holding_size = V2, 
    inst_holdings = V3 
    ) %>% 
    mutate(
    si_no = as.numeric(as.character(si_no)), 
    inst_holdings = as.numeric(as.character(inst_holdings)) 
    ) 

dim(result) 
# [1] 66 5 

head(result) 
# district tehsil si_no holding_size inst_holdings 
# 1 NORTH GOA ponda  1  MARGINAL   0.34 
# 2 NORTH GOA ponda  2   SMALL   0.00 
# 3 NORTH GOA ponda  3  SEMIMEDIUM   2.50 
# 4 NORTH GOA ponda  4   MEDIUM   0.00 
# 5 NORTH GOA ponda  5   LARGE  182.64 
# 6 NORTH GOA ponda  6 ALL SIZE CLASS   41.09 

tail(result) 
# district tehsil si_no holding_size inst_holdings 
# 1 SOUTH GOA quepem  1  MARGINAL   0.30 
# 2 SOUTH GOA quepem  2   SMALL   0.00 
# 3 SOUTH GOA quepem  3  SEMIMEDIUM   0.00 
# 4 SOUTH GOA quepem  4   MEDIUM   0.00 
# 5 SOUTH GOA quepem  5   LARGE   23.50 
# 6 SOUTH GOA quepem  6 ALL SIZE CLASS   15.77 

RSelenium даже поддерживает обезглавленный просмотр Усиливая PhantomJS, как описано в этом vignette.

+0

Спасибо, Алекс, это выглядит очень многообещающе. Однако в строке remDrv $ open() мой R возвращает ошибку: Ошибка: сводка: UnknownError Detail: при обработке команды произошла неизвестная ошибка на стороне сервера. Класс: org.openqa.selenium.webDriverException Может ли это иметь отношение к настройкам моего брандмауэра? –

+0

В этом случае я проверил бы раздел [вопрос] (https://github.com/ropensci/RSelenium) в репозитории GitHub RSelenium. Если вы попытаетесь найти свой ответ, просто откройте новую проблему. – alex23lemm

+0

Я запускал его на другом компьютере, и теперь он отлично работал. Мое лучшее предположение: у него есть что-то с настройками брандмауэра или антивируса. Большое спасибо! –

Смежные вопросы