Hasta este punto, tenemos un scraper que funciona. Pero eso es prácticamente todo lo que tenemos. Si quieres crear un scraper web más avanzado con Pyppeteer, tendrás que añadir más funcionalidades a id. Alerta de spoiler: nos adentraremos en el mundo de la programación orientada a objetos. Pero primero, definamos nuestros objetivos. ¿Qué queremos que sea capaz de hacer nuestro scraper?
- Inicializar el navegador con algunos valores personalizados
- Navegar y extraer contenido de una página web
- Escribir texto en un campo de entrada
- Extraer el valor de un único elemento
- Extraer el valor de varios elementos
3.1. Opciones personalizadas
Así que vamos a crear una nueva clase `Scraper` por ahora y añadiremos sus métodos más adelante:
class Scraper:
def __init__(self, launch_options: dict) -> None:
self.options = launch_options['options']
self.viewPort = launch_options['viewPort'] if 'viewPort' in launch_options else None
pass
El único argumento que utilizamos para nuestro Scraper es un diccionario `launch_options`. Como ves, contiene dos claves en su interior. Una clave define las opciones del lanzador de Pyppeteer. La segunda opción es `None` o un diccionario que contiene el `width` y el `height` del `viewPort`. Esta última se utiliza para este método.
3.2. Navegar a una página
Si observas la función que utilizamos anteriormente, verás que cubre tanto la navegación como la extracción de datos sin procesar de una URL específica. Lo único que tenemos que hacer es modificarla y convertirla en un método para nuestro Scraper:
async def goto(self, url: str) -> None:
self.browser = await launch(options=self.options)
self.page = await self.browser.newPage()
await self.page.setViewport(self.viewPort) if self.viewPort != None else print('[i] Using default viewport')
await self.page.goto(url)
Este método es bastante sencillo. En primer lugar, abre un nuevo navegador con las opciones personalizadas que hemos establecido anteriormente. A continuación, crea una nueva página y, si nuestro diccionario `launch_options` contiene `viewPort`, establece el viewPort de la página. De lo contrario, registra un mensaje sencillo. Por último, pero no menos importante, nos lleva al destino.
3.3. Extraer datos sin procesar de una página
De nuevo, tenemos el método en nuestra función `scraper` inicial. Solo esperaremos a que se cargue `page.content()` y devuelva su valor:
async def get_full_content(self) -> str:
content = await self.page.content()
return content
3.4. Escribir texto en un campo de entrada
Para escribir algo en un campo de entrada utilizando Pyppeteer, necesitarás dos cosas. Primero, localizar el elemento. Segundo, añadirle algún valor. Por suerte, Pyppeteer tiene métodos para ambas acciones:
async def type_value(self, selector: str, value: str) -> None:
element = await self.page.querySelector(selector)
await element.type(value)
3.5. Extraer el valor de la página
Recuerda que queremos poder extraer tanto el valor de un único elemento como los valores de varios elementos. Podríamos usar un único método para ambos. Pero a mí, por lo general, me gusta tener las cosas separadas. Así que, por ahora, añadiré dos métodos más:
async def extract_one(self, selector) -> str:
element = await self.page.querySelector(selector)
text = await element.getProperty("textContent")
return await text.jsonValue()
Aquí, estamos localizando el elemento utilizando el método `querySelector`. A continuación, esperamos el `textContent` y devolvemos su `jsonValue()`. Por otro lado, cuando queramos seleccionar muchos elementos, utilizaremos `querySelector`:
async def extract_many(self, selector) -> list:
result = []
elements = await self.page.querySelectorAll(selector)
for element in elements:
text = await element.getProperty("textContent")
result.append(await text.jsonValue())
return result
Este método funciona de manera similar a `extract_one`. La única diferencia es su valor de retorno. En esta ocasión, devolvemos una lista con todo el texto que hay dentro de los elementos seleccionados. Y supongo que, con esto añadido, hemos cubierto todos nuestros objetivos.