Clase 15: Selenio arrastrándose en acción

En la última lección, aprendimos el uso básico de Selenium. En esta lección, combinaremos un caso real para experimentar los escenarios aplicables y el uso de Selenium.

1. Preparación

Antes de comenzar esta lección, asegúrese de haber realizado los siguientes preparativos:

  • Instale el navegador Chrome y configure el ChromeDriver correctamente.
  • Instale Python (al menos la versión 3.6) y ejecute el programa Python correctamente.
  • Los paquetes relacionados con Selenium están instalados y Selenium se puede utilizar con éxito para abrir el navegador Chrome.

2. Escenarios aplicables

En el caso real anterior, algunas páginas web se pueden rastrear directamente con solicitudes, y algunas se pueden rastrear directamente analizando Ajax. Los diferentes tipos de sitios web tienen sus métodos de rastreo aplicables.

El selenio también tiene sus escenarios aplicables. Para aquellas páginas web renderizadas con JavaScript, en la mayoría de los casos no podemos usar solicitudes directamente para rastrear el código fuente de la página web, pero en algunos casos podemos usar solicitudes directamente para simular solicitudes Ajax para obtener los datos directamente.
Sin embargo, en algunos casos, algunas interfaces de solicitud de Ajax pueden llevar algunos parámetros encriptados, como token, signo, etc. Si no analizamos cómo se generan estos parámetros, nos es difícil simular y construir estos parámetros. ¿Cómo hacerlo? En este momento, podemos optar directamente por utilizar Selenium para impulsar el procesamiento del navegador y encontrar otra forma de lograr el rastreo WYSIWYG, de modo que no tengamos que preocuparnos por las solicitudes que ocurren detrás de esta página, qué datos obtenemos y cómo procesar la página. La página que vemos es el resultado final de que el navegador nos ayudó a simular la solicitud Ajax y la representación de JavaScript, y Selenium también puede obtener el resultado final, que es equivalente a omitir la etapa de análisis y simulación de solicitudes Ajax para alcanzar el objetivo.

Sin embargo, Selenium ciertamente tiene sus limitaciones. Su eficiencia de rastreo es baja. Algunos rastreos necesitan simular el funcionamiento del navegador, lo cual es relativamente complicado de implementar. Sin embargo, también es un método de rastreo eficaz en algunos escenarios.

3. Rastrear el objetivo

En esta lección, tomaremos como ejemplo un sitio aplicable a Selenium. Su enlace es: https://dynamic2.scrape.cuiqingcai.com/ , que es el mismo sitio de películas que antes. La página se muestra en la figura.

Inserte la descripción de la imagen aquí
A primera vista, la página no es diferente de la anterior, pero una inspección más cercana revela que su interfaz de solicitud Ajax y la URL de cada película contienen parámetros encriptados.

Por ejemplo, hacemos clic en cualquier película y observamos los cambios de URL, como se muestra en la figura.
Inserte la descripción de la imagen aquí
Aquí podemos ver que la URL de la página de detalles es diferente a la anterior. En el caso anterior, el detalle de la URL fue seguido directamente por el id, como 1, 2, 3, etc., pero directamente se ha convertido en un largo La cadena parece ser un contenido codificado en Base64, por lo que aquí no podemos construir directamente la URL de la página de detalles de acuerdo con la ley.

Bien, entonces echemos un vistazo a la solicitud Ajax directamente. Hacemos clic de la página 1 a la página 10 de la página de lista para observar cómo se ve la solicitud Ajax, como se muestra en la figura.

Inserte la descripción de la imagen aquí
Se puede ver que el parámetro de la interfaz aquí tiene un token más que antes, y el token solicitado es diferente cada vez. Este token también se ve como una cadena codificada en Base64. Lo que es más difícil es que esta interfaz todavía es sensible al tiempo. Si copiamos la URL de la interfaz Ajax directamente, será accesible en un corto período de tiempo, pero después de un período de tiempo, será inaccesible y se devolverá directamente un código de estado 401.

¿Qué debemos hacer ahora? Anteriormente, podíamos usar solicitudes directamente para construir solicitudes Ajax, pero ahora la interfaz de solicitud Ajax tiene este token y aún es variable. Ahora no conocemos la lógica de generación del token, por lo que no podemos construir directamente solicitudes Ajax para rastrear Entendido. En este momento, podemos analizar la lógica de generación de tokens y simular solicitudes Ajax, pero este método es relativamente difícil. Entonces, aquí podemos usar directamente Selenium para omitir esta etapa, obtener directamente el código fuente de la página final renderizada en JavaScript y luego extraer los datos.

Entonces, los objetivos que tenemos que lograr en esta lección son:

  • Recorra la página de la lista a través de Selenium para obtener la URL de la página de detalles de cada película.
  • Utilice Selenium para rastrear la página de detalles de cada película de acuerdo con la URL de la página de detalles obtenida en el paso anterior.
  • Extraiga el nombre, la categoría, la partitura, la introducción, la portada y otros contenidos de cada película.

4. Rastrear la página de la lista

En primer lugar, necesitamos hacer el siguiente trabajo de inicialización, el código es el siguiente:

from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import logging
logging.basicConfig(level=logging.INFO,
                   format='%(asctime)s - %(levelname)s: %(message)s')
INDEX_URL = 'https://dynamic2.scrape.cuiqingcai.com/page/{page}'
TIME_OUT = 10
TOTAL_PAGE = 10
browser = webdriver.Chrome()
wait = WebDriverWait(browser, TIME_OUT)

En primer lugar, importamos algunos módulos de Selenium necesarios, incluidos webdriver, WebDriverWait, etc. Los usaremos más adelante para implementar el rastreo de páginas y la configuración de espera de retraso. Luego se definen algunas variables y la configuración del registro, que son similares al contenido de las lecciones anteriores. Luego usamos la clase Chrome para generar un objeto webdriver y asignarlo al navegador. Aquí podemos usar el navegador para llamar a algunas API de Selenium para completar algunas operaciones del navegador, como capturas de pantalla, clics, menús desplegables, etc. Finalmente, declaramos un objeto WebDriverWait, con el que podemos configurar el tiempo máximo de espera para la carga de la página.

Bien, entonces observaremos la página de lista e implementaremos el rastreo de la página de lista. Aquí se puede observar que la URL de la página de la lista todavía tiene un patrón determinado, por ejemplo, la primera página es https://dynamic2.scrape.cuiqingcai.com/page/1 , el número de página es el último número de la URL, por lo que aquí podemos construir directamente cada La URL de una página.

Entonces, ¿cómo juzga si cada página de lista se carga correctamente? Muy sencillo, cuando el contenido que queremos aparece en la página, significa que la carga se ha realizado correctamente. Aquí podemos usar la condición de juicio implícito de Selenium para juzgar. Por ejemplo, el selector CSS del bloque de información de cada película es #index .item, como se muestra en la figura.
Inserte la descripción de la imagen aquí
Entonces, aquí usamos directamente la condición de juicio visibilidad_de_todos_elementos_localizados más el contenido del selector CSS para determinar si la página se ha cargado. Con la configuración de tiempo de espera de WebDriverWait, podemos lograr 10 segundos de monitoreo de carga de la página. Si las condiciones configuradas se cumplen dentro de los 10 segundos, significa que la página se cargó correctamente; de ​​lo contrario, se lanzará una TimeoutException.

El código se implementa de la siguiente manera:

def scrape_page(url, condition, locator):
   logging.info('scraping %s', url)
   try:
       browser.get(url)
       wait.until(condition(locator))
   except TimeoutException:
       logging.error('error occurred while scraping %s', url, exc_info=True)
def scrape_index(page):
   url = INDEX_URL.format(page=page)
   scrape_page(url, condition=EC.visibility_of_all_elements_located,
               locator=(By.CSS_SELECTOR, '#index .item'))

Aquí definimos dos métodos.

El primer método scrape_page sigue siendo un método de rastreo general, puede lograr cualquier rastreo de URL y monitoreo de estado y manejo de excepciones, recibe tres parámetros url, condición, localizador, el parámetro url es la URL de la página que se rastreará ; La condición es la condición de juicio de la carga de la página, puede ser una de las condiciones de juicio de las condiciones_esperadas, como visibilidad_de_todos_elementos_ubicados, visibilidad_de_elemento_ubicado, etc.; Localizador significa localizador, que es una tupla, que se puede obtener configurando condiciones y parámetros de consulta. Múltiples nodos, como (By.CSS_SELECTOR, '# index .item') significa buscar #index .item a través del selector CSS para obtener todos los nodos de información de películas en la página de lista. Además, la detección de TimeoutException se agrega al proceso de rastreo. Si el nodo correspondiente no se carga dentro del tiempo especificado (10 segundos aquí), se lanzará una excepción TimeoutException y se generará el registro de errores.

El segundo método, scrape_index, es el método para rastrear la página de la lista. Recibe una página de parámetros y completa el rastreo de la página llamando al método scrape_page y pasando la condición y los objetos del localizador. Aquí usamos visibilidad_de_todos_elementos_localizados para la condición, lo que significa que todos los nodos se cargan antes de que se considere exitoso.

Tenga en cuenta que no necesitamos devolver ningún resultado al rastrear la página aquí, porque después de que se ejecuta scrape_index, la página está en el estado en el que se carga la página correspondiente. Podemos usar el objeto del navegador para extraer más información.

Bien, ahora podemos cargar la página de la lista. El siguiente paso es, por supuesto, analizar la página de la lista y extraer la URL de la página de detalles. Definimos un método para analizar la página de la lista de la siguiente manera:

from urllib.parse import urljoin
def parse_index():
   elements = browser.find_elements_by_css_selector('#index .item .name')
   for element in elements:
       href = element.get_attribute('href')
       yield urljoin(INDEX_URL, href)

Aquí extraemos directamente los nombres de todas las películas a través del método find_elements_by_css_selector, luego recorremos los resultados, extraemos el href de la página de detalles a través del método get_attribute y los fusionamos en una URL completa usando el método urljoin.

Finalmente, usamos un método principal para conectar los métodos anteriores en serie para lograr lo siguiente:

def main():
   try:
       for page in range(1, TOTAL_PAGE + 1):
           scrape_index(page)
           detail_urls = parse_index()
           logging.info('details urls %s', list(detail_urls))
   finally:
       browser.close()

Aquí hemos recorrido todos los números de página, rastreamos la página de lista de cada página por turno y extraemos la URL de la página de detalles.

Los resultados son los siguientes:

2020-03-29 12:03:09,896 - INFO: scraping https://dynamic2.scrape.cuiqingcai.com/page/1
2020-03-29 12:03:13,724 - INFO: details urls ['https://dynamic2.scrape.cuiqingcai.com/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIx',
...
'https://dynamic2.scrape.cuiqingcai.com/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWI5', 'https://dynamic2.scrape.cuiqingcai.com/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIxMA==']
2020-03-29 12:03:13,724 - INFO: scraping https://dynamic2.scrape.cuiqingcai.com/page/2
...

Debido al gran contenido de salida, parte del contenido se omite aquí.

Al observar los resultados, podemos encontrar que las URL irregulares en la página de detalles fueron extraídas con éxito por nosotros.

5. Rastrear la página de detalles

Bien, ahora que podemos obtener con éxito la URL de la página de detalles, completemos el rastreo de la página de detalles y extraigamos la información correspondiente.

Con la misma lógica, también podemos agregar una condición de juicio a la página de detalles, como juzgar que el nombre de la película está cargado, lo que significa que la página de detalles se cargó correctamente. También se puede llamar al método scrape_page. La implementación del código es la siguiente:

def scrape_detail(url):
   scrape_page(url, condition=EC.visibility_of_element_located,
               locator=(By.TAG_NAME, 'h2'))

Aquí usamos visibilidad_de_elemento_localizado para la condición de juicio, lo que significa que podemos juzgar si aparece un solo elemento. Para el localizador, pasamos (Por.TAG_NAME, 'h2'), que es el nodo h2, que es el nodo correspondiente al nombre de la película. Como se muestra en la figura.
Inserte la descripción de la imagen aquí
Si se ejecuta el método scrape_detail y no hay TimeoutException, la página se carga correctamente, y luego definimos un método para analizar la página de detalles para extraer la información que queremos. La implementación es la siguiente:

def parse_detail():
   url = browser.current_url
   name = browser.find_element_by_tag_name('h2').text
   categories = [element.text for element in browser.find_elements_by_css_selector('.categories button span')]
   cover = browser.find_element_by_css_selector('.cover').get_attribute('src')
   score = browser.find_element_by_class_name('score').text
   drama = browser.find_element_by_css_selector('.drama p').text
   return {
    
    
       'url': url,
       'name': name,
       'categories': categories,
       'cover': cover,
       'score': score,
       'drama': drama
   }

Aquí definimos un método parse_detail para extraer la URL, nombre, categoría, portada, puntuación, introducción, etc. El método de extracción es el siguiente:

  • URL: llame directamente a la propiedad current_url del objeto del navegador para obtener la URL de la página actual.
    Nombre: se puede obtener extrayendo el texto dentro del nodo h2. Aquí, se usa el método find_element_by_tag_name y se pasa h2. Se extrae el nodo con el nombre, y luego se extrae el texto dentro del nodo llamando al atributo text, que es el nombre de la película.
  • Categoría: Para mayor comodidad, podemos extraer categorías a través de selectores de CSS. El selector de CSS correspondiente es .categories button span. Se pueden seleccionar varios nodos de categoría. Aquí podemos extraer varios nodos de categoría correspondientes a los selectores de CSS a través de find_elements_by_css_selector , Y luego recorre el resultado a su vez, llama a su propiedad text para obtener el texto interno del nodo.
  • Portada: También puede usar el selector CSS .cover para obtener directamente el nodo correspondiente a la portada, pero como la URL de la portada corresponde al atributo src, aquí use el método get_attribute y pase src para extraer.
  • Score: El selector de CSS correspondiente a la puntuación es .score, podemos extraerlo de la misma forma que el anterior, pero aquí cambiamos un método llamado find_element_by_class_name, que puede usar el nombre de la clase para extraer el nodo, que puede lograr el mismo efecto. Pero el parámetro que se pasa aquí es el nombre de la puntuación de la clase en lugar de .score. Después de extraer el nodo, podemos llamar a la propiedad text para extraer el texto del nodo.
  • Introducción: también puede utilizar el selector CSS .drama p para obtener directamente el nodo correspondiente a la introducción, y luego llamar al atributo text para extraer el texto.

Finalmente, podemos construir el resultado como un diccionario y devolverlo.
A continuación, agregamos la llamada de estos dos métodos en el método principal, la implementación es la siguiente:

def main():
   try:
       for page in range(1, TOTAL_PAGE + 1):
           scrape_index(page)
           detail_urls = parse_index()
           for detail_url in list(detail_urls):
               logging.info('get detail url %s', detail_url)
               scrape_detail(detail_url)
               detail_data = parse_detail()
               logging.info('detail data %s', detail_data)
   finally:
       browser.close()

De esta forma, luego de rastrear la página de la lista, podemos rastrear la página de detalles a su vez para extraer la información específica de cada película.

2020-03-29 12:24:10,723 - INFO: scraping https://dynamic2.scrape.cuiqingcai.com/page/1
2020-03-29 12:24:16,997 - INFO: get detail url https://dynamic2.scrape.cuiqingcai.com/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIx
2020-03-29 12:24:16,997 - INFO: scraping https://dynamic2.scrape.cuiqingcai.com/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIx
2020-03-29 12:24:19,289 - INFO: detail data {
    
    'url': 'https://dynamic2.scrape.cuiqingcai.com/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIx', 'name': '霸王别姬 - Farewell My Concubine', 'categories': ['剧情', '爱情'], 'cover': 'https://p0.meituan.net/movie/ce4da3e03e655b5b88ed31b5cd7896cf62472.jpg@464w_644h_1e_1c', 'score': '9.5', 'drama': '影片借一出《霸王别姬》的京戏,牵扯出三个人之间一段随时代风云变幻的爱恨情仇。段小楼(张丰毅 饰)与程蝶衣(张国荣 饰)是一对打小一起长大的师兄弟,两人一个演生,一个饰旦,一向配合天衣无缝,尤其一出《霸王别姬》,更是誉满京城,为此,两人约定合演一辈子《霸王别姬》。但两人对戏剧与人生关系的理解有本质不同,段小楼深知戏非人生,程蝶衣则是人戏不分。段小楼在认为该成家立业之时迎娶了名妓菊仙(巩俐 饰),致使程蝶衣认定菊仙是可耻的第三者,使段小楼做了叛徒,自此,三人围绕一出《霸王别姬》生出的爱恨情仇战开始随着时代风云的变迁不断升级,终酿成悲剧。'}
2020-03-29 12:24:19,291 - INFO: get detail url https://dynamic2.scrape.cuiqingcai.com/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIy
2020-03-29 12:24:19,291 - INFO: scraping https://dynamic2.scrape.cuiqingcai.com/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIy
2020-03-29 12:24:21,524 - INFO: detail data {
    
    'url': 'https://dynamic2.scrape.cuiqingcai.com/detail/ZWYzNCN0ZXVxMGJ0dWEjKC01N3cxcTVvNS0takA5OHh5Z2ltbHlmeHMqLSFpLTAtbWIy', 'name': '这个杀手不太冷 - Léon', 'categories': ['剧情', '动作', '犯罪'], 'cover': 'https://p1.meituan.net/movie/6bea9af4524dfbd0b668eaa7e187c3df767253.jpg@464w_644h_1e_1c', 'score': '9.5', 'drama': '里昂(让·雷诺 饰)是名孤独的职业杀手,受人雇佣。一天,邻居家小姑娘马蒂尔德(纳塔丽·波特曼 饰)敲开他的房门,要求在他那里暂避杀身之祸。原来邻居家的主人是警方缉毒组的眼线,只因贪污了一小包毒品而遭恶警(加里·奥德曼 饰)杀害全家的惩罚。马蒂尔德 得到里昂的留救,幸免于难,并留在里昂那里。里昂教小女孩使枪,她教里昂法文,两人关系日趋亲密,相处融洽。 女孩想着去报仇,反倒被抓,里昂及时赶到,将女孩救回。混杂着哀怨情仇的正邪之战渐次升级,更大的冲突在所难免……'}
...

De esta forma, también podemos extraer los datos de la página de detalles.

6. Almacenamiento de datos

Finalmente, agregamos un método de almacenamiento de datos como antes. Para mayor comodidad, guárdelo como un archivo de texto JSON aquí. La implementación es la siguiente:

from os import makedirs
from os.path import exists
RESULTS_DIR = 'results'
exists(RESULTS_DIR) or makedirs(RESULTS_DIR)
def save_data(data):
   name = data.get('name')
   data_path = f'{RESULTS_DIR}/{name}.json'
   json.dump(data, open(data_path, 'w', encoding='utf-8'), ensure_ascii=False, indent=2)

El principio y el método de implementación aquí son exactamente los mismos que los de la clase de combate real de rastreo de Ajax, por lo que no los repetiré aquí.

Finalmente, agregue una llamada a save_data para ver el efecto de ejecución por completo.

7 sin cabeza

Si cree que el navegador emergente es molesto durante el proceso de rastreo, podemos activar el modo sin cabeza de Chrome para que el navegador ya no aparezca durante el proceso de rastreo y la velocidad de rastreo se mejore aún más.

Simplemente realice las siguientes modificaciones:

options = webdriver.ChromeOptions()
options.add_argument('--headless')
browser = webdriver.Chrome(options=options)

Aquí, el parámetro --headless se agrega a través de ChromeOptions, y luego ChromeOptions se puede usar para inicializar Chrome.

Vuelva a ejecutar el código después de la modificación, el navegador Chrome no aparecerá y los resultados del rastreo son exactamente los mismos.

8. Resumen

En esta clase, aprendimos sobre los escenarios aplicables de Selenium a través de un caso, y usamos Selenium en combinación con el caso para lograr el rastreo de páginas, a fin de tener una mejor comprensión del uso de Selenium.

En el futuro, sabremos cuándo podemos usar Selenium y cómo usar Selenium para completar el rastreo de páginas.

Supongo que te gusta

Origin blog.csdn.net/weixin_38819889/article/details/108697172
Recomendado
Clasificación