使用下拉菜单的Python Selenium 脚本

问题描述 投票:0回答:1

我正在尝试一个与未来加拿大健康和安全行业职业抱负相关的有趣项目,这也将帮助我培养 Python 技能。有一个网站提供加拿大职业健康和安全统计数据。

我的目标是使用 Selenium 与下拉菜单交互。有三种:一个代表年份,一个代表数据划分的类别,例如性别、职业等,另一个有两个选项:死亡人数或损失工时索赔 (LTC)。

然后,我需要单击一个“生成”按钮。页面加载,并生成一个表格,您可以选择将表格导出为 .csv 或 .pdf 文件。

另一件事是我想自动下载每年、类别以及死亡人数和长期护理人员的所有可能报告。

我是Python的初学者,过去几天一直在努力,每天花几个小时试图让它工作。

到目前为止,这是我的代码:

# First, let's import the Selenium library and the required modules for this project.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
import time

# Then lets specify the URL of interest and navigate to the webpage.

url = "https://awcbc.org/en/statistics/national-work-injury-disease-and-fatality-statistics-nwisp-year-at-a-glance/"
driver = webdriver.Chrome()
driver.get(url)

time.sleep(7)


# The following helps locate the iframe that contains the drop-down menus needed.

try: 
    iframe = driver.find_element(By.XPATH, "//*[@id='res-inventry-page']/div/div/div/div/p[7]/iframe")
    driver.switch_to.frame(iframe)
except: 
    print("Failed to locate iframe")
else:
    print("iframe successfully switched.")
    
time.sleep(7)
wait = WebDriverWait(driver, 10)  # Wait for a maximum of 10 seconds
    # Define all the drop-down menus within the iframe and try and select one option in each.
ddyear = driver.find_element(By.ID, "DropdownListYear")
Select(ddyear)

years = driver.find_elements(By.XPATH, "//select[@id='DropdownListYear']/option")
years = years[1:]


yr2022 = driver.find_element(By.XPATH, '//*[@id="DropdownListYear"]/option[2]')
Select(yr2022)

# for year in years:
#     print(year.text)
    

category = driver.find_elements(By.ID, "DropdownReportType")
categories = driver.find_elements(By.XPATH, '//*[@id="DropdownReportType"]/option')
categories = categories[1:]

result = driver.find_element(By.ID, "DropdownScope")
results = driver.find_elements(By.XPATH, '//*[@id="DropdownScope"]/option')
results = results[1:]

generate_button = driver.find_element(By.XPATH, '//*[@id="generateReport"]')

export_csv = driver.find_element(By.XPATH, '//*[@id="ExportExcelLB"]')

当我尝试选择我在 2022 年创建的第一个选项时,遇到错误 UnexpectedTagNameException:选择仅适用于元素,不适用于选项。我相信这个社区的技术专业知识可以帮助我解决这个问题。

我需要这方面的帮助,以及有关使用某种类型的循环来选择可用报告的所有可能组合然后自动下载的任何其他提示。如果有一种更简单的方法可以从网页中找到下载链接,将其保存到文本文件中,然后使用 wget,我也愿意这样做。这是我想自己编写脚本的东西,所以我正在寻找正确方向的一点,我想学习如何做到这一点。

提前谢谢大家。我感谢这个社区提供的所有帮助。

python selenium-webdriver web-scraping wget
1个回答
0
投票

一些反馈...

    大多数情况下应避免使用
  1. time.sleep()
    。它会减慢您的脚本速度,并且对于偶尔的等待时间没有真正的帮助。最佳实践是在所有情况下都使用
    WebDriverWait

  2. 熟悉

    expected_conditions
    中的所有不同等待选项。例如,您可以利用
    EC.frame_to_be_available_and_switch_to_it()
    等待并切换到 IFRAME。

  3. 您找到了

    Select
    类,但从未真正使用过它。它使与 SELECT HTML 元素的交互变得更加容易,并且可以在此处使用来简化代码。例如,给出下面的 HTML

    <select class="A" id="DropdownListYear" name="DropdownListYear" size="1">
        <option value="-1">Select one...</option>
        <option value="2022">2022</option>
        <option value="2021">2021</option>
    </select>
    

    您可以使用下面的代码以三种不同的方式选择“2022”。

    year_select = Select(driver.find_element(By.ID, "DropdownListYear"))
    year_select.select_by_index(1) # index starts at 0
    year_select.select_by_value("2022")
    year_select.select_by_visible_text("2022")
    

    哪里

    <option value="2022">2022</option>
                   ^^^^ .select_by_value("2022")
                         ^^^^ .select_by_visible_text("2022")
    
  4. 我建议您谨慎使用

    try-except
    (如果有的话)。在学习时,您需要查看每个异常/错误消息并学习如何读取堆栈跟踪。它将显着增加您对失败原因和失败位置的理解,并加快理解和解决问题的过程。也就是说,它们很有用,但仅使用它们来捕获您计划处理的特定异常。

    例如,而不是

    except:
        print("Failed to locate iframe")
    

    使用

    from selenium.common.exceptions import NoSuchElementException
    
    except NoSuchElementException:
        print("Failed to locate iframe")
    

    这样,如果抛出任何其他异常,您都会看到它。当您仅使用

    except:
    时,您正在吃所有异常类型,这可能会导致您 假设 您得到
    NoSuchElementException
    ,而实际上它是其他可能导致混乱和浪费时间的东西。

考虑到所有这些建议,我将代码重构为以下内容。

注意:下载的每个文件都具有相同的通用名称:report.xls。下载完成后,您可能想找到该文件,并根据当前的下拉选项对其进行重命名。我在其中留下了

label
,其中包含每个下拉选项,如果您愿意,您可以将其重新用作文件名。

# First, let's import the Selenium library and the required modules for this project
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select

# Then lets specify the URL of interest and navigate to the webpage
url = "https://awcbc.org/en/statistics/national-work-injury-disease-and-fatality-statistics-nwisp-year-at-a-glance/"
driver = webdriver.Chrome()
driver.maximize_window()
driver.get(url)

wait = WebDriverWait(driver, 10)  # Wait for a maximum of 10 seconds

# The following helps locate the iframe that contains the drop-down menus needed
wait.until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, "iframe.iframe-class")))

# Define the Year dropdown and loop
year_select = Select(driver.find_element(By.ID, "DropdownListYear"))

# for year in range(1, 2): # for debugging
for year in range(1, len(year_select.options)):
    year_select.select_by_index(year)
    year_label = year_select.first_selected_option.text

    # Define the NWISP Category dropdown
    category_select = Select(driver.find_element(By.ID, "DropdownReportType"))
    for category in range(1, len(category_select.options)):
    # for category in range(1, 2): # for debugging
        category_select.select_by_index(category)
        category_label = category_select.first_selected_option.text

        # Define the Data Type dropdown
        type_select = Select(driver.find_element(By.ID, "DropdownScope"))
        for type in range(1, len(type_select.options)):
            type_select.select_by_index(type)
            type_label = type_select.first_selected_option.text

            # print a combined label of dropdown selections
            label = f"{year_label} : {category_label} : {type_label}"
            print(label)

            driver.find_element(By.ID, 'generateReport').click()

            # switch into the Export IFRAME
            wait.until(EC.frame_to_be_available_and_switch_to_it((By.ID, "iframe")))
            wait.until(EC.element_to_be_clickable((By.ID, "ExportExcelLB"))).click()

            # switch back to default and then into the first IFRAME
            driver.switch_to.default_content()
            wait.until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, "iframe.iframe-class")))

这可能无法实现您想要的所有功能,但它应该是一个可供您构建和学习的框架。

© www.soinside.com 2019 - 2024. All rights reserved.