Raspado web
Con el lenguaje de programación Python, es posible "extraer" datos de la web de una manera rápida y eficiente.
El web scraping se define como:
una herramienta para convertir los datos no estructurados en la web en datos estructurados legibles por máquina que están listos para el análisis. (fuente)El web scraping es una herramienta valiosa en el conjunto de habilidades del científico de datos.
Ahora, ¿qué raspar?

Datos disponibles públicamente
El sitio web de KanView es compatible con "Transparencia en el gobierno". Ese es también el lema del sitio. El sitio proporciona datos de nómina para el estado de Kansas. ¡Y eso es genial!
Sin embargo, al igual que muchos sitios web gubernamentales, esconde los datos en enlaces y tablas detallados. Esto a menudo requiere una "navegación basada en la mejor estimación" para encontrar los datos específicos que está buscando. Quería utilizar los datos públicos proporcionados para las universidades de Kansas en un proyecto de investigación. Raspar los datos con Python y guardarlos como JSON era lo que tenía que hacer para empezar.
Los enlaces JavaScript aumentan la complejidad
El raspado web con Python a menudo no requiere más que el uso del módulo Beautiful Soup para alcanzar la meta. Beautiful Soup es una biblioteca de Python popular que facilita la implementación del raspado web al atravesar el DOM (modelo de objeto de documento).
Sin embargo, el sitio web de KanView utiliza enlaces JavaScript. Por lo tanto, los ejemplos que usan Python y Beautiful Soup no funcionarán sin algunas adiciones adicionales.

Selenio al rescate
El paquete Selenium se utiliza para automatizar la interacción del navegador web desde Python. Con Selenium, es posible programar un script de Python para automatizar un navegador web. Posteriormente, esos molestos enlaces de JavaScript ya no son un problema.
from selenium import webdriver from selenium.webdriver.common.keys import Keys from bs4 import BeautifulSoup import re import pandas as pd import os
Selenium ahora iniciará una sesión de navegador. Para que Selenium funcione, debe acceder al controlador del navegador. De forma predeterminada, se verá en el mismo directorio que el script de Python. Los enlaces a los controladores de Chrome, Firefox, Edge y Safari están disponibles aquí. El siguiente código de ejemplo usa Firefox:
#launch url url = "//kanview.ks.gov/PayRates/PayRates_Agency.aspx" # create a new Firefox session driver = webdriver.Firefox() driver.implicitly_wait(30) driver.get(url) python_button = driver.find_element_by_id('MainContent_uxLevel1_Agencies_uxAgencyBtn_33') #FHSU python_button.click() #click fhsu link
Lo python_button.click()
anterior le dice a Selenium que haga clic en el enlace de JavaScript en la página. Después de llegar a la página de títulos de trabajo, Selenium entrega la fuente de la página a Beautiful Soup.

Transición a una sopa hermosa
Beautiful Soup sigue siendo la mejor manera de atravesar el DOM y extraer los datos. Después de definir una lista vacía y una variable de contador, es hora de pedirle a Beautiful Soup que tome todos los enlaces de la página que coincidan con una expresión regular:
#Selenium hands the page source to Beautiful Soup soup_level1=BeautifulSoup(driver.page_source, 'lxml') datalist = [] #empty list x = 0 #counter for link in soup_level1.find_all('a', id=re.compile("^MainContent_uxLevel2_JobTitles_uxJobTitleBtn_")): ##code to execute in for loop goes here
Puede ver en el ejemplo anterior que Beautiful Soup recuperará un enlace de JavaScript para cada puesto de trabajo en la agencia estatal. Ahora, en el bloque de código del bucle for / in, Selenium hará clic en cada enlace de JavaScript. Beautiful Soup recuperará la tabla de cada página.
#Beautiful Soup grabs all Job Title links for link in soup_level1.find_all('a', id=re.compile("^MainContent_uxLevel2_JobTitles_uxJobTitleBtn_")): #Selenium visits each Job Title page python_button = driver.find_element_by_id('MainContent_uxLevel2_JobTitles_uxJobTitleBtn_' + str(x)) python_button.click() #click link #Selenium hands of the source of the specific job page to Beautiful Soup soup_level2=BeautifulSoup(driver.page_source, 'lxml') #Beautiful Soup grabs the HTML table on the page table = soup_level2.find_all('table')[0] #Giving the HTML table to pandas to put in a dataframe object df = pd.read_html(str(table),header=0) #Store the dataframe in a list datalist.append(df[0]) #Ask Selenium to click the back button driver.execute_script("window.history.go(-1)") #increment the counter variable before starting the loop over x += 1

pandas: biblioteca de análisis de datos de Python
Beautiful Soup pasa los hallazgos a los pandas. Pandas usa su read_html
función para leer los datos de la tabla HTML en un marco de datos. El marco de datos se agrega a la lista vacía definida previamente.
Antes de que se complete el bloque de código del bucle, Selenium debe hacer clic en el botón Atrás en el navegador. Esto es así para que el siguiente enlace del bucle esté disponible para hacer clic en la página de la lista de trabajos.
Cuando el ciclo for / in se ha completado, Selenium ha visitado todos los enlaces de títulos de trabajo. Beautiful Soup ha recuperado la tabla de cada página. Pandas ha almacenado los datos de cada tabla en un marco de datos. Cada marco de datos es un elemento de la lista de datos. Los marcos de datos de tablas individuales ahora deben fusionarse en un marco de datos grande. Luego, los datos se convertirán al formato JSON con pandas.Dataframe.to_json:
#loop has completed #end the Selenium browser session driver.quit() #combine all pandas dataframes in the list into one big dataframe result = pd.concat([pd.DataFrame(datalist[i]) for i in range(len(datalist))],ignore_index=True) #convert the pandas dataframe to JSON json_records = result.to_json(orient='records')
Ahora Python crea el archivo de datos JSON. ¡Está listo para usar!
#get current working directory path = os.getcwd() #open, write, and close the file f = open(path + "\\fhsu_payroll_data.json","w") #FHSU f.write(json_records) f.close()
El proceso automatizado es rápido
El proceso de raspado web automatizado descrito anteriormente se completa rápidamente. Selenium abre una ventana del navegador que puede ver funcionando. Esto me permite mostrarles un video de captura de pantalla de lo rápido que es el proceso. Verá lo rápido que el script sigue un enlace, toma los datos, retrocede y hace clic en el siguiente enlace. Hace que la recuperación de datos de cientos de enlaces sea cuestión de minutos de un solo dígito.
El código completo de Python
Aquí está el código Python completo. He incluido una importación para tabular. Requiere una línea adicional de código que usará tabular para imprimir los datos en su interfaz de línea de comandos:
from selenium import webdriver from selenium.webdriver.common.keys import Keys from bs4 import BeautifulSoup import re import pandas as pd from tabulate import tabulate import os #launch url url = "//kanview.ks.gov/PayRates/PayRates_Agency.aspx" # create a new Firefox session driver = webdriver.Firefox() driver.implicitly_wait(30) driver.get(url) #After opening the url above, Selenium clicks the specific agency link python_button = driver.find_element_by_id('MainContent_uxLevel1_Agencies_uxAgencyBtn_33') #FHSU python_button.click() #click fhsu link #Selenium hands the page source to Beautiful Soup soup_level1=BeautifulSoup(driver.page_source, 'lxml') datalist = [] #empty list x = 0 #counter #Beautiful Soup finds all Job Title links on the agency page and the loop begins for link in soup_level1.find_all('a', id=re.compile("^MainContent_uxLevel2_JobTitles_uxJobTitleBtn_")): #Selenium visits each Job Title page python_button = driver.find_element_by_id('MainContent_uxLevel2_JobTitles_uxJobTitleBtn_' + str(x)) python_button.click() #click link #Selenium hands of the source of the specific job page to Beautiful Soup soup_level2=BeautifulSoup(driver.page_source, 'lxml') #Beautiful Soup grabs the HTML table on the page table = soup_level2.find_all('table')[0] #Giving the HTML table to pandas to put in a dataframe object df = pd.read_html(str(table),header=0) #Store the dataframe in a list datalist.append(df[0]) #Ask Selenium to click the back button driver.execute_script("window.history.go(-1)") #increment the counter variable before starting the loop over x += 1 #end loop block #loop has completed #end the Selenium browser session driver.quit() #combine all pandas dataframes in the list into one big dataframe result = pd.concat([pd.DataFrame(datalist[i]) for i in range(len(datalist))],ignore_index=True) #convert the pandas dataframe to JSON json_records = result.to_json(orient='records') #pretty print to CLI with tabulate #converts to an ascii table print(tabulate(result, headers=["Employee Name","Job Title","Overtime Pay","Total Gross Pay"],tablefmt='psql')) #get current working directory path = os.getcwd() #open, write, and close the file f = open(path + "\\fhsu_payroll_data.json","w") #FHSU f.write(json_records) f.close()

Conclusión
Web scraping with Python and Beautiful Soup is an excellent tool to have within your skillset. Use web scraping when the data you need to work with is available to the public, but not necessarily conveniently available. When JavaScript provides or “hides” content, browser automation with Selenium will insure your code “sees” what you (as a user) should see. And finally, when you are scraping tables full of data, pandas is the Python data analysis library that will handle it all.
Reference:
The following article was a helpful reference for this project:
//pythonprogramminglanguage.com/web-scraping-with-pandas-and-beautifulsoup/
Reach out to me any time on LinkedIn or Twitter. And if you liked this article, give it a few claps. I will sincerely appreciate it.
//www.linkedin.com/in/davidagray/
Dave Gray (@yesdavidgray) | Twitter
The latest Tweets from Dave Gray (@yesdavidgray). Instructor @FHSUInformatics * Developer * Musician * Entrepreneur *…
twitter.com