Программно соскабливая заголовок ответа внутри R

Я пытаюсь получить доступ к выделенному тексту response header: location на скриншоте ниже, используя только R и его библиотеки скриншотов на основе curl. можно легко добраться до этой точки в любом веб-браузере, посетив http://www.worldvaluessurvey.org/WVSDocumentationWVL.jsp, нажав на загрузку для любого из файлов данных и заполнив формы договора. Загрузка начинается автоматически в веб-браузере.

введите описание изображения здесь

Я считаю, что единственный способ получить действительный файл cookie - library(curlconverter) (см. Как загрузить файл за полуразбитой функцией asp с javascript с помощью R), но этого ответа недостаточно, чтобы программно определить http-адрес файла, только для загрузки заархивированного файла, как только он уже известен.

Я наклеил код ниже с разными httr и curlconverter кодом, с которыми я играл, но у меня что-то отсутствует. Опять же, единственная цель - программно определить выделенный текст целиком внутри R (кросс-платформенный).

library(curlconverter)
library(httr)

browserPOST <-
    "curl 'http://www.worldvaluessurvey.org/AJDownload.jsp'
    -H 'Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'
    -H 'Accept-Encoding:gzip, deflate'
    -H 'Accept-Language:en-US,en;q=0.8'
    -H 'Cache-Control:max-age=0'
    --compressed -H 'Connection:keep-alive'
    -H 'Content-Length:188'
    -H 'Content-Type:application/x-www-form-urlencoded'
    -H 'Cookie:ASPSESSIONIDCASQAACD=IBLGBFOAEHFILMMJJCFEOEMI; JSESSIONID=50DABDEDD0B2FC370C415B4BD1855260; __atuvc=13%7C45; __atuvs=58224f37d312c42400c'
    -H 'Host:www.worldvaluessurvey.org'
    -H 'Origin:http://www.worldvaluessurvey.org'
    -H 'Referer:http://www.worldvaluessurvey.org/AJDownloadLicense.jsp'
    -H 'Upgrade-Insecure-Requests:1'
    -H 'User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36'"

form_data <-
    list( 
        ulthost = "WVS" ,
        CMSID = "" ,
        LITITLE = "" ,
        LINOMBRE = "fas" ,
        LIEMPRESA = "asf" ,
        LIEMAIL = "asdf" ,
        LIPROJECT = "asfd" ,
        LIUSE = "1" ,
        LIPURPOSE = "asdf" ,
        LIAGREE = "1" ,
        DOID = "3996" ,
        CndWAVE = "-1" ,
        SAID = "-1" ,
        AJArchive = "WVS Data Archive" ,
        EdFunction = "" ,
        DOP = "" 
    )   



getDATA <- (straighten(browserPOST) %>% make_req)[[1]]()

a <- VERB(verb = "POST", url = "http://www.worldvaluessurvey.org/AJDownload.jsp", 
    httr::add_headers(Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", 
        `Accept-Encoding` = "gzip, deflate", `Accept-Language` = "en-US,en;q=0.8", 
        `Cache-Control` = "max-age=0", Connection = "keep-alive", 
        `Content-Length` = "188", Host = "www.worldvaluessurvey.org", 
        Origin = "http://www.worldvaluessurvey.org", Referer = "http://www.worldvaluessurvey.org/AJDownloadLicense.jsp", 
        `Upgrade-Insecure-Requests` = "1", `User-Agent` = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36"), 
    httr::set_cookies(`Cookie:ASPSESSIONIDCASQAACD` = "IBLGBFOAEHFILMMJJCFEOEMI", 
        JSESSIONID = "50DABDEDD0B2FC370C415B4BD1855260", `__atuvc` = "13%7C45", 
        `__atuvs` = "58224f37d312c42400c"), encode = "form",body=form_data)

Ответ 1

Это был хороший вызов!

Проблема не связана с языком R. Мы будем иметь тот же результат на любом языке, если просто попробуем опубликовать некоторые данные для загрузки script. Здесь мы имеем дело с каким-то "шаблоном" безопасности. Сайт запрещает пользователям извлекать URL-адреса файлов, и он просит их заполнить формы данными для предоставления этих ссылок. Если браузер может получить эти ссылки, мы также можем написать соответствующие HTTP-вызовы. Дело в том, что нам нужно точно знать, какие вызовы мы должны сделать. Чтобы найти это, нам нужно увидеть индивидуальные вызовы, которые делает сайт, когда кто-то нажимает на скачивание. Вот что я нашел несколько звонков перед успешным вызовом 302 AJDownload.jsp POST:

Http-запросы

Мы можем видеть это ясно, если мы посмотрим на источник AJDocumentation.jsp, он делает эти вызовы с помощью jQuery $.get:

$.get("http://ipinfo.io?token=xxxxxxxxxxxxxx", function (response) {
    var geodatos=encodeURIComponent(response.ip+"\t"+response.country+"\t"+response.postal+"\t"+
    response.loc+"\t"+response.region+"\t"+response.city+"\t"+
    response.org);

    $.get("jdsStatJD.jsp?ID="+geodatos+
        "&url=http%3A%2F%2Fwww.worldvaluessurvey.org%2FAJDocumentation.jsp&referer=null&cms=Documentation",
        function (resp2) {
    });
}, "jsonp");

Затем, несколько вызовов ниже, мы можем увидеть успешный POST /AJDownload.jsp со статусом 302 Moved Temporarily и с желаемым Location в его заголовках ответов:

Http-запросы

HTTP/1.1 302 Moved Temporarily
Content-Length: 0
Content-Type: text/html
Location: http://www.worldvaluessurvey.org/wvsdc/CO00001/F00003724-WVS_Longitudinal_1981-2014_stata_dta_v_2015_04_18.zip
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Thu, 01 Dec 2016 16:24:37 GMT

Итак, это механизм безопасности этого сайта. Он использует ipinfo.io для хранения информации о посетителях об их IP-адресе, местоположении и даже организации ISP непосредственно перед тем, как пользователь начнет загрузку нажав на ссылку. script, который принимает эти данные, является /jdsStatJD.jsp. Я havent использовал ipinfo.io, а также их ключ API для этой службы (они были скрыты на моих снимках экрана), и вместо этого я создал фиктивную действительную последовательность данных, просто чтобы проверить запрос. Данные формы сообщения для "защищенных" файлов вообще не требуются. Можно загружать файлы, не публикуя эти данные.

Кроме того, библиотека curlconverter не требуется. Все, что нам нужно сделать, это простые запросы GET и POST с использованием библиотеки httr. Одна из важных моментов, которые я хочу отметить, заключается в том, что для предотвращения использования функции httr POST после заголовка Location, полученного с состоянием 302 при нашем последнем вызове, нам нужно использовать настройку конфигурации config(followlocation = FALSE) что, конечно, не позволит ему следовать за Location и выберем Location из заголовков.

OUTPUT

My R script может быть запущен из командной строки и может принимать DOID числовые значения параметров для получения необходимого файла. Например, если мы хотим получить ссылку на файл WVS_Longitudinal_1981-2014_stata_dta_v_2015_04_18, тогда мы должны добавить его DOID (который равен 3724) в конец нашего script при вызове с помощью команды Rscript:

Rscript wvs_fetch_downloads.r 3724
[1] "http://www.worldvaluessurvey.org/wvsdc/CO00001/F00003724-WVS_Longitudinal_1981-2014_stata_dta_v_2015_04_18.zip"

Я создал функцию R, чтобы получить каждое местоположение файла, которое вы хотите, просто передав DOID:

getFileById <- function(fileId)

Вы можете удалить синтаксический анализ аргумента командной строки и использовать функцию, передав DOID напрямую:

#args <- commandArgs(TRUE)
#if(length(args) == 0) {
#   print("No file id specified. Use './script.r ####'.")
#   quit("no")
#}

#fileId <- args[1]
fileId <- "3724"

# DOID=3843 : WVS_EVS_Integrated_Dictionary_Codebook v_2014_09_22 (Excel)
# DOID=3844 : WVS_Values Surveys Integrated Dictionary_TimeSeries_v_2014-04-25 (Excel)
# DOID=3725 : WVS_Longitudinal_1981-2014_rdata_v_2015_04_18
# DOID=3996 : WVS_Longitudinal_1981-2014_sas_v_2015_04_18
# DOID=3723 : WVS_Longitudinal_1981-2014_spss_v_2015_04_18
# DOID=3724 : WVS_Longitudinal_1981-2014_stata_dta_v_2015_04_18

getFileById(fileId)

Финальная работа R script

library(httr)

getFileById <- function(fileId) {
    response <- GET(
        url = "http://www.worldvaluessurvey.org/AJDocumentation.jsp?CndWAVE=-1", 
        add_headers(
            `Accept` = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", 
            `Accept-Encoding` = "gzip, deflate",
            `Accept-Language` = "en-US,en;q=0.8", 
            `Cache-Control` = "max-age=0",
            `Connection` = "keep-alive", 
            `Host` = "www.worldvaluessurvey.org", 
            `User-Agent` = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0",
            `Content-type` = "application/x-www-form-urlencoded",
            `Referer` = "http://www.worldvaluessurvey.org/AJDownloadLicense.jsp", 
            `Upgrade-Insecure-Requests` = "1"))

    set_cookie <- headers(response)$`set-cookie`
    cookies <- strsplit(set_cookie, ';')
    cookie <- cookies[[1]][1]

    response <- GET(
        url = "http://www.worldvaluessurvey.org/jdsStatJD.jsp?ID=2.72.48.149%09IT%09undefined%0941.8902%2C12.4923%09Lazio%09Roma%09Orange%20SA%20Telecommunications%20Corporation&url=http%3A%2F%2Fwww.worldvaluessurvey.org%2FAJDocumentation.jsp&referer=null&cms=Documentation", 
        add_headers(
            `Accept` = "*/*", 
            `Accept-Encoding` = "gzip, deflate",
            `Accept-Language` = "en-US,en;q=0.8", 
            `Cache-Control` = "max-age=0",
            `Connection` = "keep-alive", 
            `X-Requested-With` = "XMLHttpRequest",
            `Host` = "www.worldvaluessurvey.org", 
            `User-Agent` = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0",
            `Content-type` = "application/x-www-form-urlencoded",
            `Referer` = "http://www.worldvaluessurvey.org/AJDocumentation.jsp?CndWAVE=-1",
            `Cookie` = cookie))

    post_data <- list( 
        ulthost = "WVS",
        CMSID = "",
        CndWAVE = "-1",
        SAID = "-1",
        DOID = fileId,
        AJArchive = "WVS Data Archive",
        EdFunction = "",
        DOP = "",
        PUB = "")  

    response <- POST(
        url = "http://www.worldvaluessurvey.org/AJDownload.jsp", 
        config(followlocation = FALSE),
        add_headers(
            `Accept` = "*/*", 
            `Accept-Encoding` = "gzip, deflate",
            `Accept-Language` = "en-US,en;q=0.8", 
            `Cache-Control` = "max-age=0",
            `Connection` = "keep-alive",
            `Host` = "www.worldvaluessurvey.org",
            `User-Agent` = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0",
            `Content-type` = "application/x-www-form-urlencoded",
            `Referer` = "http://www.worldvaluessurvey.org/AJDocumentation.jsp?CndWAVE=-1",
            `Cookie` = cookie),
        body = post_data,
        encode = "form")

    location <- headers(response)$location
    location
}

args <- commandArgs(TRUE)
if(length(args) == 0) {
    print("No file id specified. Use './script.r ####'.")
    quit("no")
}

fileId <- args[1]

# DOID=3843 : WVS_EVS_Integrated_Dictionary_Codebook v_2014_09_22 (Excel)
# DOID=3844 : WVS_Values Surveys Integrated Dictionary_TimeSeries_v_2014-04-25 (Excel)
# DOID=3725 : WVS_Longitudinal_1981-2014_rdata_v_2015_04_18
# DOID=3996 : WVS_Longitudinal_1981-2014_sas_v_2015_04_18
# DOID=3723 : WVS_Longitudinal_1981-2014_spss_v_2015_04_18
# DOID=3724 : WVS_Longitudinal_1981-2014_stata_dta_v_2015_04_18

getFileById(fileId)

Ответ 2

Согласно источник базового httr::request_perform, объект, который вы получаете из VERB(), выглядит следующим образом:

res <- response(
  url = resp$url,
  status_code = resp$status_code,
  headers = headers,
  all_headers = all_headers,
  cookies = curl::handle_cookies(handle),
  content = resp$content,
  date = date,
  times = resp$times,
  request = req,
  handle = handle
)

Итак, вас интересует его headers или all_headers (response - это всего лишь структура). Если было задействовано перенаправление, all_headers будет иметь несколько наборов заголовков, возвращаемых curl::parse_headers(), headers всегда являются окончательным набором.