├── .gitignore ├── Dockerfile ├── Images ├── readme.txt ├── wallhaven-dl (1).gif └── wallhaven-dl.gif ├── LICENSE ├── README.md ├── requirements.txt └── wallhaven-dl.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | 91 | # folder with images 92 | Wallhaven 93 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3 2 | 3 | RUN mkdir -p /Wallhaven-dl/Wallhaven 4 | WORKDIR /Wallhaven-dl 5 | 6 | COPY requirements.txt ./ 7 | RUN pip install --no-cache-dir -r requirments.txt 8 | 9 | COPY . . 10 | 11 | VOLUME /Wallhaven-dl/Wallhaven 12 | 13 | CMD [ "python", "./wallhaven-dl.py" ] 14 | -------------------------------------------------------------------------------- /Images/readme.txt: -------------------------------------------------------------------------------- 1 | These are the GIFs for the screenshot section. 2 | -------------------------------------------------------------------------------- /Images/wallhaven-dl (1).gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saurabhan/Wallhaven-dl/67822062c862bb7e9ffb71ff44950064bbebc3fa/Images/wallhaven-dl (1).gif -------------------------------------------------------------------------------- /Images/wallhaven-dl.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saurabhan/Wallhaven-dl/67822062c862bb7e9ffb71ff44950064bbebc3fa/Images/wallhaven-dl.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Saurabh Bhan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Wallhaven-dl 2 | 3 | ## UPDATE 4 | ###The script now comes with a search functionality, you can now search and download wallpapers from the command line. 5 | 6 | --------------------------------------------------------------------- 7 | 8 | A wallhaven scraper which downloads all the wallpapers from the first page of [alpha.wallhaven.cc](http://alpha.wallhaven.cc/) 9 | 10 | This Script now comes with categories and purity sort support. 11 | ###### NOTE- Downloading NSFW images require a [Wallhaven Account](https://alpha.wallhaven.cc/user/create) 12 | 13 | 14 | ![](https://raw.githubusercontent.com/GeekSpin/Wallhaven-dl/master/Images/wallhaven-dl%20(1).gif) 15 | 16 | ## How to use: 17 | 18 | 1. Download the wallhaven-dl.py 19 | 2. Move wallhaven-dl.py to the folder in which you want wallpapers to download. 20 | 3. run script 21 | 4. It'll ask you to choose a category, download the latest wallpapers or search, choose as per desired. 22 | 5. enjoy! 23 | ``` 24 | $ python3 wallhaven-dl.py 25 | ``` 26 | 27 | ## Dependencies: 28 | 29 | This project depends on BeautifulSoup, Requests, tqdm, lxml 30 | Your can install install the dependencies using the requirements.txt file and running 31 | ``` 32 | $ pip3 install -r requirements.txt 33 | ``` 34 | 35 | 36 | 37 | Wallhaven-dl © 2016, Saurabh Bhan. Released under the [MIT License](https://raw.githubusercontent.com/GeekSpin/Wallhaven-scraper/master/LICENSE). 38 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | beautifulsoup4==4.4.1 2 | bs4==0.0.1 3 | lxml==4.6.3 4 | requests==2.20.0 5 | tqdm==4.7.6 6 | -------------------------------------------------------------------------------- /wallhaven-dl.py: -------------------------------------------------------------------------------- 1 | ######################################################## 2 | # Program to Download Wallpapers from # 3 | # alpha.wallhaven.cc # 4 | # # 5 | # Author - Saurabh Bhan # 6 | # # 7 | # Dated- 26 June 2016 # 8 | # Update - 11 June 2019 # 9 | ######################################################## 10 | 11 | import os 12 | import getpass 13 | import re 14 | import requests 15 | import tqdm 16 | import time 17 | import urllib 18 | import json 19 | 20 | os.makedirs('Wallhaven', exist_ok=True) 21 | BASEURL="" 22 | cookies=dict() 23 | 24 | global APIKEY 25 | APIKEY = "EnterYourAPIKeyHere" 26 | 27 | def category(): 28 | global BASEURL 29 | print(''' 30 | **************************************************************** 31 | Category Codes 32 | 33 | all - Every wallpaper. 34 | general - For 'general' wallpapers only. 35 | anime - For 'Anime' Wallpapers only. 36 | people - For 'people' wallapapers only. 37 | ga - For 'General' and 'Anime' wallapapers only. 38 | gp - For 'General' and 'People' wallpapers only. 39 | **************************************************************** 40 | ''') 41 | ccode = input('Enter Category: ').lower() 42 | ctags = {'all':'111', 'anime':'010', 'general':'100', 'people':'001', 'ga':'110', 'gp':'101' } 43 | ctag = ctags[ccode] 44 | 45 | print(''' 46 | **************************************************************** 47 | Purity Codes 48 | 49 | sfw - For 'Safe For Work' 50 | sketchy - For 'Sketchy' 51 | nsfw - For 'Not Safe For Work' 52 | ws - For 'SFW' and 'Sketchy' 53 | wn - For 'SFW' and 'NSFW' 54 | sn - For 'Sketchy' and 'NSFW' 55 | all - For 'SFW', 'Sketchy' and 'NSFW' 56 | **************************************************************** 57 | ''') 58 | pcode = input('Enter Purity: ') 59 | ptags = {'sfw':'100', 'sketchy':'010', 'nsfw':'001', 'ws':'110', 'wn':'101', 'sn':'011', 'all':'111'} 60 | ptag = ptags[pcode] 61 | 62 | BASEURL = 'https://wallhaven.cc/api/v1/search?apikey=' + APIKEY + "&categories=" +\ 63 | ctag + '&purity=' + ptag + '&page=' 64 | 65 | def latest(): 66 | global BASEURL 67 | print('Downloading latest') 68 | topListRange = '1M' 69 | BASEURL = 'https://wallhaven.cc/api/v1/search?apikey=' + APIKEY + '&topRange=' +\ 70 | topListRange + '&sorting=toplist&page=' 71 | 72 | def search(): 73 | global BASEURL 74 | query = input('Enter search query: ') 75 | BASEURL = 'https://wallhaven.cc/api/v1/search?apikey=' + APIKEY + '&q=' + \ 76 | urllib.parse.quote_plus(query) + '&page=' 77 | 78 | def downloadPage(pageId, totalImage): 79 | url = BASEURL + str(pageId) 80 | urlreq = requests.get(url, cookies=cookies) 81 | pagesImages = json.loads(urlreq.content); 82 | pageData = pagesImages["data"] 83 | 84 | for i in range(len(pageData)): 85 | currentImage = (((pageId - 1) * 24) + (i + 1)) 86 | 87 | url = pageData[i]["path"] 88 | 89 | filename = os.path.basename(url) 90 | osPath = os.path.join('Wallhaven', filename) 91 | if not os.path.exists(osPath): 92 | imgreq = requests.get(url, cookies=cookies) 93 | if imgreq.status_code == 200: 94 | print("Downloading : %s - %s / %s" % (filename, currentImage , totalImage)) 95 | with open(osPath, 'ab') as imageFile: 96 | for chunk in imgreq.iter_content(1024): 97 | imageFile.write(chunk) 98 | elif (imgreq.status_code != 403 and imgreq.status_code != 404): 99 | print("Unable to download %s - %s / %s" % (filename, currentImage , totalImage)) 100 | else: 101 | print("%s already exist - %s / %s" % (filename, currentImage , totalImage)) 102 | 103 | def main(): 104 | Choice = input('''Choose how you want to download the image: 105 | 106 | Enter "category" for downloading wallpapers from specified categories 107 | Enter "latest" for downloading latest wallpapers 108 | Enter "search" for downloading wallpapers from search 109 | 110 | Enter choice: ''').lower() 111 | while Choice not in ['category', 'latest', 'search']: 112 | if Choice != None: 113 | print('You entered an incorrect value.') 114 | choice = input('Enter choice: ') 115 | 116 | if Choice == 'category': 117 | category() 118 | elif Choice == 'latest': 119 | latest() 120 | elif Choice == 'search': 121 | search() 122 | 123 | pgid = int(input('How Many pages you want to Download: ')) 124 | totalImageToDownload = str(24 * pgid) 125 | print('Number of Wallpapers to Download: ' + totalImageToDownload) 126 | for j in range(1, pgid + 1): 127 | downloadPage(j, totalImageToDownload) 128 | 129 | if __name__ == '__main__': 130 | main() 131 | --------------------------------------------------------------------------------