Necesito interactuar con una aplicación en línea escrita por un desarrollador externo, parte de la cual está escrita en React. Para interactuar con el sitio estoy manejando Firefox a través de Selenium y Python. Puedo usar los selectores de CSS tradicionales para interactuar con la mayor parte del sitio, pero las partes escritas en React tienen nombres de clase generados automáticamente al azar que cambian cada vez que los desarrolladores reconstruyen su aplicación. No se encuentran ID en ningún elemento DOM, excepto en el nodo raíz.
¿Cómo puedo obtener un selector CSS único para un elemento DOM, dado un componente React específico en el DOM virtual?
Por ejemplo, al usar React Developer Tools , veo este árbol:
Context.Provider ├─ Context.Provider │ └─ gs ├─ Context.Provider │ └─ styled.div │ └─ styled.button └─Iv ¿Cómo puedo obtener un Selector de CSS único para el elemento DOM que representa el componente React de Context.Provider > Context.Provider > styled.div > styled.button ?
He visto la biblioteca React Element Selector Query NodeJS, pero necesito algo que pueda ejecutarse en Python o que pueda interpretarse desde Python y Selenium.
Aquí hay un código de ejemplo de la aplicación a la que me dirijo:
<div id="root"> <div class="sc-hTtwUo kyYkJm"> <div class="sc-jqUVSM bZjAcv"> <button class="sc-jSMfEi kXusAw">Foo</button> <button class="sc-eCYdqJ ddMHci">Bar</button> </div> <div class="sc-kgUAyh bqLSQt"> <div class="sc-kgflAQ kGhjap"> <div class="sc-kDDrLX civFbY"> ... Lots more ... </div> </div> </div> </div> </div>Aparte del texto del elemento del botón, ese es el HTML de producción real. Tenga en cuenta que esto no es una ofuscación deliberada, sino que esto no es poco común para las aplicaciones React.
Puede verificar la identificación, si se asignan identificaciones a cada etiqueta, se puede acceder muy fácilmente.
por ejemplo
<div class="randon-class" id="renderingID"> This is some div rendering some content <div> Puede acceder al div por #renderingID esto le dará las propiedades requeridas.
Por lo general, hay un patrón cuando se transforma un nombre de clase, como un guión bajo. Entonces puede dividir usando eso y verificar el nombre de clase dado. Por ejemplo, buscamos .content en .body . Entonces, el elemento tendrá className como body_content_<hash> . Entonces, podemos dividir usando y verificar si tiene content
Nota: este enfoque se basa en la manipulación de cadenas. Entonces, si el nombre de la clase tiene el mismo delimitador, fallará.
document .getElementById('btnSearch') .addEventListener('click', () => { const searchClass = document.getElementById('txtSearchId').value const elements = searchElements(searchClass) highlightElement(searchClass, elements) }) function searchElements(className) { return document.querySelectorAll(`[class*="${className}"]`) } function highlightElement(className, elements) { document .querySelectorAll('.border') .forEach((element) => { element.classList.remove('border') }) Array.from(elements).filter((element) => { const classes = element.className.split(/[ _]/); const matched = classes.includes(className); if (matched) { element.classList.add('border') } return matched }) } .border { border: 1px dashed gray; } div { margin: 5px; } <div> <input type="text" id="txtSearchId" /> <button id="btnSearch">Search and Highlight </button> </div> <div class='body_1nu21'> <div class='body_content_2nasiy'> <div class='body_card_21dfl'>test</div> <div class='body_card-test_2345a'>test</div> <div class='body_card-blue_9hysh8'>test</div> <div class='body_card_7hdsg'>test</div> </div> </div>Probablemente tengas que ir por estructura/texto interior en este caso. Por ejemplo:
#root > div > div > button => Foo #root > div > div > button + button => Bar