2009-09-26 16 views

Respuesta

25

Como una visión general, se tendrá que realizar cuatro tareas principales:

  • a presentar la solicitud (s) en el sitio web,
  • para recuperar la respuesta (s) del sitio
  • para analizar estas respuestas
  • que tienen cierta lógica para iterar en las tareas anteriores, con los parámetros asociados a la navegación (a páginas "siguiente" en la lista de resultados)

El manejo de solicitud y respuesta http se realiza con métodos y clases de la biblioteca estándar de Python urllib y urllib2. El análisis de las páginas HTML se puede hacer con HTMLParser o con otros módulos tales como Beautiful Soup

el siguiente fragmento de la biblioteca estándar de Python demuestra la solicitud y recepción de una búsqueda en el sitio indicado en la pregunta.Este sitio es impulsado por ASP y, como resultado, debemos asegurarnos de enviar varios campos de formulario, algunos de ellos con valores "horribles", ya que la lógica de ASP los utiliza para mantener el estado y para autenticar la solicitud hasta cierto punto. De hecho, sometiendo. Las solicitudes deben enviarse con el http POST método ya que esto es lo que se espera de esta aplicación ASP. La dificultad principal es identificar el campo de formulario y los valores asociados que ASP espera (obtener páginas con Python es la parte fácil).

Este código es funcional, o más precisamente, era funcional, hasta que eliminé la mayor parte del valor de VSTATE, y posiblemente introduje un error 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 para obtener la página inicial. Como se dijo anteriormente, entonces uno necesitaría analizar la página, es decir, encontrar 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 tipo de tecnología XSLT (de hecho después de analizar el html a xml), o incluso para trabajos crudos, expresión regular simple. Además, uno de los elementos que normalmente se extrae es la "siguiente información", es decir, un tipo de enlace, que se puede utilizar en una nueva solicitud al servidor para obtener páginas subsiguientes.

Esto debería darle un sabor aproximado de lo que es el raspado html de "mano larga". Hay muchos otros enfoques para esto, como las utilidades dedicadas, los scripts en el complemento GreaseMonkey de Mozilla (FireFox), XSLT ...

+0

Si estoy usando Google Chrome, ¿cómo debería reemplazar el valor de 'HTTP_USER_AGENT'? Lo siento si esta pregunta es tonta ya que no hice muchas cosas en la web. ¡Gracias! – taocp

+0

@taocp, una manera fácil de saber qué cadena 'HTTP_USER_AGENT' usar para un navegador determinado es visitar http://www.all-nettools.com/toolbox/environmental-variables-test.php esta página le mostrará el valores de encabezado enviados por el navegador, busque "HTTP_USER_AGENT". La cadena real depende del sistema operativo y de la versión y compilación específica de Chrome, pero debería verse como 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, como Gecko) Chrome/29.0.1547.66 Safari/537.36' – mjv

+0

muchas gracias por su respuesta. Probé tu código con los valores correctos establecidos en mi navegador Chrome. El resultado del archivo tmp.htm dice "no se encontraron resultados", mientras que cuando coloco "york" en el sitio web, se devuelve mucho. ¿Sabes por qué? – taocp

0

"Supongamos que tenemos que seleccionar" todos los años "y" todos los tipos "de los menús desplegables respectivos".

¿Qué le hacen estas opciones a la URL que finalmente se envía?

Después de todo, equivale a una solicitud HTTP enviada a través de urllib2.

Si sabe cómo hacer "todos los años" y "todos los tipos" desde los menús desplegables respectivos, haga lo siguiente.

  1. Seleccionar 'todos los años "y 'todos los tipos' de los respectivos menús desplegables'

  2. Nota de la URL que se presenta efectivamente.

  3. Utilice esta URL en urllib2.

+0

Al parecer, la página es una forma que requiere la POST, pero la idea es la misma: tomar nota de la nombre del campo de formulario y del valor asociado con 'Todos los años' y con 'todos los tipos' y use urlib2.Request para obtener los datos. – mjv

+0

Estoy usando el proxy de depuración web Charles para ver todo el tráfico http cuando navego por este sitio y enviar consultas, y la url es completamente estática. No contiene ningún parámetro en absoluto. De alguna forma, hay datos de formularios para pases, ajax, supongo, pero no sé cómo enviar los datos de ese formulario al servidor.Todo parece ininteligible para mí. El hecho de que no puedo enviar una consulta manipulando la URL es lo que me confunde. – twneale

+0

Una vez que obtenga los resultados de esta página, si desea escarparla, puede usar el módulo de python HTMLParser o Beautifulsoup para analizar la página html. También es probable que rascar involucre más llamadas urlib2 para navegar a las próximas páginas de resultados. – mjv

4

mayoría de los sitios ASP.NET (la que ha hecho referencia incluido) en realidad a publicar sus consultas nuevo a sí mismos utilizando el verbo HTTP POST, no el verbo GET. Es por eso que la URL no está cambiando como anotó.

Lo que tendrá que hacer es mirar el HTML generado y capturar todos sus valores de formulario. Asegúrese de capturar todos los valores de formulario, ya que algunos de ellos se utilizan para validar la página y sin ellos su solicitud POST será denegada.

Aparte de la validación, una página ASPX en cuanto a raspado y publicación no es diferente de otras tecnologías web.

5

Selenium es una gran 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 python. Usando Selenium, es posible que no tenga que hacer el trabajo manual de simular una solicitud de publicación válida y todas sus variables ocultas, como me enteré después de mucho ensayo y error.

+1

¿Podría proporcionar algún fragmento de código? – taocp

+0

Tuve éxito conectando, iniciando sesión y haciendo clic en enlaces usando selenio. Estoy atrapado en la parte en la que desea tomar datos de una página. Dado que el URI se mantiene igual incluso después de hacer clic, esto plantea un problema. –

4

El código en las otras respuestas fue útil; Nunca hubiera podido escribir mi rastreador sin él.

Un problema que encontré fueron las cookies. El sitio que arrastraba estaba usando cookies para iniciar la sesión del ID de sesión/materia de seguridad, por lo que tuvo que añadir código para obtener mi rastreador para trabajar:

Añadir esta importación:

import cookielib    

Init las cosas cookie:

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 

Instalar CookieJar para que se utiliza como valor predeterminado CookieProcessor en el controlador de apertura por defecto:

cj.load(COOKIEFILE) 
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) 
    urllib2.install_opener(opener) 

para ver lo que las cookies del sitio está utilizando:

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 
Cuestiones relacionadas