最近学了下多线程+Queue的爬虫,于是在我很喜欢的一个壁纸网站(Wallhaven)上做实践。
想每次运行程序,就能帮我自动爬取最新的所有壁纸(直到上一次已经下载过的壁纸)下载到电脑里。
代码见Github - Newest wallpaper everyday
多线程的编写中规中矩,不过任务的分配并不是简单的平均分配,而是结合了Queue来实时地给各个线程分配任务,以充分利用各个线程资源。
首先创建一个队列对象,把爬取到的各个要访问的图片链接入队:
q = Queue()
for i in range(len(picUrl)):
q.put(picUrl[i])
接着是MyThread类,不断从queue中出队图片链接后执行下载操作:
class MyThread(threading.Thread):
def __init__(self, threadID):
threading.Thread.__init__(self)
self.threadID = threadID
def run(self):
# 下载出队图片
while not q.empty():
urlNum = q.get()
downloadPic(urlNum, self.threadID)
最后再创建启动各个进程即可:
for i in range(threadSum):
thread = MyThread(i+1)
thread.start()
要让每次运行程序爬取最新壁纸时,能爬到上次下载过的图片就停止。
因此爬取前,都要先获取上次爬取到的图片信息,以及每次爬取后,更新记录这个信息。
而这个记录功能用到的是Python的shelve模块。
每次爬取后,记录爬取的最新的三张图片的编号,放到模块文件的'alpha-wallhaven'键中:
import shelve
shelfFile = shelve.open('myData')
shelfFile['alpha-wallhaven'] = picNames[0:3]
shelfFile.close()
每次爬取之前,都先读取该模块文件里的信息,之后将该信息作为对比即可知道上次下载到哪里了:
shelfFile = shelve.open('myData')
lastPicNum = shelfFile['alpha-wallhaven']
shelfFile.close()
为什么不能只记录一张图片的信息,要记录三张呢?
这是为了防止网站上有壁纸被删了,而我们上次记录的恰好是这张图片,那程序将找不到这张图片,停不下来一直下载。
那为什么不能用<=呢?检测到当前壁纸编号<=上次记录的壁纸编号,那么就到此为止了?
爬一下链接编号就可以发现,Wallhaven的最新壁纸编号并不都是按顺序的,so,还是应该记录多张壁纸信息。
把py代码输出成windows的可执行文件,用到的是PyInstaller模块。
用pip安装好该模块和pywin32(是的,还要另一个模块)后,在cmd下更改到py文件所在路径后,执行:
pyinstaller -F xxx.py
就会生成几个文件夹和文件,而我们要的exe文件就在dist文件夹中了。
其他一并生成的文件据我所知是可以删掉的,不影响exe文件的执行。
然后把可执行文件的快捷方式放到桌面,每天运行一下就能获取最新壁纸啦~