una tutorial scraping pagina medium extraer ejemplos datos python html web-scraping page-numbering

tutorial - scraping beautifulsoup python



Raspe varias páginas con BeautifulSoup y Python (1)

Mi código raspa con éxito las etiquetas tr align = center de [ http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY ] y escribe los elementos td en un archivo de texto.

Sin embargo, hay varias páginas disponibles en el sitio anterior en las que me gustaría poder raspar.

Por ejemplo, con la url anterior, cuando hago clic en el enlace a "página 2", la URL general NO cambia. Miré la fuente de la página y vi un código de JavaScript para pasar a la página siguiente.

¿Cómo puedo cambiar mi código para eliminar datos de todas las páginas enumeradas disponibles?

Mi código que funciona solo para la página 1:

import bs4 import requests response = requests.get(''http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY'') soup = bs4.BeautifulSoup(response.text) soup.prettify() acct = open("/Users/it/Desktop/accounting.txt", "w") for tr in soup.find_all(''tr'', align=''center''): stack = [] for td in tr.findAll(''td''): stack.append(td.text.replace(''/n'', '''').replace(''/t'', '''').strip()) acct.write(", ".join(stack) + ''/n'')


El truco aquí es verificar las solicitudes que entran y salen de la acción de cambio de página cuando haces clic en el enlace para ver las otras páginas. La forma de comprobar esto es usar la herramienta de inspección de Chrome (al presionar F12 ) o instalar la extensión Firebug en Firefox. Usaré la herramienta de inspección de Chrome en esta respuesta. Ver a continuación para mi configuración.

Ahora, lo que queremos ver es una solicitud GET a otra página o una solicitud POST que cambie la página. Mientras la herramienta está abierta, haga clic en un número de página. Por un momento muy breve, solo habrá una solicitud que aparecerá, y es un método POST . Todos los otros elementos seguirán rápidamente y llenarán la página. Vea a continuación lo que estamos buscando.

Haga clic en el método POST arriba. Debería aparecer una subventana de tipo que tiene pestañas. Haga clic en la pestaña Headers . Esta página enumera los encabezados de las solicitudes, más o menos las cosas de identificación que el otro lado (el sitio, por ejemplo) necesita de usted para poder conectarse (alguien más puede explicar este muuuch mejor que yo).

Siempre que la URL tenga variables como números de página, marcadores de ubicación o categorías, con más frecuencia, el sitio utiliza cadenas de consulta. Una larga historia abreviada, es similar a una consulta SQL (en realidad, es una consulta SQL, a veces) que permite que el sitio obtenga la información que necesita. Si este es el caso, puede verificar los encabezados de solicitud para los parámetros de cadena de consulta. Desplácese un poco hacia abajo y debería encontrarlo.

Como puede ver, los parámetros de cadena de consulta coinciden con las variables en nuestra URL. Un poco más abajo, puede ver los Form Data con pageNum: 2 debajo de él. Esta es la clave.

POST solicitudes POST conocen más comúnmente como solicitudes de formularios porque son el tipo de solicitudes realizadas cuando envía formularios, inicia sesión en sitios web, etc. Básicamente, casi cualquier cosa donde tenga que enviar información. Lo que la mayoría de la gente no ve es que las solicitudes POST tienen una URL que siguen. Un buen ejemplo de esto es cuando inicias sesión en un sitio web y, muy brevemente, ves el cambio de tu barra de direcciones en una especie de URL de galimatías antes de establecerse en /index.html o somesuch.

Lo que básicamente significa el párrafo anterior es que puede (pero no siempre) anexar los datos del formulario a su URL y llevará a cabo la solicitud POST en la ejecución. Para saber la cadena exacta que debe agregar, haga clic en view source .

Prueba si funciona agregándolo a la URL.

Et voila, funciona. Ahora, el verdadero desafío: obtener la última página automáticamente y raspar todas las páginas. Tu código está más o menos allí. Lo único que queda por hacer es obtener el número de páginas, construir una lista de URL para raspar e iterar sobre ellas.

El código modificado está a continuación:

from bs4 import BeautifulSoup as bsoup import requests as rq import re base_url = ''http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY'' r = rq.get(base_url) soup = bsoup(r.text) # Use regex to isolate only the links of the page numbers, the one you click on. page_count_links = soup.find_all("a",href=re.compile(r".*javascript:goToPage.*")) try: # Make sure there are more than one page, otherwise, set to 1. num_pages = int(page_count_links[-1].get_text()) except IndexError: num_pages = 1 # Add 1 because Python range. url_list = ["{}&pageNum={}".format(base_url, str(page)) for page in range(1, num_pages + 1)] # Open the text file. Use with to save self from grief. with open("results.txt","wb") as acct: for url_ in url_list: print "Processing {}...".format(url_) r_new = rq.get(url_) soup_new = bsoup(r_new.text) for tr in soup_new.find_all(''tr'', align=''center''): stack = [] for td in tr.findAll(''td''): stack.append(td.text.replace(''/n'', '''').replace(''/t'', '''').strip()) acct.write(", ".join(stack) + ''/n'')

Usamos expresiones regulares para obtener los enlaces adecuados. Luego, al usar la lista de comprensión, creamos una lista de cadenas de URL. Finalmente, iteramos sobre ellos.

Resultados:

Processing http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY&pageNum=1... Processing http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY&pageNum=2... Processing http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY&pageNum=3... [Finished in 6.8s]

Espero que ayude.

EDITAR:

Por puro aburrimiento, creo que acabo de crear un scraper para todo el directorio de clases. Además, actualizo tanto el código anterior como el siguiente para que no se produzca un error cuando solo hay una página disponible.

from bs4 import BeautifulSoup as bsoup import requests as rq import re spring_2015 = "http://my.gwu.edu/mod/pws/subjects.cfm?campId=1&termId=201501" r = rq.get(spring_2015) soup = bsoup(r.text) classes_url_list = [c["href"] for c in soup.find_all("a", href=re.compile(r".*courses.cfm/?campId=1&termId=201501&subjId=.*"))] print classes_url_list with open("results.txt","wb") as acct: for class_url in classes_url_list: base_url = "http://my.gwu.edu/mod/pws/{}".format(class_url) r = rq.get(base_url) soup = bsoup(r.text) # Use regex to isolate only the links of the page numbers, the one you click on. page_count_links = soup.find_all("a",href=re.compile(r".*javascript:goToPage.*")) try: num_pages = int(page_count_links[-1].get_text()) except IndexError: num_pages = 1 # Add 1 because Python range. url_list = ["{}&pageNum={}".format(base_url, str(page)) for page in range(1, num_pages + 1)] # Open the text file. Use with to save self from grief. for url_ in url_list: print "Processing {}...".format(url_) r_new = rq.get(url_) soup_new = bsoup(r_new.text) for tr in soup_new.find_all(''tr'', align=''center''): stack = [] for td in tr.findAll(''td''): stack.append(td.text.replace(''/n'', '''').replace(''/t'', '''').strip()) acct.write(", ".join(stack) + ''/n'')