xdxgkxq 发表于 2022-11-16 21:58

爬虫-调用IDM利用API来快速下载Wall Haven账号收藏夹中的图片

https://wallhaven.cc/ 网站中有许多好看图片,平时看到就顺手就收藏了,那么如何快速批量下载自己收藏夹中的图片呢?

网站很贴心地提供了api,(https://wallhaven.cc/help/api) 所以直接利用api来下载,特别方便。为了提高下载速度,可以通过调用IDM来进行下载,速度嘎嘎快。

## 导入库:
```
from asyncio.windows_events import NULL
from math import ceil
import requests
import os
import json
import subprocess
from time import sleep
```

## 为了方便直接写一个类

```
class Wallhaven_master(requests.Session):

    def __init__(self):
      super(Wallhaven_master, self).__init__()
      self.APIKEY = 'apikey='
      self.logjson = []
      self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/527.36 (KHTML, like Gecko) Chrome/61.0.3143.79 Safari/527.36",
      }
      self.firurl = f"https://wallhaven.cc/api/v1/collections?{self.APIKEY}"
```
APIKEY里**填自己的**,毕竟是要下载自己收藏夹里的图片

## 若干个函数

### 获得键值
观察打开的api链接。需要比较频繁地获得键值,图方便就写了这个函数
参数key填字符串'mate'或者'data'
```
    def get_dict(self, url, key):
      '''
      获得字典中data键或mate键的键值
      '''
      r = self.get(url, headers=self.headers)
      req = r.json()
      sleep(5)
      dict = req
      return dict
```

### 调用IDM
IDMPath填自己的IDM安装路径
```
    def IDMdownload(self, DownUrl, DownPath, FileName):
      IDMPath = "D:\\Internet Download Manager\\IDMan.exe"
      command = f'"{IDMPath}" /d {DownUrl} /p "{DownPath}" /f {FileName} /n /a'
      subprocess.Popen(command)
```
因为硬盘太小下的图片有点多,所以没有写开始下载的命令,仅仅是把下载链接添加到下载队列里,如果有需要再手动点开始队列下载。

### 防止重复下载
我的思路是:因为图片名称是唯一的,所以把名称添加到一个列表中,然后保存在json文件中,每次下载前,检查列表中是否含有被下载图片的名称,有则跳过,以此来达到排重目的。
```
    def readjson(self):
      '''
      读取json文件中的已下载链接,若无则创建
      '''
      try:

            if os.path.isfile("WH-pics\\DownloadLog.json"):
                with open("WH-pics\\DownloadLog.json", 'r') as dl:
                  self.logjson = json.load(dl)
                  return self.logjson
            else:
                with open("WH-pics\\DownloadLog.json", 'a') as dl:
                  self.logjson = []
                  return self.logjson
      except:
            self.logjson = []
            return self.logjson
```

### 下载部分
```
    def Run(self):

      if not os.path.exists(("WH-pics")):
            os.mkdir(("WH-pics"))

      firdata = self.get_dict(self.firurl, "data")

      for col in firdata:
            colid = col["id"]
            label = col["label"]
            count = col["count"]
            origpath = os.path.abspath(".")
            flag = 1
            page = 1

            print(f"正在下载 {label} 中的图片,共 {count} 张")

            if not os.path.exists((f"WH-pics\\{colid}-{label}")):
                os.mkdir((f"WH-pics\\{colid}-{label}"))

            if not count:
                continue
            # 若收藏夹中图片数为0则跳过

            else:
                lastpage = ceil(count/24)
                while page <= lastpage:
                  securl = f"https://wallhaven.cc/api/v1/collections/id/{colid}?page={page}&{self.APIKEY}"

                  secdata = self.get_dict(securl, "data")

                  for picinfo in secdata:

                        picid = picinfo["id"]

                        if (picid in self.readjson()):
                            print(f"{str(flag).rjust(3)}*", end="   ")
                            if not (flag % 8):
                              print("")
                            flag += 1
                            sleep(1)
                            continue

                        picpath = picinfo["path"]
                        with open(f"WH-pics\\{colid}-{label}\\{colid}-{label}.txt", 'a+') as fl:
                            fl.write(f"{picpath}\n")

                        savepath = f"{origpath}\\WH-pics\\{colid}-{label}"
                        self.IDMdownload(picpath, savepath, NULL)

                        self.logjson.append(picid)
                        with open("WH-pics\\DownloadLog.json", 'w') as dl:
                            json.dump(self.logjson, dl)

                        print(f"{str(flag).rjust(3)}", end="    ")
                        if not (flag % 8):
                            print("")
                        flag += 1
                        sleep(1)

                  page += 1# 当前页数+1

                print(f"\n{label} 中的图片链接已全部写入\n\n")
```
因为这个网站设置的是每页是24张图片,然后为了便于观察运行结果,加了点提示信息,每个收藏夹里每下载一张图片,输出序号,每8个换一次行,如果是已下载的图片则会在序号后面输出*。
> 正在下载 xxxxxx 中的图片,共 39 张
1      2      3\*   4\*   5\*   6\*   7\*   8\*


最后创建一个实例,运行函数.Run()就可以了,开始愉快爬图


### 结尾
网站调用api有速度限制,为了保险所以设置的速度比较慢,耐心等待就好
页: [1]
查看完整版本: 爬虫-调用IDM利用API来快速下载Wall Haven账号收藏夹中的图片