Вложенный цикл for-while останавливает итерацию после первого запуска - PullRequest
2 голосов
/ 06 июля 2019

Платформа:
Версия Python: 3.7.3
Версия Selenium: 3.141.0
ОПЕРАЦИОННЫЕ СИСТЕМЫ: Win7

Выпуск:
У меня есть список URL-адресов в виде текстового файла, каждый URL-адрес в отдельной строке. URL ссылки для скачивания. Я хочу перебрать все URL-адреса и загрузить файлы, связанные с каждым URL-адресом, в определенную папку.

Код, который я пробовал, представляет собой вложенный цикл for-while. Первая итерация проходит без проблем, но вторая итерация застревает в одном из цикла while.

Очевидно, что есть лучший способ сделать то, что я пытаюсь сделать. Я только начинающий в Python и изучаю язык как можно лучше.

My Url List:

https://mega.nz/#!bOgBWKiB!AWs3JSksW0mpZ8Eob0-Qpr5ZAG0N1zhoFBFVstNJfXs
https://mega.nz/#!qPxGAAYJ!BX-hv7jgE4qvBs_uhHPVpsLRm1Yl4JkZ17nI1-U6hvk
https://mega.nz/#!GPoiHaaT!TAKT4sOhIiMUSFFSmlvPOidMcscXzHH_8HgK27LyTRM

Код, который я пробовал:

import os
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
from pathlib import Path
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
binary = FirefoxBinary('C:\\Program Files\\Mozilla Firefox\\firefox.exe')
fp = webdriver.FirefoxProfile()
fp.set_preference("browser.download.folderList", 2)
fp.set_preference("browser.download.manager.showWhenStarting", False)
fp.set_preference("browser.download.dir", "H:\\downloads")
fp.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/zip")
driver = webdriver.Firefox(firefox_binary=binary, firefox_profile=fp, executable_path=r'C:\\Program Files\\Python\\Python37\\Lib\\site-packages\\selenium\\webdriver\\firefox\\geckodriver.exe')
driver.set_window_size(1600, 1050)
with open("H:\\downloads\\my_url_list.txt", "r") as f:
    for url in f:
        driver.get(url.strip())
        sleep(5)
        while True:
            # checks whether the element is available on the page, used 'while' instead of 'wait' as I couuldn't figure out the wait time.
            try:
                content = driver.find_element_by_css_selector('div.buttons-block:nth-child(1) > div:nth-child(2)')
                break
            except NoSuchElementException:
                continue
        # used 'execute_script' instead of 'click()' due to "scroll into view error"
        driver.execute_script("arguments[0].click();", content)
        sleep(5)
        while True:
            # checks whether 'filename' element is available on the page, the page shows multiple elements depending on interaction.
            if driver.find_element_by_xpath("/html/body/div[6]/div[3]/div/div[1]/div[4]/div[1]/div/span[1]"):
                filename = driver.find_element_by_xpath("/html/body/div[6]/div[3]/div/div[1]/div[4]/div[1]/div/span[1]").text
                break
            elif driver.find_element_by_xpath("/html/body/div[6]/div[3]/div/div[1]/div[5]/div/div/div[1]/div[1]/div[2]/div[3]/div[1]/span[1]"):
                filename = driver.find_element_by_xpath("/html/body/div[6]/div[3]/div/div[1]/div[5]/div/div/div[1]/div[1]/div[2]/div[3]/div[1]/span[1]").text
                break
            else:
                sleep(5)
        print(filename)
        dirname = 'H:\\downloads'
        suffix = '.zip'
        file_path = Path(dirname, filename).with_suffix(suffix)
        while True:
            # checks whether the file has downloaded into the folder.
            if os.path.isfile(file_path):
                break

Что происходит:

Первая итерация проходит - файл (связанный с URL) загружается в папку H:\\downloads и печатается filename.

В случае второй итерации файл загружается в папку, но имя файла не печатается, второй цикл while входит в неопределенный цикл.

Нет для итерации после второго запуска, поскольку filename не может быть получено во второй итерации, цикл переходит в неопределенный режим.

Второй цикл while в приведенном выше коде:

while True:  
            # checks whether 'filename' element is available on the page, the page shows multiple elements depending on interaction.  
            if driver.find_element_by_xpath("/html/body/div[6]/div[3]/div/div[1]/div[4]/div[1]/div/span[1]"):  
                filename = driver.find_element_by_xpath("/html/body/div[6]/div[3]/div/div[1]/div[4]/div[1]/div/span[1]").text  
                break  
            elif driver.find_element_by_xpath("/html/body/div[6]/div[3]/div/div[1]/div[5]/div/div/div[1]/div[1]/div[2]/div[3]/div[1]/span[1]"):  
                filename = driver.find_element_by_xpath("/html/body/div[6]/div[3]/div/div[1]/div[5]/div/div/div[1]/div[1]/div[2]/div[3]/div[1]/span[1]").text  
                break  
            else:  
                sleep(5) 

Прикрепленные изображения для имени файла опция xpath (причина, по которой два разных xpath были выбраны для имени файла)

  1. Параметр while loop first

enter image description here

  1. второй вариант цикла loop

enter image description here

1 Ответ

1 голос
/ 07 июля 2019

То, что вы ищете, это явное ожидание, я советую вам посетить эту страницу из документации Selenium-python.Я цитирую со страницы:

Явное ожидание - это код, который вы определили для ожидания определенного условия, прежде чем продолжить работу в коде.В крайнем случае это time.sleep (), который устанавливает условие для точного периода времени ожидания.Есть несколько удобных методов, которые помогут вам написать код, который будет ждать столько времени, сколько потребуется.WebDriverWait в сочетании с ExpectedCondition является одним из способов достижения этой цели.

Если вы хотите узнать больше о ExpectedCondition, вы можете посетить эту ссылку документации

Я предлагаю этот код для вашего случая, используя лямбда-функцию, потому что вы ожидаете хотя бы один элемент.

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

driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delays_loading")
try:
    xpath1="/html/body/div[6]/div[3]/div/div[1]/div[4]/div[1]/div/span[1]"
    xpath2="/html/body/div[6]/div[3]/div/div[1]/div[5]/div/div/div[1]/div[1]/div[2]/div[3]/div[1]/span[1]"
    timeLimit = 15 #seconds, you really need to set a time out.
    element = WebDriverWait(driver, timeLimit).until( lambda driver: driver.find_elements(By.xpath, xpath1) or driver.find_elements(By.xpath, xpath2) )
finally:
    pass

Это ожидает до 15 секунд, прежде чем выдается исключение TimeoutException, если он не найдет один из элементов, которые выв ожидании xpath.По умолчанию WebDriverWait вызывает ExpectedCondition каждые 500 миллисекунд, пока он не завершится успешно, поэтому вам не нужно обрабатывать логику и циклы, как вы пытаетесь это сделать.

Для обработки исключения TimeoutException вы можете, например, обновить страницу.

...