小白喜欢的攻略!python 网站下载器,wget + selenium + request + beautifulsoup。过于仔细程序设计。下载完整的整个网站

简述论文:

大家好,有时候我们会遇到一些较为陈旧的网站,却惊喜地发现它们非常好用。不过,遗憾的是,这些网站往往已经存在近十年,处于一种半死不活的状态。当尝试百度搜索如何下载这些网站时,会发现已有工具可以实现这一功能,例如HTTrack或者wget(Unix命令)。即使在Windows系统中,也可以通过Shell来实现这些功能。然而,每次使用这些工具都非常痛苦。例如,涉及到登录功能时,就需要手动保存cookie等信息。而且在使用过程中,还可能遇到许多有趣的bug。

因此,我决定尝试实现一个更加精细的网站下载器,目的是为了让整个网站的下载过程变得更加轻松。

遇到的问题:

首先,我发现自己实际上什么都不会。虽然我能轻易地想到需要使用哪些工具和实现哪些功能,但我不知道如何具体实现它们。我写了一个计划,但它并没有太大的用处。虽然我的论文并不是一个标准的程序设计论文——它没有完整的类图、流程图、E-R图等,但论文的意义并不在于此。它主要描述了我作为一个初学者面临的困难,以及我想要理解但却不知道的内容。因此,这篇论文也非常适合像我一样的初学者,尽管我也不完全确定,毕竟我自己也是一个初学者。

开始:

在开始编写代码之前,首先需要熟悉整个程序的结构。这包括理解不同类之间的相互作用以及正确使用所需的库。同时,遵循PEP8规范对于面向对象编程(OOP)来说非常重要。这些准备工作能确保代码具有良好的可读性,这不仅有助于未来的自己更容易理解代码,同时也保证了代码的可维护性(便于修改和扩展)和安全性(有效处理异常和错误)。


面向对象编程(OOP)

在程序设计中,面向对象编程(OOP)是一种常用的方法,因为它提供了一套基本的模型和规则。有时,我们在编程时不自觉地使用了OOP的概念,即使我们可能并不完全意识到这一点。理解OOP的基本概念有助于理解以下内容。在此,介绍一些OOP的基本概念。封装和接口之间的区别可能难以理解,因为它们紧密相连,但各有其独特的职责。以下是对这些概念的具体解释:

1. 封装(Encapsulation)能变化的部分:

封装不仅仅是将事物分开,它更多的是关于隐藏实现细节,只向外部暴露必要的接口。封装的核心是将数据(属性)和操作这些数据的方法(行为)组合在一起。例如,如果下载操作直接实现在Download类内,那么在需要扩展功能时,就需要修改Download类的代码。而通过封装,可以形成独立的对象,其目的是隐藏对象的内部实现细节,只向外界提供一个清晰、简洁的接口。在Download类中,可以通过接口为每种下载方法指定自己的类,从而可以使用策略模式(一种设计模式)来处理这种多样性。Download类和接口(如IDownload)都不了解具体实现方法的细节。

2. 面向接口编程(Interface-oriented programming)或面向抽象编程(Abstraction-oriented programming):

例如,Download类创建了一个名为IDownload的接口(或抽象类)《interface》。这个接口不关心具体如何实现这些方法,只是声明这些方法必须存在。接口包含了所有下载操作必须实现的方法,例如:start(), pause(), resume(), cancel()等。根据不同的下载需求,可以实现多个具体的下载类,如WgetDownload, SeleniumDownload, RequestsDownload等。在程序的其他部分,如Download类,当需要进行下载操作时,代码只与IDownload接口交互,而不是直接与具体的下载类交互。这意味着可以根据需要选择使用哪个下载类,而无需修改Download类的代码。

类命名(class):

本部分旨在辅助理解论文的核心内容,下述描述仅用于概述它们的基本功能。

   ```python

class User: # 代表用户实体,管理用户数据和行为,如用户名、密码、账户等。

        # 具体代码

    pass

class Account: # 代表特定服务上的账户,管理认证和会话信息。

class Download: # 管理网络下载过程,处理下载相关逻辑。

class File: # 管理文件读写操作,提供对本地文件系统的接口。

class DownloaderAppUI: # 管理用户界面相关的元素和事件。

class DownloaderAppLogic: # 作为 UI 和底层功能之间的桥梁,管理应用程序的主要逻辑。

class NetworkManager: # 处理所有网络请求和会话管理。

class StorageManager: # 管理本地数据存储,如文件和 Cookies。

class Logger: # 提供统一的日志记录接口。

class ErrorHandler: # 处理应用程序中的异常和错误。

class ConfigManager: # 管理应用程序的配置设置。

class CaptchaSolver: # 分别负责代理服务器配置和验证码解析。

# 其他,如 class ProxyManager: 等

 ```

关于系统的层次结构(核心组成):

1. 用户(User)和账户(Account):

   - 一个 User 可以有多个 Account,而每个 Account 只能属于一个 User。

   - User 负责存储和管理一些基本的数据,可以视为系统的底层。

   - Account 主要负责管理和保存与账户相关的信息。

2. 网络管理(NetworkManager):

   - NetworkManager 负责处理网络请求和会话管理。

   - 网络请求包括获取 cookie(不仅限于此),而会话管理则涉及保存 cookie。这里的“会话”指的是用户登录后,系统用以记住用户身份的机制。

   - 简单来说,NetworkManager 是 User 和 Account 的真正逻辑层(一部分),而 StorageManager 用于保存 cookie 的组件。


 

关于UI层(PyQt)和逻辑层(程序逻辑和UI逻辑)的关系:

1. 界面层 (DownloaderAppUI):

   - 使用 PyQt 的各种控件(如 QLineEdit, QLabel 等)来构建用户界面,这个层不包含具体逻辑。

   - QLineEdit 可用于接收用户输入,例如用户名、密码等(这只是一个简单的例子,实际应用可能更为复杂)。

   - QLabel 可用于显示信息,例如登录状态、下载进度等(控件可以根据需求进行扩展)。

2. 逻辑层(业务逻辑层) - (DownloaderAppLogic):

   - User、Account 和 Download 是业务逻辑层的一部分。

   - DownloaderAppLogic 类负责处理用户的输入(如登录、下载操作)并调用其他类(如 User、Account、Download)来执行具体任务。

   - 例如,用户点击下载按钮后,逻辑层会处理下载请求。DownloaderAppLogic 获取 QLineEdit 的内容,传递给 User 类,然后 User 类通过 Account 类进行操作,最终到达 Download 类。在这个过程中,各个类可能会向 DownloaderAppLogic 发送各种信息(如登录状态、下载进度、错误信息等),则 DownloaderAppLogic 通过 QLabel 将这些信息展示在 UI 上,以便用户了解当前状态。

3. 数据层 - File,StorageManager,ConfigManager:

   - 这一层实际上与界面层 (DownloaderAppUI) 没有直接的联系,所有的交互都是通过逻辑层来实现的。

   - 可以将 DownloaderAppUI 和 DownloaderAppLogic 的关系看成为类(class)之间的联系,它们相互协作,但各自负责不同的功能模块。


 

Download 类的逻辑根据不同的需求,有不同实现方式。例如:

1. wget:这种方式模拟 Unix 系统中的 wget 命令行工具。

2. Selenium:是一个用于自动化网络浏览器操作的工具,可以适用于网络请求(不好用,但是可以模仿用户操作,则避免反虫)。

3. Requests + BeautifulSoup:结合了 Requests 库(用于发送网络请求)和 BeautifulSoup 库(用于处理 HTML 内容)。

无论是使用 Requests 库还是 Selenium 工具获取的 HTML 源码,通常情况下,这些源码只包含 HTML 代码本身,而不包括 CSS 样式、图片文件或 JavaScript 脚本。这些额外的资源通常是通过 HTML 文档中的链接加载的,例如通过 `<link>`, `<script>`, `<img>` 等标签指定的链接。这意味着在处理下载任务时,可能需要额外的步骤来处理这些链接指向的资源。


 

日志记录及错误处理:

在软件开发中,日志记录和错误处理是确保程序稳定性和安全性的关键环节。这通常涉及到两个主要组件:Logger 和 ErrorHandler。

1. Logger:

负责记录各种类型的信息,这包括错误、警告、普通信息消息以及调试消息。它的使用并不仅限于记录错误。通常,Logger 记录的信息主要用于开发者分析和调试,而不是直接展示给用户。

2. ErrorHandler:

专门用于处理程序中出现的错误和异常。它的主要目的是获取异常,以防止程序因未处理的错误而崩溃。ErrorHandler 通常会将获到的错误信息转换成用户可以理解的形式,并显示给用户。例如,ErrorHandler 代码的形式:

   ```python

   class ErrorHandler:

       def handle_error(self, error):

           # 处理错误的逻辑

   def some_method(error_handler):

       try:

           # 执行可能引发异常的操作

       except SomeException as e:

           error_handler.handle_error(e)

   ```

将异常处理逻辑集中到专门的 ErrorHandler 类中,可以提高代码的可维护性和可读性。与 Logger 相比,ErrorHandler 更专注于异常处理,而不是信息记录。因此,通常不会在 Logger 类中实现类似 ErrorHandler 的复杂处理逻辑,以避免过度职责。

   

描述用户与 DownloaderAppUI(这是整个程序的界面层,作为用户与程序之间的接口)之间的交互:

1. 登录:

   - 1.1 是否需要登录?通过 `ConfigManager` 的 `saveLoginState(self, remember: bool)` 方法来决定。

   - 1.2 选择账户数据(可以是多个账户或单个账户)通过 `ConfigManager` 的 `saveAccountPref(self, multiple_accounts: bool)` 方法来实现。

备注:在下面的步骤中,都会用到 `Logger` 和 `ErrorHandler`,关于日志记录及错误处理的具体内容已在“日志记录及错误处理”部分进行了详细描述。

2. 账户信息输入方法:

   - 2.1 用户需选择登录方式:“手动”或“自动”,通过 `ConfigManager` 的 `setLoginInfoSource(self, source: str)` 方法来设置。

   - 2.2 如果选择“手动”方式:

     - 2.2.1 用户通过 UI 输入登录信息(用户名/邮箱+密码),不在网站本身。

     - 2.2.2 “QR 码登录”,通过 `ConfigManager` 的 `setManualLoginMethod(self, method: str):` 方法来设置,这样做是为了方便未来的扩展。

   - 2.3 如果选择“自动”方式,则从文件中读取登录信息(用户名/邮箱+密码),通过 `ConfigManager` 的 `setAutoLoginMethod(self, method: str):` 方法来实现,并采用分层方法处理。

3. 输入登录信息的方法:

   - 3.1 用户需要在“手动”和“自动”中选择一种登录方式,这通过 `ConfigManager` 的 `saveLoginMethodPreference(self, method: str)` 方法来实现。

4. 登录验证:

   - 4.1 判断是否需要进行验证,通过 `ConfigManager` 的 `setVerificationRequirement(self, required: bool)` 方法来设置。

   - 4.2 选择验证方法:

     - 4.2.1 “扫码”验证。

     - 4.2.2 “email 验证码”验证。

     - 4.2.3 “手机号验证码”验证。

     - 4.2.4 类似于“Google Authenticator”的验证方法。

     - 这些方法可以通过 `ConfigManager` 的 `selectVerificationMethod(self, method: str)` 方法来选择。

   - 4.3 选择获取验证码的方式:

     - 4.3.1 “手动”获取验证码。

     - 4.3.2 “半自动”获取验证码。

     - 4.3.3 “自动”获取验证码。

     - 这些策略可以通过 `ConfigManager` 的 `setCaptchaRetrievalStrategy(self, strategy: str)` 方法来设置。

5. 登录时的验证码(Captcha)处理:

   - 5.1 设置登录过程中是否需要通过验证码,可以通过 `ConfigManager` 的 `enableCaptchaForLogin(self, required: bool)` 方法来决定。

   - 5.2 选择验证码处理方式:

     - 5.2.1 “手动”处理验证码。

     - 5.2.2 “自动”处理验证码。

     - 这些处理方式可以通过 `ConfigManager` 的 `setCaptchaHandlingStrategy(self, strategy: str, **kwargs)` 方法来设置。

       - 5.2.1.1 在“手动”模式下,用户需自行手动完成验证码的验证。

       - 5.2.2.1 在“自动”模式下,可以选择“使用 API 解决验证码”或“使用专门的验证码解决库”。:

6. 启动登录流程:

   - 6.1 用户点击按钮以启动登录过程。DownloaderAppUI 并不是从一开始就展示所有设置选项,而是根据用户的选择逐步显示。例如,在 DownloaderAppUI 的“登录模块”中,初始化时仅显示部分界面,让用户决定是否需要登录。其他未激活的选项在界面上表现为不可用状态(如用灰色显示),以明确指示用户这些部分暂时不可选择。

   - 6.2 如果用户在(1.1)中选择了需要登录,则(1.2)和(2)变为可选且必须的选项,用户未选择这些选项时将无法启动登录过程。

   - 6.3 DownloaderAppLogic 会根据 ConfigManager 的设置逐步判断是否显示各个选项,同时也会基于 ConfigManager 来处理可能出现的异常等情况。

简述流程:

1. DownloaderAppUI 负责收集用户信息,并将这些信息传递给 DownloaderAppLogic。

2. DownloaderAppLogic 接着确定如何处理这些数据。例如,它可能会先查看 ConfigManager 中的设置,然后利用 Account 类尝试执行登录操作。

3. Account 类可能会通过 NetworkManager 向服务器发送请求,以进行用户认证。

4. 用户认证的结果会被返回给 DownloaderAppLogic,随后由其处理后续逻辑。这可能包括更新 User 类的登录状态,或者通过 DownloaderAppUI 向用户反馈登录成功或失败的信息。


 

详细流程 - 登录信息部分:

1. 初始化:DownloaderAppUI 在每次启动程序时进行初始化。

2. 显示选项和信息:根据 DownloaderAppLogic 的指示,DownloaderAppUI 显示新的选项和信息。

3. 信息保存:DownloaderAppUI 收集的属性信息由 DownloaderAppLogic 保存到 ConfigManager 中。

4. 执行与处理:DownloaderAppUI 收集的执行命令由 DownloaderAppLogic 根据其异常处理机制和 ConfigManager 的设置来处理。

5. 用户选择与执行:例如,用户决定是否需要登录,以及选择信息获取的方法。DownloaderAppLogic 根据用户的选择和其异常处理机制,在 DownloaderAppUI 中显示相应的信息窗口(如手动方法)或选择文件路径(如自动方法)。

6. 信息输入与处理:

   - 如果需要手动输入信息,DownloaderAppUI 将信息直接发送到 Account。

   - 如果是通过文件获取信息,DownloaderAppUI 会引用 StorageManager。StorageManager 从文件中获取信息并发送到 Account。

7. 完成与状态更新:

完成上述过程后,会将“信息成功获取”的状态更新为 True。这包括“选择部分”和“获取输入部分”的处理。

选择有自己的逻辑,先选a,然后如果a为true那一定选择b,c,d等,首先输入不会影响选择,就是能先完成选择才开始输入,或者选择部分啊就立刻输入,继续。但是实际上逻辑更复杂。并且但是选择和输入跟能不能启动登陆有联系。

详细流程 - 登录验证部分:

1. 显示登录验证选项:

DownloaderAppUI 首先显示是否选择进行登录验证的选项。由于之前已选择登录,因此界面自动增加了包含验证码等新的选择项。

2. 用户选择保存:

DownloaderAppLogic 接收用户的选择,并将这些选择(例如是否启用验证码验证)的布尔值保存在 ConfigManager 中。

3. 信息处理:

   - 手动和自动模式:如果已有固定的验证码保存在 Account 中,那么对于“手动”模式,验证码验证通过 DownloaderAppUI 自行完成;对于“自动”模式,则通过 StorageManager 来处理。

   - 如果验证码是登录过程中才产生的,那么在登录过程中将根据 StorageManager 的判断进行处理。例如,在手动模式下,NetworkManager 会在登录过程中暂停,等待用户完成验证码验证。

4. 登录实现与处理:

   - NetworkManager 是实现登录的主要类,依赖于 Account、ConfigManager 等。当 DownloaderAppUI 启动登录时,DownloaderAppLogic 指示 NetworkManager 开始登录过程。

   - 在半自动模式下,NetworkManager 可尝试打开电子邮件网页并试图登录,寻找验证码。每一步都会向 DownloaderAppUI 反馈,以确认操作是否正确。如果 DownloaderAppUI 返回 False,或者 NetworkManager 直接获取失败,则会从半自动模式切换到手动模式。

   - 自动模式与半自动模式类似,但不会在每一步都询问用户确认。这种模式可能会出现错误,最终可能需要切换回手动模式。

此部分及其后续流程,由于对登录过程的影响较大,半自动和自动模式可能存在使用上的困难。这意味着,如果出现错误导致登录失败,系统可能需要询问用户是否重新登录。同时,为了避免重复出错,建议在下一次尝试登录时将验证和验证码(captcha)的处理方式更改为“手动”模式。

登录验证码(Captcha)处理部分:

1. 这一部分的流程与之前的流程相似,但有一个关键区别:用户无需从文件或 UI 提前获取答案,因为验证码处理只在登录开始后才需要进行。

2. 一旦 DownloaderAppUI 启动登录流程,就会将全部处理权交给 NetworkManager,并且它会调用 CaptchaSolver 来解决验证码问题。

3. 手动和自动模式的逻辑在这里是相似的,但不包括半自动模式。

在上面两个需要在DownloaderAppUI,手动部分显示为“推荐”,同时,在用户选择半自动或自动操作时,应提醒用户这两种方式的效率可能相对较低。

登录成功后的流程:

1. 一旦登录成功,NetworkManager 会将 cookie 保存在 StorageManager 中。

2. 接着,NetworkManager 将登录状态更新为成功。

3. 需要注意的是,在这个过程中会涉及到日志记录(logger)和异常处理。这些操作会根据具体的逻辑情况来执行,并随之动态编写。

7. 用户输入 URL:

   - 7.1 用户输入他们想要下载内容的网站地址(URL)。这可以通过 `configManager.saveDownloadURLs(url_list)` 方法来实现。

   - 7.2 用户还可以输入不希望访问的链接(这样做是为了避免程序自动退出账户)。这可以通过获取 `configManager.getBlockedURLs()` 方法返回的禁止访问的链接列表 `blocked_url_list` 来完成。

流程描述:

1. 用户首先在界面上(如 DownloaderAppUI)输入多个 URL。

2. 接着,DownloaderAppUI 将这些输入的 URL 传递给 DownloaderAppLogic。

3. 然后,DownloaderAppLogic 会调用 `configManager.getBlockedURLs()` 方法来保存这些 URL。

8. 下载设置:

   - 8.1 选择下载方法:

     - 8.1.1 “正常”模式:以 wget 作为主要工具进行下载。

     - 8.1.2 “高级”模式:使用 selenium + request(以 download 为主工具)。若选择“高级”模式,需先检查该工具是否已实现。如果未实现,则显示“抱歉,您选择的工具暂时不支持”,并自动切换至“正常”模式。

   - 8.2 选择保存路径(下载文件的存储位置)。

   - 8.3 设置递归下载深度(决定下载内容的层级深度)。

   - 8.4 设置下载速度,例如:在一分钟内下载 20 页。

   - 8.5 设置大小限制,例如:当下载的网站文件夹达到 2GB 时,自动结束下载。

   - 8.6 选择特殊目标,如在下载过程中或下载后自动寻找特定目标,例如:百度盘、夸克盘等链接并解析。

   - 通过 `configManager.setDownloadPreferences(preferences)` 方法设置下载相关的用户偏好,如下载路径、下载速度限制等。

9. 启动下载过程(`downloader.startDownload()`):

   - 9.1 在下载过程中提供以下选项:

     - 9.1.1 暂停下载:通过 `downloader.pauseDownload()` 方法实现。

     - 9.1.2 取消下载:通过 `downloader.cancelDownload()` 方法实现。

     - 9.1.3 继续下载:通过 `downloader.resumeDownload()` 方法实现。

     - 9.1.4 重新启动下载:通过 `downloader.restartDownload()` 方法实现。这个操作不会删除当前已下载的内容,而是在新的文件夹中重新开始下载。

   - 注意:这些方法应在 `Download` 类中得到实现。

谢谢观众,求评价!

  • 31
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值