2010-08-06 15 views
6

Estoy usando RCurl en R para intentar descargar datos de un sitio web, pero tengo problemas para descubrir qué URL usar. Aquí está el sitio:Encontrar la dirección web de un enlace de Javascript

http://www.invescopowershares.com/products/holdings.aspx?ticker=PGX

Vea cómo en la parte superior derecha, por encima de la hoja que se muestra, hay un enlace para descargar los datos como un archivo .csv? Me preguntaba si había una manera de encontrar una dirección HTTP regular para ese archivo .csv, porque RCurl no puede manejar los comandos de Javascript.

Respuesta

7

Al hacer clic en el siguiente enlace ejecuta este fragmento de código JavaScript:

__doPostBack('ctl00$MainPageLeft$MainPageContent$ExportHoldings1$LinkButton1','') 

Eso __doPostBack función parece sólo tiene que rellenar un par de campos de formulario ocultos en esa página a continuación, envía una solicitud POST.

Un rápido Google muestra que RCurl es capaz de enviar una solicitud POST. Entonces, lo que tendría que hacer es buscar en el origen de esa página, encontrar el formulario con el nombre "aspnetForm", tomar todos los campos de ese formulario y crear su propia solicitud POST que envíe los campos a la URL de acción (http://www.invescopowershares.com/products/holdings.aspx?ticker=PGX)

No se puede garantizar que esto funcione, sin embargo. Parece que hay un campo de formulario oculto llamado __VIEWSTATE que parece codificar cierta información, y no sé cómo influye esto.

+0

Great-- ¿dónde encontrar la documentación sobre cómo presentar una solicitud POST para Javascript usando RCurl? –

+0

http://www.omegahat.org/RCurl/installed/RCurl/html/postForm.html – Jeff

1

Esta es definitivamente la manera de obtener el archivo .csv en RCurl, pero no puedo " t averiguar qué campos de formulario quiero usar en getForm para que funcione. ¿Debo usar los campos del comando doPostBack que está adjunto al enlace "Descargar" en la página, o debería usar los campos de aspnetForm en la página fuente? Solo como referencia, el campo aspnetForm que nos interesa es:

" form name =" aspnetForm "method =" post "action =" holdings.aspx? Ticker = PGX "id =" aspnetForm "style =" margen: 0px " "

... y la solicitud postForm he intentado que no funcionó fue

postForm (" http://www.invescopowershares.com/products/holdings.aspx?ticker=PGX", "nombre del formulario" = "aspnetForm", "método" = " post "," action "=" holdings.aspx? ticker = PGX "," id "=" aspnetForm "," style "=" margin: 0px ")

¡Gracias por toda la ayuda!

+0

Comience con los campos en el formulario aspnetForm, luego anule lo que esté allí con los valores que la función doPostBack inserta en el campos ocultos.Porque lo que doPostBack hace es básicamente tomar el formulario existente y completar dos de los campos ocultos, luego enviar el formulario. – Jeff

10

Le daré una forma rápida y sucia de obtener los datos. En primer lugar, puede usar Fiddler2 http://www.fiddler2.com/fiddler2/ para inspeccionar la POST que envía su navegador. Esto se traduce en el siguiente post:

POST http://www.invescopowershares.com/products/holdings.aspx?ticker=PGX HTTP/1.1 
Host: www.invescopowershares.com 
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: en-us,en;q=0.5 
Accept-Encoding: gzip, deflate 
DNT: 1 
Connection: keep-alive 
Referer: http://www.invescopowershares.com/products/holdings.aspx?ticker=PGX 
Content-Type: application/x-www-form-urlencoded 
Content-Length: 70669 

__EVENTTARGET=ctl00%24MainPageLeft%24MainPageContent%24ExportHoldings1%24LinkButton1&__EVENTARGUMENT=&__VIEWSTATE=%2FwEPDwUKLTE1OTcxNjYzNw9kFgJmD2QWBAIDD2QWBAIDD2QWCAIBDw9kFgQeC2........ 

Así podemos ver que 3 parámetros se están publicando a saber __EVENTTARGET, __EVENTVALIDATION y __VIEWSTATE.

la forma requerida para la llamada postForm sería:

postForm(ftarget, "form name" = "aspnetForm", "method" = "POST", "action" = "holdings.aspx?ticker=PGX", "id" = "aspnetForm","__EVENTTARGET"=event.target,"__EVENTVALIDATION"=event.val,"__VIEWSTATE"=view.state) 

Ahora viene la parte rápida y sucia.Me acaba de abrir un navegador y obtener los parámetros relevantes que recieves de la siguiente manera:

library(rcom) 
ie = comCreateObject('InternetExplorer.Application') 
ie[["visible"]]=T # true for debugging 
ie$Navigate2("http://www.invescopowershares.com/products/holdings.aspx?ticker=PGX") 
while(comGetProperty(ie,"busy")||comGetProperty(ie,"ReadyState")<4){ 
Sys.sleep(1) 
print(comGetProperty(ie,"ReadyState")) 
} 
myDoc<-comGetProperty(ie,"Document") 
myPW<-comGetProperty(myDoc,"parentWindow") 
comInvoke(myPW,"execScript","var dumVar1=theForm.__EVENTVALIDATION.value;var dumVar2=theForm.__VIEWSTATE.value;","JavaScript") 
event.val<-myPW[["dumVar1"]] 
view.state<-myPW[["dumVar2"]] 
event.target<-"ctl00$MainPageLeft$MainPageContent$ExportHoldings1$LinkButton1" 
ie$Quit() 
ftarget<-"http://www.invescopowershares.com/products/holdings.aspx?ticker=PGX" 
web.data<-postForm(ftarget, "form name" = "aspnetForm", "method" = "POST", "action" = "holdings.aspx?ticker=PGX", "id" = "aspnetForm","__EVENTTARGET"=event.target,"__EVENTVALIDATION"=event.val,"__VIEWSTATE"=view.state) 
write(web.data[1],'temp.csv') 
fin.data<-read.csv('temp.csv') 


> fin.data[1,] 
    ticker SecurityNum      Name CouponRate maturitydate 
1 PGX 949746879 WELLS FARGO & COMPANY PFD  0.08    
    rating Shares PercentageOfFund PositionDate 
1 BBB+/Baa3 2538656  0.04442112 06/11/2012 

__EVENTVALIDATION, __VIEWSTATE tal vez sea siempre el mismo o tal vez las cookies de sesión. Probablemente puedas obtenerlos usando RCurl, pero como digo, esta es la solución rápida y sucia, y solo tomamos los que se le da a Internet Explorer. Cosas a tener en cuenta:

1). Esto requiere ventanas con IE instalado para usar los bits rcom.

2). Si está ejecutando ie9, puede necesitar agregar invescopowershares.com a la Configuración de vista de compatibilidad (ya que Microsoft parece haber bloqueado event.val < -myPW [["dumVar1"]] tipo com llamadas)

EDITAR (ACTUALIZAR)

Después de examinar el sitio web con más detalle __EVENTVALIDATION, __VIEWSTATE se configuran como variables de JavaScript en la página inicial. Podemos analizar estos de manera rápida y sucia de la siguiente manera sin recurrir a llamar a un navegador.

dum<-getURL("http://www.invescopowershares.com/products/holdings.aspx?ticker=PGX") 
event.target<-"ctl00$MainPageLeft$MainPageContent$ExportHoldings1$LinkButton1" 
event.val<-unlist(strsplit(dum,"__EVENTVALIDATION\" value=\""))[2] 
event.val<-unlist(strsplit(event.val,"\" />\r\n\r\n<script"))[1] 
view.state<-unlist(strsplit(dum,"id=\"__VIEWSTATE\" value=\""))[2] 
view.state<-unlist(strsplit(view.state,"\" />\r\n\r\n\r\n<script"))[1] 
ftarget<-"http://www.invescopowershares.com/products/holdings.aspx?ticker=PGX" 
web.data<-postForm(ftarget, "form name" = "aspnetForm", "method" = "POST", "action" = "holdings.aspx?ticker=PGX", "id" = "aspnetForm","__EVENTTARGET"=event.target,"__EVENTVALIDATION"=event.val,"__VIEWSTATE"=view.state) 
write(web.data[1],'temp.csv') 
fin.data<-read.csv('temp.csv') 

Lo anterior debe funcionar multiplataforma.

+0

¡Bravo! ¡Bravo! ¡Muchas gracias! – GSee

1

Ahora hay una función en el qmao package que hará esto por usted. (Se basa en código de una respuesta ahora eliminada a esta pregunta.)

Puede utilizar el dlPowerShares función como esta:

require("qmao") 
Symbol <- "PGX" 
dat <- qmao:::dlPowerShares(event.target = "ctl00$MainPageLeft$MainPageContent$ExportHoldings1$LinkButton1", 
          action = paste0("holdings.aspx?ticker=", Symbol)) 
> head(dat) 
    ticker SecurityNum       Name CouponRate maturitydate rating Shares PercentageOfFund PositionDate 
1 PGX 173080201   CITIGROUP CAPITAL XIII 0.07875 10/30/2040 BB/Ba2 2998647  0.04274939 08/31/2012 
2 PGX 949746879  WELLS FARGO & COMPANY PFD 0.08000    BBB+/Baa3 2549992  0.03935854 08/31/2012 
3 PGX 06739H362  BARCLAYS BK PLC    0.08125    A-/Baa3 2757635  0.03644835 08/31/2012 
4 PGX 46625H621  JPMORGAN CHASE    0.08625    BBB+/Baa1 2416021  0.03310707 08/31/2012 
5 PGX 060505765 BANK OF AMERICA CORP PFD 8.2 0.08200     BB+/B1 2345508  0.03128002 08/31/2012 
6 PGX 060505559 BANC OF AMERICA CORP PFD 8.625 0.08625     BB+/B1 2259484  0.03001599 08/31/2012 

En el código anterior, event.target es la primera cadena en el interior de la función javascript: __ doPostBack() que obtendrá cuando haga clic con el botón derecho en el enlace "Descargar" y "Copiar dirección de enlace".

action es la parte específica de producto de la url de acción.

Internamente, el código siguiente Jeff's sugerencia en su answer y búsquedas de la fuente de la página para los valores de los campos para el "aspnetForm". A continuación, utiliza esos valores en una llamada a postForm (del paquete RCurl.)

En el qmao package, dlPowerShares es utilizado por getHoldings.powershares. Además, getHoldings llamará al getHoldings.powershares si uno de los Symbols que se le transfiere es el símbolo de un ETF de PowerShares.


p.s. Si qmao:::dlPowerShares se llama con sus valores por defecto, se descargará la lista de productos a partir de PowerShares http://www.invescopowershares.com/products/

Cuestiones relacionadas