asp.net - cómo enviar una consulta a la página.aspx en python
asp.net-ajax (5)
"Asuma que debemos seleccionar" todos los años "y" todos los tipos "en los respectivos menús desplegables".
¿Qué hacen estas opciones con la URL que finalmente se envía?
Después de todo, equivale a una solicitud HTTP enviada a través de urllib2
.
Sepa cómo hacer "todos los años" y "todos los tipos" desde los respectivos menús desplegables: haga lo siguiente.
Seleccione ''"todos los años" y "todos los tipos" en los respectivos menús desplegables''
Tenga en cuenta la URL que se envía realmente.
Utilice esta URL en
urllib2
.
Necesito raspar los resultados de la consulta de una página web .aspx.
http://legistar.council.nyc.gov/Legislation.aspx
La url es estática, entonces, ¿cómo envío una consulta a esta página y obtengo los resultados? Supongamos que debemos seleccionar "todos los años" y "todos los tipos" en los respectivos menús desplegables.
Alguien por ahí debe saber cómo hacer esto.
Como resumen, deberá realizar cuatro tareas principales:
- enviar solicitud (s) al sitio web,
- para recuperar la (s) respuesta (s) del sitio
- para analizar estas respuestas
- tener algo de lógica para iterar en las tareas anteriores, con parámetros asociados con la navegación (a "las siguientes" páginas en la lista de resultados)
El manejo de solicitudes y respuestas http se realiza con métodos y clases de urllib y urllib2 la biblioteca estándar de Python. El análisis de las páginas html se puede hacer con el HTMLParser la biblioteca estándar de HTMLParser o con otros módulos como Beautiful Soup
El siguiente fragmento muestra la solicitud y recepción de una búsqueda en el sitio indicado en la pregunta. Este sitio está dirigido por ASP y, como resultado, debemos asegurarnos de que enviamos varios campos de formulario, algunos de ellos con valores "horribles", ya que estos son utilizados por la lógica ASP para mantener el estado y autenticar la solicitud en cierta medida. De hecho la presentación. Las solicitudes deben enviarse con el método HTTP POST, ya que esto es lo que se espera de esta aplicación ASP. La principal dificultad es identificar el campo de formulario y los valores asociados que ASP espera (obtener las páginas con Python es la parte fácil).
Este código es funcional o, más precisamente, fue funcional, hasta que eliminé la mayor parte del valor VSTATE y posiblemente introduje un error tipográfico o dos agregando comentarios.
import urllib
import urllib2
uri = ''http://legistar.council.nyc.gov/Legislation.aspx''
#the http headers are useful to simulate a particular browser (some sites deny
#access to non-browsers (bots, etc.)
#also needed to pass the content type.
headers = {
''HTTP_USER_AGENT'': ''Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13'',
''HTTP_ACCEPT'': ''text/html,application/xhtml+xml,application/xml; q=0.9,*/*; q=0.8'',
''Content-Type'': ''application/x-www-form-urlencoded''
}
# we group the form fields and their values in a list (any
# iterable, actually) of name-value tuples. This helps
# with clarity and also makes it easy to later encoding of them.
formFields = (
# the viewstate is actualy 800+ characters in length! I truncated it
# for this sample code. It can be lifted from the first page
# obtained from the site. It may be ok to hardcode this value, or
# it may have to be refreshed each time / each day, by essentially
# running an extra page request and parse, for this specific value.
(r''__VSTATE'', r''7TzretNIlrZiKb7EOB3AQE ... ...2qd6g5xD8CGXm5EftXtNPt+H8B''),
# following are more of these ASP form fields
(r''__VIEWSTATE'', r''''),
(r''__EVENTVALIDATION'', r''/wEWDwL+raDpAgKnpt8nAs3q+pQOAs3q/pQOAs3qgpUOAs3qhpUOAoPE36ANAve684YCAoOs79EIAoOs89EIAoOs99EIAoOs39EIAoOs49EIAoOs09EIAoSs99EI6IQ74SEV9n4XbtWm1rEbB6Ic3/M=''),
(r''ctl00_RadScriptManager1_HiddenField'', ''''),
(r''ctl00_tabTop_ClientState'', ''''),
(r''ctl00_ContentPlaceHolder1_menuMain_ClientState'', ''''),
(r''ctl00_ContentPlaceHolder1_gridMain_ClientState'', ''''),
#but then we come to fields of interest: the search
#criteria the collections to search from etc.
# Check boxes
(r''ctl00$ContentPlaceHolder1$chkOptions$0'', ''on''), # file number
(r''ctl00$ContentPlaceHolder1$chkOptions$1'', ''on''), # Legislative text
(r''ctl00$ContentPlaceHolder1$chkOptions$2'', ''on''), # attachement
# etc. (not all listed)
(r''ctl00$ContentPlaceHolder1$txtSearch'', ''york''), # Search text
(r''ctl00$ContentPlaceHolder1$lstYears'', ''All Years''), # Years to include
(r''ctl00$ContentPlaceHolder1$lstTypeBasic'', ''All Types''), #types to include
(r''ctl00$ContentPlaceHolder1$btnSearch'', ''Search Legislation'') # Search button itself
)
# these have to be encoded
encodedFields = urllib.urlencode(formFields)
req = urllib2.Request(uri, encodedFields, headers)
f= urllib2.urlopen(req) #that''s the actual call to the http site.
# *** here would normally be the in-memory parsing of f
# contents, but instead I store this to file
# this is useful during design, allowing to have a
# sample of what is to be parsed in a text editor, for analysis.
try:
fout = open(''tmp.htm'', ''w'')
except:
print(''Could not open output file/n'')
fout.writelines(f.readlines())
fout.close()
Eso es todo por conseguir la página inicial. Como se dijo anteriormente, entonces sería necesario analizar la página, es decir, buscar las partes de interés y reunirlas según corresponda, y almacenarlas en el archivo / base de datos / donde sea. Este trabajo se puede hacer de muchas maneras: usando analizadores html, o el tipo de tecnología XSLT (incluso después de analizar el html a xml), o incluso para trabajos crudos, expresiones regulares simples. Además, uno de los elementos que normalmente se extrae es la "información siguiente", es decir, un enlace de tipo, que se puede usar en una nueva solicitud al servidor para obtener páginas posteriores.
Esto debería darle una idea aproximada de lo que trata el raspado html de "mano larga". Hay muchos otros enfoques para esto, como utilidades exclusivas, scripts en el complemento GreaseMonkey de Mozilla (Firefox), XSLT ...
El código en las otras respuestas fue útil; Nunca hubiera podido escribir mi rastreador sin él.
Un problema que encontré fue cookies. El sitio que estaba rastreando usaba cookies para registrar datos de identificación / seguridad de sesión, así que tuve que agregar código para que mi rastreador funcionara:
Añadir esta importación:
import cookielib
Inicia las cosas de galletas:
COOKIEFILE = ''cookies.lwp'' # the path and filename that you want to use to save your cookies in
cj = cookielib.LWPCookieJar() # This is a subclass of FileCookieJar that has useful load and save methods
Instale CookieJar
para que se use como el CookieProcessor
predeterminado en el controlador de apertura predeterminado:
cj.load(COOKIEFILE)
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
urllib2.install_opener(opener)
Para ver qué cookies está utilizando el sitio:
print ''These are the cookies we have received so far :''
for index, cookie in enumerate(cj):
print index, '' : '', cookie
Esto guarda las cookies:
cj.save(COOKIEFILE) # save the cookies
La mayoría de los sitios ASP.NET (a los que hace referencia, incluidos) enviarán sus consultas a sí mismos utilizando el verbo HTTP POST, no el verbo GET. Es por eso que la URL no está cambiando como notaste.
Lo que deberá hacer es mirar el HTML generado y capturar todos sus valores de formulario. Asegúrese de capturar todos los valores del formulario, ya que algunos de ellos se utilizan para validar páginas y, sin ellos, se rechazará su solicitud POST.
Aparte de la validación, una página ASPX en lo que respecta a raspado y publicación no es diferente a otras tecnologías web.
Selenium es una excelente herramienta para este tipo de tareas. Puede especificar los valores de formulario que desea ingresar y recuperar el html de la página de respuesta como una cadena en un par de líneas de código de Python. Usando Selenium, es posible que no tenga que realizar el trabajo manual de simulación de una solicitud de publicación válida y todas sus variables ocultas, como descubrí después de muchas pruebas y errores.