How to execute all javascript content on webpage w

2019-07-22 13:19发布

问题:

I've been trying to make a Python script to login into a certain website, navigate through the menu, fill out a form and save the file it generates to a folder.

I've been using Selenium trying to make the website fully load so i can find the elements for the login, but i'm being unsucessful, maybe because the website does a lot of JavaScript content before it fully loads, but i can't make it fully load and show me the data i want.

I tried Robobrowser, Selenium, Requests and BeautifulSoup to get it done.

import requests
from bs4 import BeautifulSoup
from selenium import webdriver

url = "https://directa.natal.rn.gov.br/"

driver = webdriver.Chrome(executable_path="C:\\webdrivers\\chromedriver.exe")
driver.get(url)

html = driver.execute_script("return document.documentElement.outerHTML")
sel_soup = BeautifulSoup(html, 'html.parser')

senha = driver.find_element_by_xpath('//*[@id="senha"]')
senha.send_keys("123")

I expected to have filled the password (senha) field with "123" but i can't even find the element.

回答1:

To send the character sequence 123 to the password (senha) field, as the the desired elements are within a <frame> so you have to:

  • Induce WebDriverWait for the desired frame to be available and switch to it.
  • Induce WebDriverWait for the desired element to be clickable.
  • You can use the following solution:

    • Code Block:

      from selenium import webdriver
      from selenium.webdriver.common.by import By
      from selenium.webdriver.support.ui import WebDriverWait
      from selenium.webdriver.support import expected_conditions as EC
      
      options = webdriver.ChromeOptions()
      options.add_argument("start-maximized")
      options.add_argument('disable-infobars')
      options.add_argument("--disable-extensions")
      driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:\WebDrivers\chromedriver.exe')
      driver.get("https://directa.natal.rn.gov.br/")
      WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"frame[name='mainsystem'][src^='main']")))
      WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input.input[name='usuario']"))).send_keys("Tads")
      driver.find_element_by_css_selector("input.input[name='senha']").send_keys("123")
      
  • Browser Snapshot:

Here you can find a relevant discussion on Ways to deal with #document under iframe



回答2:

It seems like what's needed here is a little bit of a scroll, wait and switch, incase the login fields just aren't ready for input :) The below should work, whereby we actually scroll to the element, having switch to the iframe, before we interact with the rest of the login form. You're able to adjust the delay from 5 seconds to anything of your preference.

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException

""" Variables """
url = "https://directa.natal.rn.gov.br/"
delay = 5 # seconds

""" Initiate driver """
driver = webdriver.Chrome(executable_path="C:\\webdrivers\\chromedriver.exe")

""" Go to url """
driver.get(url)

""" Iframe switch """
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"frame[name='mainsystem'][src^='main']")))


""" Attempt to get all our elements """
try:
    """ Username """
    usuario = WebDriverWait(driver, delay).until(EC.presence_of_element_located((By.ID, 'usuario')))
    """ Password """
    senha = WebDriverWait(driver, delay).until(EC.presence_of_element_located((By.ID, 'senha')))

    print("All elements located!")

except TimeoutException:
    print("Loading took too much time!")
    exit(0)

"""Scroll to our element """
driver.execute_script("arguments[0].scrollIntoView();", usuario)

""" Input data into our fields """
usuario.send_keys("username")
senha.send_keys("password")

""" Locate our login element """
login = WebDriverWait(driver, delay).until(EC.presence_of_element_located((By.ID, 'acessar')))

""" Click Login """
login.click()