唔.....这个程序是这么多天来写的最麻烦,最费时间精力的一个程序,大概花了两天时间
下面讲讲心酸历程。。。
-
看看运行结果:
初始界面是这样,,而且我还只实现了小说部分,图片部分甚至视频部分都没得精力搞下去了,,,就光实现这个小说部分,总共代码长度就800多行了,
点进去之后的一部分是这样的:
最上面是它们网站所有小说的分类 ,然后中间是用户可以进行的操作。
功能还是挺不错的,细节方面都调试过n遍了,现在bug应该没有,,吧。。
路径下如果已经存在就不会重复下载。
-
看起来简单的一个程序,要实现出它完整的功能还是挺麻烦的。具体我才用了oop思想,也就是面向对象编程,把不同功能的实现代码分开编写,可能会清楚些,封装好后大概是这样:
很清晰明了,My_thread是线程,用来并行处理gui和爬虫的任务;
Gui就是我们的tkinter主界面;Spider就是我们的爬虫部分。最下面调用下。
大体步骤:
(一):实现Spider类的部分功能:
大概一共就这么多个函数,注释已经给的很详细了。
注意内容:
① number是类属性,目的是判断当前是第几只爬虫(比如小说,图片,甚至视频需要不同的爬虫来爬,这里记录总共有几只。)
这里面很多都是我在后期调试,然后实现新功能的时候慢慢加的,都是很有必要的。
③ 在实现get_etree的时候我也尝试了很多次,刚开始一直修改timeout,因为有时候网络访问会很慢(表现出卡死的样子),所以我设置只要timeout后就退出;后来我发现很多时候根本爬不到数据。然后我给timeout设置很短,直接啥也没有,设置很大,它爬半天也没结果。
注意一些类属性的判断啥的都是后期加上去的,为了让程序更完善。
它返回一个解析后所有数据的列表。
⑤ 下载文件的函数我为了和gui结合起来还是搞的挺复杂的:但是主体思想如果不用gui的话还是很简单,没什么变化,给的待下载列表里面就是一个个的字典,每个字典都是一本小说,字典有两个键,一个是小说名字,还一个是小说url。
⑥ deal_novel大概就是专门处理与gui交互的准备过程,将一些必要的参数爬取下来,比如给⑤的参数列表,就在这里面实现,这里我也把所有页的所有小说都爬下来了(当然用户可以在gui界面手动停止。)大概这样:很多东西我都注释了的,还挺容易看懂的。
⑦ start方法大概就是统筹下,做预处理工作等等:大概内容就这么多,很多东西不是一开始就能构思完的,函数框架可以在刚开始构建出来,但是内容确实要根据程序的需要不断变化。
(二):实现Gui类的部分功能:
这个gui是整个程序最复杂的一部分了(大概占了4,500行代码),gui是用python 标准库tkinter开发的, 如果没有tkinter基础可能难看懂 。gui实现过程大概有以下几步:1. 创建主窗口,同时在主窗口的里面创建很多需要的组件。
- 给不同的组件绑定不同的事件。
- 当触发gui的事件后就设计函数去处理事件。
- gui的mainloop, 也就是一个永真循环。但是可以被阻塞,也可以在里面创建子进程。
一个个大致讲下:
其中frames是所有的框架组件,buttons是所有的按钮组件,labels是所有的标签组件,它们都是列表,为什么要用列表呢?原因是方便管理,当我处理同一类的组件时它们放在一起会很好处理,所以这是个好习惯,把所有同类型的组件放在同一个列表里。
③ 放置主窗体所有组件:像这样,有的用gird,有的用pack,看实际需求。
④ 处理主窗体的所有事件:这里注意个细节:我把按键响应与按钮绑定在一起,而不是单独处理,这样会很方便,f1和f2就是把按键响应和按钮绑定在一起的:
我把用户点击右上角的退出事件和离开事件也绑定在一起了,可以方便处理。 ⑤ 设置字体没啥说的,用tkinter.font库生成一个字体列表,用的时候从里面取就好了:
⑦ 当用户点击“小说”后会触发一个很重要的事件(主要代码也在里面),结果是会生成一个子窗体,然后各种操作也是在子窗体里面去完成,这样做的好处,就是可以灵活的处理不同类型的主事件,比如图片啊,视频啊,小说啊什么,点击后会有更多的灵活处理的空间。
放置这些组件也是在响应函数里完成的。同时还需要在里面完成处理子窗体的组件绑定的各种事件:
这里重要的点也是:将按键事件与按钮绑定在一起,方便一起处理。
⑧ 各种响应事件的实现:我都放在类里面,作为类的成员函数,这样一是方便,二是方便与spider爬虫类交互。比如这个关闭子窗口的事件:需要把用户点击右上角退出和esc离开事件都绑定成了它。
。。。大概就说这么多,有tkinter基础的好搞些,慢慢搞总是能搞出来的。
这里我再着重说下几个我之前不太会的:
- 创建frame框架时要手动设置它的长和宽, 创建各种组件时如果你需要按照你的规则拜访好,最好也给他们设置长和宽, 但是这个长和宽和主窗体设置时候的长和宽是不同的, 差不多组件的长和宽代表它在”一面“一个可视范围内能占多数条(例如 listbox组件)
- 将组件与拉条绑定, 需要将拉条的command绑定成组件的yview函数, 将组件的yscrollcommand绑定成拉条的set函数。
- grid的sticky 将组件放好后边缘对齐很重要。 pack的fill将组件沿着x或者y或者两者填充满, side表示将组件放在窗体的哪个边上。
(三):实现Thread类的功能:
我实现的thread类继承threading.Thread类,这样我只要重写它的run方法,那么run方法里面的内容就是在子线程中会执行的方法。这里为什么要用thread开线程? 因为gui界面是一个死循环, 你要在死循环里面暂停后去处理别的事件(这里比如爬虫事件), 那么主窗体会卡死, 未响应, 所以你必须要开线程去处理那些处理完需要很长时间的代码。
我加了个code, 这个用来实现不同的处理, target_list则是传递过来的待下载的目标列表, 然后用线程去下载。
run方法就是线程的主题,线程会做这里面的事情:
我像这样用不同的code来识别处理不同的事件,这样很方便,不用写额外的线程代码啥的。
(四):慢慢一步一步debug,统领协调整个程序,处理类之间的交互:
然后最后这步才是最重要的,我们需要把自己想象成用户,去尝试运行自己的程序,然后处理程序的bug,或者哪些需要改进的也要自己去改进,反正都到了这步了,慢慢来就好了,我也是花了很长时间在这步,有时候运行的时候想到了怎么改进,但是正在处理别的,就用记事本把事情记下来之后再处理,一步步完善,直到最后把程序做好,总之,用户的体验才是最重要的,你程序写的再好没有用户喜欢也是白搭,所以跟着用户的喜好走很重要的。
其中我在这步里面就加了n个类的成员属性去完成不同的事情,处理各种bug。。
总之很煎熬,但只要你坚持下来了,你就能胜利。
大概。。。就写这么多吧,,,这个做完自己还是有很大的成长, 但是也看到了很多自己的不足, 要学习的东西还是太多了, ,希望大家好好学习,, 知识是最棒的。。 ✌
(如果想要源码或者exe文件或者有想要讨论的地方可以私信我。。看到必回。谢谢)