【Python】Python3.6处理数据实例:数据处理前置条件-数据导出脚本模块分析

数据导出脚本模块分析


一、 脚本功能

  这个脚本在特定的网页环境下实现数据导出的自动化操作,具有一定的实用性和灵活性。但是,目前存在一定的问题,由于对网页结构的强依赖,代码的可维护性和适应性受到一定限制。在实际使用中,需要密切关注网页的变化,如果页面架构有变动,需要及时调整代码以确保脚本的正常运行。同时,可以考虑进一步优化随机等待时间和操作策略,提高脚本的稳定性和效率。

二、功能概述

功能概述
这个 Python 脚本实现了一个自动执行数据导出的工具,主要用于从特定网页中根据指定日期范围和品类选择进行数据导出操作,并记录导出过程。

  1. 登录指定网页:根据给定的链接,登录某个特定的网页,由于部分网站存在只能二维码登录的情况,先登录不用二维码的网页,再打开目标网页进行跳转。
  2. 品类、日期等前置选项选择:根据给定的品类、指定开始结束日期进行前置条件设置。
  3. 查询导出:定位查询按钮、导出按钮,注意随机点击次数避免网站检测。
  4. 生成并填写文件名:定义generate_filenamefill_filename函数用于生成填充文件名,可以自行设置映射。
  5. 确认导出并关闭新跳出来的页面:自动点击确认导出按钮,并把blank弹出的新网页关闭。
  6. 日志记录:记录处理过程中的重要信息和错误信息。
  7. 状态管理:记录并管理最后处理过的文件的时间戳,以确保只导出新的或被删除了的文件。

三、实现模块

1. selenium 相关库
  • webdriver: 提供了WebDriver接口,用于控制浏览器。
  • chrome.options.Options: 用于设置Chrome浏览器的启动选项。
  • common.by.By: 提供了查找元素的方法,如ID、XPath等。
  • webdriver.support.ui.WebDriverWait: 用于等待页面加载完成。
  • webdriver.support.expected_conditions: 提供了多种条件判断方法,用于判断页面元素的状态。
  • common.exceptions.TimeoutException: 当页面元素加载超时时抛出的异常。
  • common.action_chains.ActionChains: 用于模拟鼠标操作。
2. datetime
  • datetime: 用于处理日期和时间。
  • timedelta: 用于表示两个日期或时间之间的差值。
3. timerandom
  • time: 提供了时间相关的函数,如sleep()用于暂停程序执行。
  • random: 用于生成随机数。
4. os
  • os: 提供了与操作系统交互的功能,如获取文件路径、创建目录等。
5. logging
  • logging: 用于记录程序运行的日志,便于调试和维护。
6. json
  • json: 用于处理JSON格式的数据,常用于配置文件或数据交换。
7. openpyxl
  • openpyxl: 用于读写Excel文件,适用于处理表格数据。
8. multiprocessing
  • multiprocessing: 用于实现多进程并发处理,提高程序效率。

四、函数模块分析

1.日期相关函数
(1)is_leap_year(year)
  • 作用:判断给定的年份是否为闰年。
  • 优点:简单直接的闰年判断逻辑,使用了经典的闰年判断条件。
  • 缺点:功能较为单一,仅用于辅助确定月份的天数。
(2)days_in_month(year, month)
  • 作用:获取给定年份和月份的实际天数。
  • 优点:考虑了不同月份和闰年的情况,能够准确返回指定月份的天数。
  • 缺点:与is_leap_year函数耦合度较高,如果闰年判断逻辑发生变化,需要同时修改这两个函数。
(3)month_mapping字典
  • 作用:定义了一个映射表,用于将英文月份转换为中文月份。
  • 优点:方便在选择日期时进行中英文月份的转换,提高了代码的可读性和可维护性。
  • 缺点:如果网页中的月份显示格式发生变化,可能需要更新这个映射表。
(4)get_formatted_time()
  • 作用:返回当前时间的格式化字符串。
  • 优点:提供了统一的时间格式化方法,方便记录操作时间和日志输出。
  • 缺点:格式化的方式较为固定,如果需要不同的时间格式,需要修改函数。
2.登录与导航模块
login_and_navigate(login_url, target_url, username, password)
  • 作用:实现了登录到指定网页并导航到目标页面的功能,还包括选择日数据的操作。
  • 优点
    使用显式等待确保页面元素加载,提高了程序的稳定性。
    清晰的步骤,易于理解和维护。
  • 缺点
    如果网页的登录流程或页面结构发生变化,需要相应地修改 CSS 选择器和等待条件。
    只支持用户名登录方式,如果有其他登录方式需求,需要扩展代码。
3.品类选择模块
select_category(driver, category)
  • 作用:在网页上选择指定的品类。
  • 优点
    通过检查当前品类并使用 JavaScript 模拟点击,实现了动态选择品类的功能。
    能够处理未找到品类的情况,并输出相应的错误信息。
  • 缺点
    依赖于特定的网页结构和 CSS 选择器,如果网页的品类选择方式发生变化,需要修改代码。
    每次选择品类时都需要遍历所有的选项,可能会在选项较多时效率较低。
4.日期选择模块
select_date(driver, target_date_str)
  • 作用:在网页上选择指定的日期。
  • 优点
    考虑了年份和月份的变化情况,能够正确地选择日期。
    使用显式等待确保页面元素加载,提高了程序的稳定性。
  • 缺点
    对网页的日期选择器结构有较强的依赖,如果网页的日期选择方式发生变化,需要修改代码。
    选择年份和月份时使用了较多的等待和遍历操作,可能会在性能上有所影响。
5.数据导出模块
download_data_for_dates(driver, start_date_str, end_date_str, category)
  • 作用:根据给定的日期范围和品类,在网页上进行数据下载操作,包括选择日期、品类、查询、导出等步骤,并记录操作日志。
  • 优点
    自动化程度高,能够按照指定的日期范围和品类进行数据下载。
    记录了操作日志,方便跟踪和排查问题。
  • 缺点
    对网页的结构和操作流程有较强的依赖,如果网页发生变化,需要修改多个地方的代码。
    随机等待时间可能不够准确,可能会在网络状况不同时导致不稳定。
5.查询、导出和文件名填写模块
(1)click_query_button(driver,min_clicks=3, max_clicks=5)
  • 作用:模拟点击查询按钮,支持随机点击次数。
  • 优点
    通过随机点击次数增加了操作的随机性,可能有助于避免被检测为自动化操作。
    使用显式等待和多种方式处理按钮不可点击的情况。
  • 缺点
    对网页的查询按钮结构有较强的依赖,如果按钮的 CSS 选择器或类名发生变化,需要修改代码。
    随机点击次数可能不是最优的策略,可能会在某些情况下导致不必要的等待或操作失败。
(2)click_export_button(driver)
  • 作用:模拟点击导出按钮。
  • 优点:与click_query_button类似,使用显式等待和ActionChains模拟点击,提高了稳定性。
  • 缺点:对网页结构的依赖与click_query_button相同。
(3)fill_filename(driver, category, day)
  • 作用:填写文件名并返回文件名。
  • 优点:使用ActionChains模拟点击输入框,提高了稳定性。
  • 缺点:对网页的文件名输入框结构有较强的依赖,如果输入框的 CSS 选择器发生变化,需要修改代码。

五、优点

1.功能明确

脚本的功能清晰,旨在根据指定日期自动执行数据导出步骤,可以多品类导出,并且有导出记录,功能较为完整。

2.自动化程度高

能够自动登录、选择日期和品类、执行查询、导出等一系列操作,减少了人工操作的繁琐。

3.错误处理

部分函数中对可能出现的错误进行了捕获和处理,并输出相应的错误信息,增加了程序的稳定性。

4.日志记录

通过设置日志记录,方便跟踪程序的执行过程和排查问题。

5.随机性

在查询按钮点击次数和等待时间上引入了随机性,可能有助于避免被检测为自动化操作。

六、缺点

1.强依赖网页结构

整个脚本高度依赖特定网页的结构和元素的 CSS 选择器、XPath 表达式等。如果网页结构发生变化,需要对多个地方的代码进行修改,维护成本较高。

2.性能问题

在日期选择和品类选择等操作中,使用了较多的等待和遍历操作,可能会在性能上有所影响,尤其是在处理大量日期和品类时。

3.不够灵活

对于不同的登录方式、数据导出格式等需求,脚本的可扩展性不足,难以快速适应变化。

4.随机策略不确定性

虽然引入了随机等待时间和点击次数,但这些随机策略的效果并不确定,可能在不同的网络环境和网页响应情况下表现不一致。

七、改进方向

1.提高适应性

使用更通用的元素定位方法,如相对定位、属性定位等,减少对特定网页结构的依赖。
可以考虑使用页面模型(Page Object Model)设计模式,将页面元素和操作封装在独立的类中,提高代码的可维护性和可扩展性。

2.优化性能

减少不必要的等待和遍历操作,可以通过更精确的等待条件和元素定位来提高性能。
对于频繁使用的操作,可以考虑缓存页面元素,避免重复查找。

3.增强灵活性

支持多种登录方式和数据导出格式,通过配置文件或参数传递的方式,让用户可以根据自己的需求进行定制。
可以添加更多的功能选项,如指定导出文件的存储路径、选择不同的日期格式等。

4.改进随机策略

对随机等待时间和点击次数进行更合理的调整,可以通过实际测试和数据分析来确定最佳的随机范围,以提高脚本的稳定性和效率。

5.异常处理

进一步完善错误处理机制,对于可能出现的各种异常情况进行更详细的分类处理,并提供更友好的错误提示信息。

6.代码重构

对代码进行重构,提高代码的可读性和可维护性。可以将一些重复的代码提取为函数或方法,减少代码冗余。

八、以下是完整代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/7/22 10:00
# @Author  : Jiang
# @功能     : 根据指定日期自动执行数据导出步骤,可以多品类导出,不同时间段,有导出记录,导出完毕后面还有下载。
# @DE      :DataExport 数据导出

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from datetime import datetime, timedelta
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.action_chains import ActionChains
import time
import random
import logging
import os

# 设置日志格式并指定日志文件路径
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s - %(levelname)s - %(message)s',
                    filename=os.path.join(os.getcwd(), 'export_data.log'),
                    filemode='a', encoding='utf-8')

def is_leap_year(year):
    """判断给定的年份是否为闰年"""
    return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)

def days_in_month(year, month):
    """获取给定年份和月份的实际天数"""
    if month in [1, 3, 5, 7, 8, 10, 12]:
        return 31
    elif month == 2:
        return 29 if is_leap_year(year) else 28
    else:
        return 30

# 定义一个映射表,用于将英文月份转换为中文月份
month_mapping = {
    "January": "一月",
    "February": "二月",
    "March": "三月",
    "April": "四月",
    "May": "五月",
    "June": "六月",
    "July": "七月",
    "August": "八月",
    "September": "九月",
    "October": "十月",
    "November": "十一月",
    "December": "十二月"
}

# 格式化报错时间为 YYYY-MM-DD HH:MM:SS.mmm
def get_formatted_time():
    """返回当前时间的格式化字符串"""
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]

def login_and_navigate(login_url, target_url, username, password):
    formatted_time = get_formatted_time()
    print(f"[{formatted_time}]:正在初始化Web驱动程序...")

    try:
        # 访问登录页面
        driver.get(login_url)
        # 等待登录选项出现
        worker_id_login_option = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, 'li.ct'))
        )
        # 点击登录选项
        worker_id_login_option.click()
        # 等待用户名输入框出现
        username_input = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, 'input[name="username"]'))
        )
        # 再次等待登录选项变为激活状态
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, 'li.ct.active'))
        )
        # 输入用户名
        username_input.send_keys(username)
        print(f"[{get_formatted_time()}]:输入用户名: {username}")
        # 等待密码输入框出现
        password_input = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, 'input[name="password"]'))
        )
        # 输入密码
        password_input.send_keys(password)
        print(f"[{get_formatted_time()}]:输入密码 (masked).")
        # 等待登录按钮出现并点击
        login_button = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, 'a.btn'))
        )
        login_button.click()

        # 等待登录成功后跳转
        WebDriverWait(driver, 10).until(
            EC.url_changes(login_url)
        )
        print(f"[{get_formatted_time()}]:登录成功,等待跳转目标网页.")

        # 访问目标页面
        driver.get(target_url)
        print(f"[{get_formatted_time()}]:访问目标网页: {target_url}")

        # 等待页面加载完成
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CLASS_NAME, "el-form-item"))
        )
        print(f"[{get_formatted_time()}]:目标网页加载成功.")

        # 选择日数据/月数据
        day_radio = WebDriverWait(driver, 30).until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, ".el-radio__input.is-checked+.el-radio__label"))
        )
        day_radio.click()
        print(f"[{get_formatted_time()}]:选择日数据.")
    except Exception as e:
        print(f"[{get_formatted_time()}]:登录过程中出现问题: {e}")

def select_category(driver, category):
    # 检查是否需要选择新的品类
    if not hasattr(select_category, 'current_category') or select_category.current_category != category:
        try:
            select_box = WebDriverWait(driver, 10).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, ".el-form-item--mini .el-select .el-input__inner"))
            )
            # 使用JavaScript来模拟点击
            driver.execute_script("arguments[0].click();", select_box)
            print(f"[{get_formatted_time()}]:点击品类选择框.")

            options = WebDriverWait(driver, 10).until(
                EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".el-select-dropdown__item span"))
            )
            for opt in options:
                if opt.text == category:
                    # 使用JavaScript来模拟点击
                    driver.execute_script("arguments[0].click();", opt)
                    print(f"[{get_formatted_time()}]: 选择品类: {category}")
                    break
            else:
                print(f"[{get_formatted_time()}]: 未找到品类: {category}")

            # 更新当前品类
            select_category.current_category = category
        except Exception as e:
            print(f"[{get_formatted_time()}]:选择品类出错: {e}")

def select_date(driver, target_date_str):
    # 将目标日期字符串转换为日期对象
    target_date = datetime.strptime(target_date_str, "%Y-%m-%d").date()

    # 点击日期选择器
    date_input = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.CSS_SELECTOR, ".el-date-editor"))
    )
    date_input.click()
    print(f"[{get_formatted_time()}]:点击日期选择器.")

    # 如果是第一次选择日期或者需要更改年月,则进行年月选择
    if not hasattr(select_date, 'current_date') or target_date.year != select_date.current_date.year or target_date.month != select_date.current_date.month:
        # 点击年份标签
        year_label = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located(
                (By.CSS_SELECTOR, ".el-date-picker__header .el-date-picker__header-label"))
        )
        time.sleep(3)
        # 使用 JavaScript 点击年份标签
        driver.execute_script("arguments[0].click();", year_label)
        print(f"[{get_formatted_time()}]:点击选择年份.")

        # 等待年份选择表加载完成
        try:
            year_table = WebDriverWait(driver, 10).until(
                EC.visibility_of_element_located((By.CSS_SELECTOR, ".el-year-table"))
            )
        except TimeoutException:
            print(f"[{get_formatted_time()}]:年份选择表未加载成功.")
            return

        # 选择具体的年份
        year_cells = year_table.find_elements(By.CSS_SELECTOR, "td a.cell")
        for cell in year_cells:
            if cell.text.strip() == str(target_date.year):
                time.sleep(3)
                cell.click()
                break
        print(f"[{get_formatted_time()}]:选择年份: {target_date.year}.")

        # 等待月份选择表加载完成
        try:
            month_table = WebDriverWait(driver, 10).until(
                EC.visibility_of_element_located((By.CSS_SELECTOR, ".el-month-table"))
            )
        except TimeoutException:
            print(f"[{get_formatted_time()}]:月份选择表未加载成功.")
            return

        # 选择具体的月份
        month_cells = month_table.find_elements(By.CSS_SELECTOR, "td div a.cell")
        target_month_chinese = month_mapping[target_date.strftime("%B")]  # 获取目标月份的中文名称
        for cell in month_cells:
            if cell.text.strip() == target_month_chinese:
                cell.click()
                break
        print(f"[{get_formatted_time()}]:选择月份: {target_month_chinese}.")

    # 选择具体的日期
    days = WebDriverWait(driver, 10).until(
        EC.presence_of_all_elements_located((By.CSS_SELECTOR, "td.available"))
    )
    for d in days:
        if d.text.strip() == str(target_date.day) and not d.get_attribute("class").find("is-disabled") >= 0:
            d.click()
            break
    print(f"[{get_formatted_time()}]:选择日期: {target_date.day}.")

    # 更新当前日期
    select_date.current_date = target_date

def download_data_for_dates(driver, start_date_str, end_date_str, category):
    # 将字符串转换为 datetime 对象
    start_date = datetime.strptime(start_date_str, "%Y-%m-%d").date()
    end_date = datetime.strptime(end_date_str, "%Y-%m-%d").date()

    current_date = start_date
    while current_date <= end_date:
        # 选择当前日期
        select_date(driver, current_date.strftime("%Y-%m-%d"))
        # 选择品类
        select_category(driver, category)
        # 这里可以添加代码来触发数据下载操作
        # 例如: trigger_download(driver)
        # 查询
        click_query_button(driver)
        # 等待查询完成
        time.sleep(random.randint(2, 5))
        # 导出
        click_export_button(driver)
        # 等待导出弹出
        time.sleep(random.randint(2, 5))
        # 填写文件名
        fill_filename(driver, category, current_date)
        # 等待1-3秒文件名写入
        time.sleep(random.randint(1, 3))
        # 确认导出
        click_confirm_button(driver)
        # 随机等待3-5秒 避免检测
        time.sleep(random.randint(3, 5))
        # 处理新窗口并关闭
        handle_new_window_and_close(driver)
        # 增加一天
        current_date += timedelta(days=1)
        # 记录品类和日期
        logging.info(f"文件名:{fill_filename},导出时间:{get_formatted_time()}.")
        # 检查是否为最后一天
        if current_date > end_date:
            break

def click_query_button(driver,min_clicks=3, max_clicks=5):
    try:
        # 生成随机点击次数
        num_clicks = random.randint(min_clicks, max_clicks)
        for i in range(num_clicks):
            # 定位并点击查询按钮
            query_button = WebDriverWait(driver, 30).until(
                EC.element_to_be_clickable((By.XPATH, "//button[contains(concat(' ', normalize-space(@class), ' '), ' el-button--primary ') and contains(concat(' ', normalize-space(@class), ' '), ' el-button--small ')]/span[text()='查询']")
                                           ))
            # driver.execute_script("arguments[0].click();", query_button)
            # 使用ActionChains模拟点击
            action = ActionChains(driver)
            action.move_to_element(query_button).perform()  # 移动到按钮上方
            action.click().perform()  # 模拟点击
            # query_button.click()
            print(f"[{get_formatted_time()}]:查询. (点击次数 {i + 1}/{num_clicks})")
    except TimeoutException:
        # 如果按钮不可见或者不可点击,则打印错误信息
        print(f"[{get_formatted_time()}]:查询按钮在10秒内未变为可点击状态.")
        # 如果按钮不可见或者不可点击,则打印错误信息
        print(f"[{get_formatted_time()}]:查询按钮在10秒内未变为可点击状态.")
        # 查找按钮元素
        query_button = driver.find_elements(By.XPATH, "//button[contains(concat(' ', normalize-space(@class), ' '), ' el-button--primary ') and contains(concat(' ', normalize-space(@class), ' '), ' el-button--small ')]/span[text()='查询']")
        if query_button:
            print(f"[{get_formatted_time()}]:查询按钮存在,但不可点击.")
        else:
            print(f"[{get_formatted_time()}]:查询按钮不存在.")

def click_export_button(driver):
    try:
        # 定位并点击导出按钮
        export_button = WebDriverWait(driver, 30).until(
            EC.element_to_be_clickable((By.XPATH, "//button[contains(concat(' ', normalize-space(@class), ' '), ' el-button--primary ') and contains(concat(' ', normalize-space(@class), ' '), ' el-button--small ')]/span[text()='导出']")
                                       ))
        # driver.execute_script("arguments[0].click();", export_button)
        # 使用ActionChains模拟点击
        action = ActionChains(driver)
        action.move_to_element(export_button).perform()  # 移动到按钮上方
        action.click().perform()  # 模拟点击
        # export_button.click()
        print(f"[{get_formatted_time()}]:导出.")
    except TimeoutException:
        # 如果按钮不可见或者不可点击,则打印错误信息
        print(f"[{get_formatted_time()}]:导出按钮在10秒内未变为可点击状态.")
        # 如果按钮不可见或者不可点击,则打印错误信息
        print(f"[{get_formatted_time()}]:导出按钮在10秒内未变为可点击状态.")
        # 查找按钮元素
        query_button = driver.find_elements(By.XPATH, "//button[contains(concat(' ', normalize-space(@class), ' '), ' el-button--primary ') and contains(concat(' ', normalize-space(@class), ' '), ' el-button--small ')]/span[text()='导出']")
        if query_button:
            print(f"[{get_formatted_time()}]:导出按钮存在,但不可点击.")
        else:
            print(f"[{get_formatted_time()}]:导出按钮不存在.")

def fill_filename(driver, category, day):
    # 定位并填写文件名
    filename_input = WebDriverWait(driver, 30).until(
        EC.element_to_be_clickable((By.CSS_SELECTOR, ".el-form-item.condition-item.is-required.el-form-item--mini.el-input__inner"))
    )
    action = ActionChains(driver)
    action.move_to_element(filename_input).perform()  # 移动到按钮上方
    action.click().perform()  # 模拟点击
    filename = generate_filename(category, day)
    filename_input.send_keys(filename)
    logging.info(f"文件:{filename}.")
    return filename
def generate_filename(category, date):
    # 生成文件名
    year, month, day = date.year, date.month, date.day
    # 将四位数的年份转换为两位数的年份
    two_digit_year = str(year)[2:]
    # 文件名前缀
    prefix = {
        "厨房卫浴电器": f"厨卫",
        "生活电器": f"小家电",
        "冰箱洗衣机": f"冰洗",
        "未知": f"未知"
    }.get(category, "未知")
    filename = f"{prefix}{two_digit_year}.{month}.{day}"
    logging.info(f"文件名已生成:{filename}")
    return filename

def click_confirm_button(driver):
    try:
        # 定位并点击确定按钮
        confirm_button = WebDriverWait(driver, 30).until(
            EC.element_to_be_clickable((By.XPATH,
                                        "//div[contains(concat(' ', normalize-space(@class), ' '), ' pagination-block ')]"
                                        "/button[contains(concat(' ', normalize-space(@class), ' '), ' el-button--primary ') and contains(concat(' ', normalize-space(@class), ' '), ' el-button--mini ')]"
                                        "/span[text()='确定']"))
        )
        # driver.execute_script("arguments[0].click();", confirm_button)
        # confirm_button.click()
        action = ActionChains(driver)
        action.move_to_element(confirm_button).perform()  # 移动到按钮上方
        action.click().perform()  # 模拟点击
        filename = fill_filename(driver, None, None)  # 根据实际情况传入参数
        logging.info(f"确定导出{filename}.")
    except TimeoutException:
        # 如果按钮不可见或者不可点击,则打印错误信息
        logging.info(f"确定按钮在10秒内未变为可点击状态.")
        # 如果按钮不可见或者不可点击,则打印错误信息
        logging.info(f"确定按钮在10秒内未变为可点击状态.")
        # 确定按钮元素
        query_button = driver.find_elements(By.XPATH,
                                            "//div[contains(concat(' ', normalize-space(@class), ' '), ' pagination-block ')]"
                                            "/button[contains(concat(' ', normalize-space(@class), ' '), ' el-button--primary ') and contains(concat(' ', normalize-space(@class), ' '), ' el-button--mini ')]"
                                            "/span[text()='确定']"
                                            )
        if query_button:
            logging.info(f"确定按钮存在,但不可点击.")
        else:
            logging.info(f"确定按钮不存在.")


# 定义一个函数来处理导出后的页面关闭
def handle_new_window_and_close(driver):
    # 记录原始窗口句柄
    original_window = driver.current_window_handle
    try:
        # 点击下载后等待新窗口出现
        WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(2))
        # 获取所有窗口句柄
        for window_handle in driver.window_handles:
            if window_handle != original_window:
                # 切换到新窗口
                driver.switch_to.window(window_handle)
                # 关闭新窗口
                driver.close()
                # 切换回原始窗口
                driver.switch_to.window(original_window)
                # 随机等待1-5秒 避免检测
                time.sleep(random.randint(1, 5))
                break
    except Exception as e:
        # 如果出现任何异常,则打印错误信息
        logging.error(f"关闭新窗口: {e}")
    finally:
        # 在finally块中添加额外的日志信息,确保即使发生异常也会执行
        logging.info("关闭新窗口.")

if __name__ == "__main__":
    print("开始运行程序...")
    # 初始化 WebDriver
    options = Options()
    # options.add_argument('--headless')  # 无头模式
    # options.add_argument('--disable-gpu')  # 禁用GPU加速
    options.add_argument('--start-maximized')
    # 创建WebDriver实例  替换为你的 chromedriver 的路径
    driver = webdriver.Chrome(executable_path='D:/Python/Python36-32/chromedriver.exe',
                              options=options)
    # 登录页面的URL
    login_url = '你的登录链接'
    # 目标页面的URL
    target_url = '指定下载的页面'
    # 设置登录账户密码
    username = '用户名'
    password = '密码'
    # 设置起始和结束日期
    start_date_str = "2023-02-01"
    end_date_str = "2023-02-28"
    # 设置品类列表
    categories = ["生活电器", "厨房卫浴电器", "……"] 
    # 登录并导航到目标页面 
    login_and_navigate(login_url, target_url, username, password)
    # 为每个品类导出数据
    for category in categories:
        download_data_for_dates(driver, start_date_str, end_date_str, category)
        print(f"[{get_formatted_time()}]:完成品类 '{category}' 的数据下载.")
    print(f"[{get_formatted_time()}]:程序执行已完成.")
    # 关闭 WebDriver
    driver.quit()

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姜大炮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值