Python: No se puede descargar con selenium en la página web

Mi propósito es descargar un archivo zip desde https://www.shareinvestor.com/prices/price_download_zip_file.zip?type=history_all&market=bursa Es un enlace en esta página web https://www.shareinvestor.com/prices/price_download .html # /? type = price_download_all_stocks_bursa . Luego guárdelo en este directorio "/home/vinvin/shKLSE/ (Estoy usando pythonaywhere). Luego descomprímalo y el extracto del archivo csv en el directorio.

El código se ejecuta hasta el final sin error pero no se descarga. El archivo zip se descarga automáticamente cuando se hace clic en https://www.shareinvestor.com/prices/price_download_zip_file.zip?type=history_all&market=bursa de forma manual.

Se utiliza mi código con un nombre de usuario y contraseña de trabajo. El nombre de usuario y la contraseña reales se utilizan para que sea más fácil entender el problema.

  #!/usr/bin/python print "hello from python 2" import urllib2 from selenium import webdriver from selenium.webdriver.common.keys import Keys import time from pyvirtualdisplay import Display import requests, zipfile, os display = Display(visible=0, size=(800, 600)) display.start() profile = webdriver.FirefoxProfile() profile.set_preference('browser.download.folderList', 2) profile.set_preference('browser.download.manager.showWhenStarting', False) profile.set_preference('browser.download.dir', "/home/vinvin/shKLSE/") profile.set_preference('browser.helperApps.neverAsk.saveToDisk', '/zip') for retry in range(5): try: browser = webdriver.Firefox(profile) print "firefox" break except: time.sleep(3) time.sleep(1) browser.get("https://www.shareinvestor.com/my") time.sleep(10) login_main = browser.find_element_by_xpath("//*[@href='/user/login.html']").click() print browser.current_url username = browser.find_element_by_id("sic_login_header_username") password = browser.find_element_by_id("sic_login_header_password") print "find id done" username.send_keys("bkcollection") password.send_keys("123456") print "log in done" login_attempt = browser.find_element_by_xpath("//*[@type='submit']") login_attempt.submit() browser.get("https://www.shareinvestor.com/prices/price_download.html#/?type=price_download_all_stocks_bursa") print browser.current_url time.sleep(20) dl = browser.find_element_by_xpath("//*[@href='/prices/price_download_zip_file.zip?type=history_all&market=bursa']").click() time.sleep(30) browser.close() browser.quit() display.stop() zip_ref = zipfile.ZipFile(/home/vinvin/sh/KLSE, 'r') zip_ref.extractall(/home/vinvin/sh/KLSE) zip_ref.close() os.remove(zip_ref) 

Fragmento de HTML:

 
  • All Historical Data About 220 MB
  • Tenga en cuenta que & amp se muestra cuando copio el fragmento. Estaba oculto de la fuente de vista, así que supongo que está escrito en JavaScript.

    Observación que encontré

    1. El directorio home/vinvin/shKLSE no se creó aunque home/vinvin/shKLSE el código sin error

    2. Intento descargar un archivo zip mucho más pequeño que se puede completar en un segundo, pero aún así no lo descargo después de 30 segundos. dl = browser.find_element_by_xpath("//*[@href='/prices/price_download_zip_file.zip?type=history_daily&date=20170519&market=bursa']").click()

    introduzca la descripción de la imagen aquí

    Related of "Python: No se puede descargar con selenium en la página web"

    Reescribí su guión, con comentarios que explican por qué hice los cambios que hice. Creo que su problema principal podría haber sido un mal tipo de letra, sin embargo, su secuencia de comandos tenía un registro de problemas sistémicos que lo habrían hecho poco confiable en el mejor de los casos. Esta reescritura utiliza esperas explícitas, lo que elimina completamente la necesidad de usar time.sleep() , lo que permite que se ejecute lo más rápido posible, al tiempo que elimina los errores que surgen de la congestión de la red.

    Deberá hacer lo siguiente para asegurarse de que todos los módulos estén instalados:

    pip install requests explicit selenium retry pyvirtualdisplay

    La secuencia de comandos:

     #!/usr/bin/python from __future__ import print_function # Makes your code portable import os import glob import zipfile from contextlib import contextmanager import requests from retry import retry from explicit import waiter, XPATH, ID from selenium import webdriver from pyvirtualdisplay import Display from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.wait import WebDriverWait DOWNLOAD_DIR = "/tmp/shKLSE/" def build_profile(): profile = webdriver.FirefoxProfile() profile.set_preference('browser.download.folderList', 2) profile.set_preference('browser.download.manager.showWhenStarting', False) profile.set_preference('browser.download.dir', DOWNLOAD_DIR) # I think your `/zip` mime type was incorrect. This works for me profile.set_preference('browser.helperApps.neverAsk.saveToDisk', 'application/vnd.ms-excel,application/zip') return profile # Retry is an elegant way to retry the browser creation # Though you should narrow the scope to whatever the actual exception is you are # retrying on @retry(Exception, tries=5, delay=3) @contextmanager # This turns get_browser into a context manager def get_browser(): # Use a context manager with Display, so it will be closed even if an # exception is thrown profile = build_profile() with Display(visible=0, size=(800, 600)): browser = webdriver.Firefox(profile) print("firefox") try: yield browser finally: # Let a try/finally block manage closing the browser, even if an # exception is called browser.quit() def main(): print("hello from python 2") with get_browser() as browser: browser.get("https://www.shareinvestor.com/my") # Click the login button # waiter is a helper function that makes it easy to use explicit waits # with it you dont need to use time.sleep() calls at all login_xpath = '//*/div[@class="sic_logIn-bg"]/a' waiter.find_element(browser, login_xpath, XPATH).click() print(browser.current_url) # Log in username = "bkcollection" username_id = "sic_login_header_username" password = "123456" password_id = "sic_login_header_password" waiter.find_write(browser, username_id, username, by=ID) waiter.find_write(browser, password_id, password, by=ID, send_enter=True) # Wait for login process to finish by locating an element only found # after logging in, like the Logged In Nav nav_id = 'sic_loggedInNav' waiter.find_element(browser, nav_id, ID) print("log in done") # Load the target page target_url = ("https://www.shareinvestor.com/prices/price_download.html#/?" "type=price_download_all_stocks_bursa") browser.get(target_url) print(browser.current_url) # CLick download button all_data_xpath = ("//*[@href='/prices/price_download_zip_file.zip?" "type=history_all&market=bursa']") waiter.find_element(browser, all_data_xpath, XPATH).click() # This is a bit challenging: You need to wait until the download is complete # This file is 220 MB, it takes a while to complete. This method waits until # there is at least one file in the dir, then waits until there are no # filenames that end in `.part` # Note that is is problematic if there is already a file in the target dir. I # suggest looking into using the tempdir module to create a unique, temporary # directory for downloading every time you run your script print("Waiting for download to complete") at_least_1 = lambda x: len(x("{0}/*.zip*".format(DOWNLOAD_DIR))) > 0 WebDriverWait(glob.glob, 300).until(at_least_1) no_parts = lambda x: len(x("{0}/*.part".format(DOWNLOAD_DIR))) == 0 WebDriverWait(glob.glob, 300).until(no_parts) print("Download Done") # Now do whatever it is you need to do with the zip file # zip_ref = zipfile.ZipFile(DOWNLOAD_DIR, 'r') # zip_ref.extractall(DOWNLOAD_DIR) # zip_ref.close() # os.remove(zip_ref) print("Done!") if __name__ == "__main__": main() 

    Revelación completa: mantengo el módulo explícito. Está diseñado para hacer que el uso explícito de las esperas sea mucho más fácil, para situaciones exactamente como esta, donde los sitios web cargan lentamente en contenido dynamic basado en las interacciones del usuario. Puede reemplazar todas las llamadas de waiter.XXX anteriores con esperas explícitas directas.

    No veo ningún inconveniente importante en su bloque de código como tal. Pero aquí hay algunas recomendaciones a través de esta Solución y la ejecución de esta secuencia de comandos de prueba automatizada:

    1. Este código funciona perfecto en las horas fuera del mercado. Durante las Horas del Mercado, hay muchas Ajax Calls de JavaScript y Ajax Calls en juego y su manejo está fuera del scope de esta Pregunta.
    2. Puede considerar buscar primero el directorio de descarga previsto y, si no está disponible, cree uno nuevo. El bloque de código para esta funcionalidad está en el estilo de Windows y funciona perfectamente en la plataforma de Windows.
    3. Una vez que haga clic en “Iniciar sesión”, induzca un poco a wait a que el DOM de HTML se procese correctamente.
    4. Cuando quiera ver el proceso de descarga, debe configurar ciertas preferencias más en el FirefoxProfile como se menciona en mi código a continuación.
    5. Siempre considere maximizar la ventana del navegador a través de browser.maximize_window()
    6. Cuando comience a descargar, debe esperar un tiempo suficiente para descargar el archivo por completo.
    7. Si está utilizando browser.quit() al final, no necesita usar browser.close()
    8. Puede considerar reemplazar todo el time.sleep() con ImplicitlyWait o ExplicitWait o FluentWait .
    9. Aquí está su propio bloque de código con algunos ajustes simples en él:

       #!/usr/bin/python print "hello from python 2" import urllib2 from selenium import webdriver from selenium.webdriver.common.keys import Keys import time from pyvirtualdisplay import Display import requests, zipfile, os display = Display(visible=0, size=(800, 600)) display.start() newpath = 'C:\\home\\vivvin\\shKLSE' if not os.path.exists(newpath): os.makedirs(newpath) profile = webdriver.FirefoxProfile() profile.set_preference("browser.download.dir",newpath); profile.set_preference("browser.download.folderList",2); profile.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/zip"); profile.set_preference("browser.download.manager.showWhenStarting",False); profile.set_preference("browser.helperApps.neverAsk.openFile","application/zip"); profile.set_preference("browser.helperApps.alwaysAsk.force", False); profile.set_preference("browser.download.manager.useWindow", False); profile.set_preference("browser.download.manager.focusWhenStarting", False); profile.set_preference("browser.helperApps.neverAsk.openFile", ""); profile.set_preference("browser.download.manager.alertOnEXEOpen", False); profile.set_preference("browser.download.manager.showAlertOnComplete", False); profile.set_preference("browser.download.manager.closeWhenDone", True); profile.set_preference("pdfjs.disabled", True); for retry in range(5): try: browser = webdriver.Firefox(profile) print "firefox" break except: time.sleep(3) time.sleep(1) browser.maximize_window() browser.get("https://www.shareinvestor.com/my") time.sleep(10) login_main = browser.find_element_by_xpath("//*[@href='/user/login.html']").click() time.sleep(10) print browser.current_url username = browser.find_element_by_id("sic_login_header_username") password = browser.find_element_by_id("sic_login_header_password") print "find id done" username.send_keys("bkcollection") password.send_keys("123456") print "log in done" login_attempt = browser.find_element_by_xpath("//*[@type='submit']") login_attempt.submit() browser.get("https://www.shareinvestor.com/prices/price_download.html#/?type=price_download_all_stocks_bursa") print browser.current_url time.sleep(20) dl = browser.find_element_by_xpath("//*[@href='/prices/price_download_zip_file.zip?type=history_all&market=bursa']").click() time.sleep(900) browser.close() browser.quit() display.stop() zip_ref = zipfile.ZipFile(/home/vinvin/sh/KLSE, 'r') zip_ref.extractall(/home/vinvin/sh/KLSE) zip_ref.close() os.remove(zip_ref) 

    Déjame saber si esto responde a tu pregunta.

    Sácalo al margen del selenium. Cambie la configuración de preferencias para que cuando haga clic en el enlace (Primero verifique si el enlace es válido) le muestre una ventana emergente que le pide guardar, ahora use sikuli http://www.sikuli.org/ para hacer clic en la ventana emergente. Los tipos de mimo no siempre funcionan, y no hay una respuesta en blanco y negro por qué no funciona.

    El motivo se debe a que la página web se está cargando lentamente. Agregué una espera de 20 segundos después de abrir el enlace de la página web.

     login_attempt.submit() browser.get("https://www.shareinvestor.com/prices/price_download.html#/?type=price_download_all_stocks_bursa") print browser.current_url time.sleep(20) dl = browser.find_element_by_xpath("//*[@href='/prices/price_download_zip_file.zip?type=history_all&market=bursa']").click() 

    No devuelve ningún error.

    Adicional, /zip es incorrecto tipo MIME. Cambie a profile.set_preference('browser.helperApps.neverAsk.saveToDisk', 'application/zip')

    La corrección final:

      #!/usr/bin/python print "hello from python 2" import urllib2 from selenium import webdriver from selenium.webdriver.common.keys import Keys import time from pyvirtualdisplay import Display import requests, zipfile, os display = Display(visible=0, size=(800, 600)) display.start() profile = webdriver.FirefoxProfile() profile.set_preference('browser.download.folderList', 2) profile.set_preference('browser.download.manager.showWhenStarting', False) profile.set_preference('browser.download.dir', "/home/vinvin/shKLSE/") # application/zip not /zip profile.set_preference('browser.helperApps.neverAsk.saveToDisk', 'application/zip') for retry in range(5): try: browser = webdriver.Firefox(profile) print "firefox" break except: time.sleep(3) time.sleep(1) browser.get("https://www.shareinvestor.com/my") time.sleep(10) login_main = browser.find_element_by_xpath("//*[@href='/user/login.html']").click() print browser.current_url username = browser.find_element_by_id("sic_login_header_username") password = browser.find_element_by_id("sic_login_header_password") print "find id done" username.send_keys("bkcollection") password.send_keys("123456") print "log in done" login_attempt = browser.find_element_by_xpath("//*[@type='submit']") login_attempt.submit() browser.get("https://www.shareinvestor.com/prices/price_download.html#/?type=price_download_all_stocks_bursa") print browser.current_url time.sleep(20) dl = browser.find_element_by_xpath("//*[@href='/prices/price_download_zip_file.zip?type=history_all&market=bursa']").click() time.sleep(30) browser.close() browser.quit() display.stop() zip_ref = zipfile.ZipFile('/home/vinvin/shKLSE/file.zip', 'r') zip_ref.extractall('/home/vinvin/shKLSE') zip_ref.close() # remove with correct path os.remove('/home/vinvin/shKLSE/file.zip') 

    No he probado en el sitio que mencionaste, sin embargo, el siguiente código funciona perfectamente y descarga el ZIP. Si no puede descargar el archivo zip, el tipo Mime podría ser diferente. puede usar el navegador Chrome y la inspección de red para verificar el tipo de mime del archivo que está intentando descargar.

    introduzca la descripción de la imagen aquí

     profile = webdriver.FirefoxProfile() profile.set_preference('browser.download.folderList', 2) profile.set_preference('browser.download.manager.showWhenStarting', False) profile.set_preference('browser.download.dir', "/home/vinvin/shKLSE/") profile.set_preference('browser.helperApps.neverAsk.saveToDisk', 'application/zip') browser = webdriver.Firefox(profile) browser.get("http://www.colorado.edu/conflict/peace/download/peace.zip")