├── src ├── __init__.py ├── bot │ ├── __init__.py │ ├── done_pins.json │ ├── runtime.txt │ ├── Aptfile │ ├── requirements.txt │ ├── test.py │ ├── pinterestBot.json │ ├── follow_users_boards.py │ ├── create_post_from_provided.py │ ├── unfollow_users_boards.py │ └── core.py └── insta │ ├── insta_unfollow.py │ ├── README.md │ └── insta_follow_like_comment.py ├── requirements.txt ├── installdeps.sh ├── LICENSE ├── .gitignore └── README.md /src/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/bot/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/bot/done_pins.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /src/bot/runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.6.1 2 | -------------------------------------------------------------------------------- /src/bot/Aptfile: -------------------------------------------------------------------------------- 1 | webp 2 | libhyphen0 3 | https://mirrors.kernel.org/ubuntu/pool/main/g/gcc-5/gcc-5_5.4.1-8ubuntu1_amd64.deb 4 | https://mirrors.kernel.org/ubuntu/pool/main/g/gcc-5/libstdc++6_5.4.0-6ubuntu1~16.04.4_amd64.deb 5 | python3-pip 6 | -------------------------------------------------------------------------------- /src/bot/requirements.txt: -------------------------------------------------------------------------------- 1 | billiard==3.5.0.2 2 | certifi==2017.4.17 3 | chardet==3.0.4 4 | click==6.7 5 | idna==2.5 6 | itsdangerous==0.24 7 | kombu==4.0.2 8 | MarkupSafe==1.0 9 | pytz==2017.2 10 | requests==2.18.1 11 | selenium==3.4.3 12 | urllib3==1.21.1 13 | vine==1.1.3 14 | -------------------------------------------------------------------------------- /src/bot/test.py: -------------------------------------------------------------------------------- 1 | from core import pinBot 2 | bot=pinBot() 3 | bot.createPost('http://i.imgur.com/Z3fM3in.jpg','a hoola new') 4 | #a.followBoard('philippawestlee/must-have') 5 | #print(a.getFollowingBoards()) 6 | #print(a.getFollowingUsers()) 7 | #ids,users = a.search('pooop','board',2) 8 | #print(users) 9 | #print("*****") 10 | #print(ids) 11 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | amqp==2.1.4 2 | beautifulsoup4==4.6.0 3 | billiard==3.5.0.2 4 | bs4==0.0.1 5 | celery==4.0.2 6 | certifi==2017.4.17 7 | chardet==3.0.4 8 | click==6.7 9 | Flask==0.12.2 10 | idna==2.5 11 | itsdangerous==0.24 12 | Jinja2==2.9.6 13 | kombu==4.0.2 14 | MarkupSafe==1.0 15 | pytz==2017.2 16 | requests==2.18.1 17 | selenium==3.4.3 18 | urllib3==1.21.1 19 | vine==1.1.3 20 | Werkzeug==0.12.2 21 | -------------------------------------------------------------------------------- /src/insta/insta_unfollow.py: -------------------------------------------------------------------------------- 1 | from instapy import InstaPy 2 | 3 | # `.unfollow_users` don't give amount more than 10 4 | # see here: https://github.com/timgrossmann/InstaPy#unfollowing 5 | # also, i am assuming this s a account that will be run only for the bot 6 | # so I am not setting `onlyInstapyFollowed` to False, this will follow any 10 users from all the following users 7 | 8 | InstaPy(username="geekodour",password="strongpassword",nogui=True)\ 9 | .login()\ 10 | .unfollow_users(amount=10, onlyInstapyFollowed = False ) \ 11 | .end() 12 | -------------------------------------------------------------------------------- /src/bot/pinterestBot.json: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "scrolls": 5, 4 | "follow": 5, 5 | "unfollow": 10 6 | }, 7 | "pin": { 8 | "scrolls": 5, 9 | "save": 5 10 | }, 11 | "user": { 12 | "follow": 4, 13 | "unfollow": 10 14 | }, 15 | "periods": { 16 | "post_to_post_per_day": 2, 17 | "follow_freq_per_day": 2, 18 | "unfollow_freq_per_week": 2 19 | }, 20 | "posts": [ 21 | {"note":"I am a desc","imageUrl":"http://i.imgur.com/pAiW6Ta.jpg"}, 22 | {"note":"I am a desc","imageUrl":"http://i.imgur.com/QjR7N6z.jpg"}, 23 | {"note":"I am a desc","imageUrl":"http://i.imgur.com/1OBA5hu.jpg"}, 24 | {"note":"I am a desc","imageUrl":"http://i.imgur.com/ZviYBqu.jpg"}, 25 | {"note":"I am a desc","imageUrl":"http://i.imgur.com/oylBqOd.jpg"} 26 | ], 27 | "search_terms": [ 28 | "happy" 29 | ] 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/bot/follow_users_boards.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import random 4 | import time 5 | import os 6 | from core import pinBot 7 | 8 | bot_dir = os.path.dirname(__file__) 9 | with open(os.path.join(bot_dir,'pinterestBot.json')) as json_data: 10 | bot_config = json.load(json_data) 11 | 12 | bot = pinBot() 13 | # please note, user.follow and board.follow will be repeated for each search term 14 | # so, if you have 10 user follows and 5 search terms you'll end up follwing 50 users 15 | # and 50 boards, which might seem fish to pintrest, so adjust that accordingly 16 | for term in bot_config['search_terms']: 17 | boardIds,users = bot.search(term,'board',bot_config['board']['scrolls']) 18 | # follow users 19 | for user in random.sample(users,bot_config['user']['follow']): 20 | bot.followUser(user) 21 | time.sleep(1) # maybe randomize 22 | # follow boards 23 | for board in random.sample(boardIds,bot_config['board']['follow']): 24 | bot.followBoard(board) 25 | time.sleep(1) # maybe randomize 26 | -------------------------------------------------------------------------------- /installdeps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | apt-get update 3 | #apt-get install -y libfontconfig rabbitmq-server python3-pip git 4 | apt-get install -y libfontconfig git python3-pip 5 | 6 | getPhantom(){ 7 | cd /usr/bin/ 8 | wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2 9 | tar xvf phantomjs-2.1.1-linux-x86_64.tar.bz2 10 | cp phantomjs-2.1.1-linux-x86_64/bin/phantomjs . 11 | cd ~ 12 | } 13 | 14 | getPhantom 15 | 16 | #pip3 install virtualenv 17 | 18 | git clone https://github.com/geekodour/pinterest-dashbot.git 19 | 20 | installDeps(){ 21 | cd pinterest-dashbot/ 22 | pip3 install -r requirements.txt 23 | } 24 | 25 | installDeps 26 | 27 | #genEnv(){ 28 | #cd pinterest-dashbot/ 29 | #virtualenv env 30 | #. env/bin/activate 31 | #pip install -r requirements.txt 32 | #deactivate 33 | #} 34 | #genEnv 35 | #setupRabbit(){ 36 | #rabbitmqctl add_user pin pinpin 37 | #rabbitmqctl add_vhost pinvh 38 | #rabbitmqctl set_user_tags pin pintag 39 | #rabbitmqctl set_permissions -p pinvh pin ".*" ".*" ".*" 40 | #} 41 | #setupRabbit 42 | -------------------------------------------------------------------------------- /src/bot/create_post_from_provided.py: -------------------------------------------------------------------------------- 1 | import json 2 | import random 3 | import time 4 | import os 5 | from core import pinBot 6 | 7 | bot = pinBot() 8 | 9 | bot_dir = os.path.dirname(__file__) 10 | with open(os.path.join(bot_dir,'pinterestBot.json')) as json_data: 11 | bot_config = json.load(json_data) 12 | 13 | with open(os.path.join(bot_dir,'done_pins.json')) as json_data: 14 | done_pins = json.load(json_data) 15 | 16 | # generate posts to post 17 | pin_upload_count = bot_config['periods']['post_to_post_per_day'] 18 | available_posts = list(filter(lambda x: x['imageUrl'] not in done_pins ,bot_config['posts'])) 19 | 20 | if len(available_posts) <= pin_upload_count: 21 | pin_upload_count = len(available_posts) 22 | 23 | if len(available_posts)>0: 24 | for post in random.sample(available_posts,pin_upload_count): 25 | bot.createPost(post['imageUrl'],post['note']) 26 | time.sleep(1) 27 | done_pins.append(post['imageUrl']) 28 | 29 | with open(os.path.join(bot_dir,'done_pins.json'), 'w') as outfile: 30 | json.dump(done_pins, outfile) 31 | -------------------------------------------------------------------------------- /src/bot/unfollow_users_boards.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import random 4 | import time 5 | from core import pinBot 6 | 7 | bot_dir = os.path.dirname(__file__) 8 | with open(os.path.join(bot_dir,'pinterestBot.json')) as json_data: 9 | bot_config = json.load(json_data) 10 | 11 | bot = pinBot() 12 | followingUsers = bot.getFollowingUsers() 13 | followingBoards = bot.getFollowingBoards() 14 | 15 | # fix number of users and boards to unfollow 16 | user_unfollow_count = bot_config['user']['unfollow'] 17 | board_unfollow_count = bot_config['user']['unfollow'] 18 | 19 | if len(followingUsers) <= user_unfollow_count: 20 | user_unfollow_count = len(followingUsers) 21 | 22 | if len(followingBoards) <= board_unfollow_count: 23 | board_unfollow_count = len(followingBoards) 24 | 25 | # unfollow random users 26 | for user in random.sample(followingUsers,user_unfollow_count): 27 | time.sleep(1) 28 | bot.unfollowUser(user) 29 | 30 | # unfollow random boards 31 | for board in random.sample(followingBoards,board_unfollow_count): 32 | time.sleep(1) 33 | bot.unfollowBoard(board) 34 | -------------------------------------------------------------------------------- /src/insta/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | $ apt-get install git 3 | $ git clone https://github.com/timgrossmann/InstaPy.git 4 | $ cd InstaPy/scripts/ 5 | $ ./unix.sh 6 | ``` 7 | after the installation is done, copy `./insta_follow_like_comment.py` and `./insta_unfollow.py` from this directory(`/src/insta/`) to the (`InstaPy/`) directory. 8 | now navigate to the root directory of `InstaPy`(the cloned diretory), you should see the two follow and unfollow scripts that you just copied there along with other files and directory. 9 | they do what they are named, sufficient comments are added to both the files to explain how to configure it, so please read both the files to understand how to configure. 10 | 11 | ## conjobs 12 | you can put the two scripts on cron 13 | the guide is here: https://github.com/timgrossmann/InstaPy#automate 14 | an example: 15 | this will run the follow script at 4:45 and the unfollow script at 3:45 16 | 17 | ``` 18 | 45 4 * * * cd /home/user/InstaPy && /usr/bin/python3 ./insta_follow_like_comment.py 19 | 45 3 * * * cd /home/user/InstaPy && /usr/bin/python3 ./insta_unfollow.py 20 | ``` 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/insta/insta_follow_like_comment.py: -------------------------------------------------------------------------------- 1 | from instapy import InstaPy 2 | 3 | # in `link_by_tags` the `amounts` refers to how many pictures of 4 | # each search results should the bot interact with 5 | # if `search_term` has 2 terms in it, and amounts is set to 2 6 | # then the bot will interact with 2*2=4 pictures total 7 | 8 | # the bot will comment if `.set_do_comment` is True as in the following example 9 | # the bot will follow if `.set_do_follow` is True as in the following example 10 | 11 | # the comment and follow percentages are set accordingly in the `.set_do*` methods, if you are interacting with more 12 | # pictures, you'll want to lower the percentage, here the percentage is set to 100 because we're 13 | # only interacting with 4 pictures anyway 14 | 15 | search_terms = ['#cat','#dog'] 16 | ignore_words = ['#bbf'] 17 | comments_pool = ['Cool!', 'Awesome!', 'Nice!'] 18 | 19 | InstaPy(username="geekodour",password="strongpassword",nogui=True)\ 20 | .login()\ 21 | .set_do_follow(enabled=True, percentage=100, times=2) \ 22 | .set_do_comment(True, percentage=100) \ 23 | .set_comments(comments_pool) \ 24 | .set_ignore_if_contains(ignore_words) \ 25 | .like_by_tags(search_terms, amount=2) \ 26 | .end() 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /.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 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | -------------------------------------------------------------------------------- /src/bot/core.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf8 -*- 3 | import requests 4 | import time 5 | from urllib.parse import urlparse 6 | from selenium import webdriver 7 | from selenium.webdriver.common.desired_capabilities import DesiredCapabilities 8 | import re 9 | 10 | # user agent settings 11 | dcap = dict(DesiredCapabilities.PHANTOMJS) 12 | dcap["phantomjs.page.settings.userAgent"] = ( 13 | "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/53 " 14 | "(KHTML, like Gecko) Chrome/15.0.87" 15 | ) 16 | 17 | ACCESS_TOKEN = 'AbVZ6pBecrXC9afBG9mahRCxS8NuFM2MA50rraBEIg4xUYA_VwAAAAA' 18 | 19 | class pinBot(): 20 | def __init__(self): 21 | self.baseUrl = 'https://in.pinterest.com' 22 | self.apiUrl = 'https://api.pinterest.com/v1/' 23 | 24 | def search(self,keyword,searchType,scrolls): 25 | # todo: urlquote keyword 26 | ids = [] 27 | users = [] 28 | if(searchType=='pin'): 29 | pinDriver = webdriver.PhantomJS(desired_capabilities=dcap) 30 | pinDriver.get( self.baseUrl + r'/search/pins/?q=' + keyword ) 31 | pinEls = [] 32 | 33 | while scrolls: 34 | pinDriver.execute_script("return window.scrollTo(0, document.body.scrollHeight);") 35 | time.sleep(5) 36 | scrolls-=1 37 | 38 | pinEls.extend(pinDriver.find_elements_by_css_selector('.pinImageWrapper')) 39 | for pin in pinEls: 40 | ids.append(re.search('\d+',pin.get_attribute('href')).group()) 41 | pinDriver.quit() 42 | return list(set(ids)) 43 | 44 | elif(searchType=='board'): 45 | boardDriver = webdriver.PhantomJS(desired_capabilities=dcap) 46 | boardDriver.get( self.baseUrl + r'/search/boards/?q=' + keyword ) 47 | boardEls = [] 48 | 49 | while scrolls: 50 | boardDriver.execute_script("return window.scrollTo(0, document.body.scrollHeight);") 51 | time.sleep(5) 52 | scrolls-=1 53 | 54 | boardEls.extend(boardDriver.find_elements_by_css_selector('.boardLinkWrapper')) 55 | for board in boardEls: 56 | boardData = urlparse(board.get_attribute('href')).path.split('/')[1:3] 57 | ids.append( '/'.join(boardData) ) 58 | users.append(boardData[0]) 59 | boardDriver.quit() 60 | return (list(set(ids)),list(set(users))) 61 | else: 62 | raise "something happened" 63 | 64 | def followUser(self,userId): 65 | params = [ 'access_token='+ACCESS_TOKEN, 'user='+userId] 66 | r = requests.post(self.apiUrl+'me/following/users/?'+'&'.join(params)) 67 | 68 | def unfollowUser(self,userId): 69 | params = [ 'access_token='+ACCESS_TOKEN ] 70 | r = requests.delete(self.apiUrl+'me/following/users/'+userId+'?'+'&'.join(params)) 71 | 72 | def followBoard(self,boardId): 73 | params = [ 'access_token='+ACCESS_TOKEN, 'board='+boardId] 74 | r = requests.post(self.apiUrl+'me/following/boards/?'+'&'.join(params)) 75 | 76 | def unfollowBoard(self,boardId): 77 | params = [ 'access_token='+ACCESS_TOKEN ] 78 | r = requests.delete(self.apiUrl+'me/following/boards/'+boardId+'?'+'&'.join(params)) 79 | 80 | def getFollowingBoards(self): 81 | params = [ 'access_token='+ACCESS_TOKEN ] 82 | r = requests.get(self.apiUrl+'me/following/boards/?'+'&'.join(params)) 83 | extract_board_name = lambda x: '/'.join(urlparse(x['url']).path.split('/')[1:3]) 84 | return list(map(extract_board_name ,r.json()['data'])) 85 | 86 | def getFollowingUsers(self): 87 | params = [ 'access_token='+ACCESS_TOKEN ] 88 | r = requests.get(self.apiUrl+'me/following/users/?'+'&'.join(params)) 89 | extract_username = lambda x: urlparse(x['url']).path.strip('/') 90 | return list(map(extract_username ,r.json()['data'])) 91 | 92 | def savePin(self,pinId): 93 | # save pin method is not implemented yet 94 | params = [ 'access_token='+ACCESS_TOKEN ] 95 | r = requests.patch(self.apiUrl+'me/following/users/'+userId+'?'+'&'.join(params)) 96 | 97 | def createPost(self,imageUrl,imageDesc): 98 | params = [ 'access_token='+ACCESS_TOKEN ] 99 | r = requests.post(self.apiUrl+'pins/?'+'&'.join(params),data={'board':'hrishikeshbarma/pinboard','note':imageDesc, 'image_url': imageUrl}) 100 | print(r.status_code) 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pinterest-dashbot 2 | 3 | ## Requirements 4 | - Read & Understand Pinterest API. ( https://developers.pinterest.com/docs/api/users/?) 5 | - Write a script to specifically ( interest based) auto follow/auto unfollow boards, users and 6 | save pins on a daily basis. 7 | - Write a script to automate daily Pinterest Postings. All the content will be given. 8 | 9 | ## Note 10 | if you directly run the script on a fast server using `python ` it will seem slow because of the delays introduced in the script. 11 | 12 | # Installation 13 | In a server, wget this install script [`installdeps.sh`](https://raw.githubusercontent.com/geekodour/pinterest-dashbot/master/installdeps.sh) 14 | it will just install all the required dependencies(some dependencies are not needed, but installed). 15 | 16 | ``` 17 | $ wget https://raw.githubusercontent.com/geekodour/pinterest-dashbot/master/installdeps.sh 18 | $ chmod u+x installdeps.sh 19 | $ ./installdeps.sh 20 | ``` 21 | 22 | - The script is using my `ACCESS_TOKEN`, to use it with your account you have to generate a token from [here](https://developers.pinterest.com/tools/access_token/) just make sure you give it all `4` scopes. 23 | - The script containing the `ACCESS_TOKEN` is `/src/bot/core.py` 24 | - after updating the token with your token 25 | - you can run the scripts by using `python3 ` or `python `, (needs python3) 26 | - there are **three** primary scripts, *(save pins script is not here)* 27 | - create_post_from_provided.py 28 | - follow_users_boards.py 29 | - unfollow_users_boards.py 30 | - these three scripts need to run as required. running them periodically can done using cronjobs, celery other alternatives, will be using cronjobs for now(discussed later). 31 | - these three scripts use data from `src/bot/pintrestBot.json` where all configuration is stored. 32 | 33 | Here is a sample of a `pinterestBot.json` file 34 | ```json 35 | { 36 | "board": { 37 | "scrolls": 5, 38 | "follow": 5, 39 | "unfollow": 10 40 | }, 41 | "pin": { 42 | "scrolls": 5, 43 | "save": 5 // no use now 44 | }, 45 | "user": { 46 | "follow": 4, 47 | "unfollow": 10 48 | }, 49 | "periods": { 50 | "post_to_post_per_day": 2, 51 | "follow_freq_per_day": 2, // no use now 52 | "unfollow_freq_per_week": 2 // no use now 53 | }, 54 | "posts": [ 55 | {"note":"I am a desc","imageUrl":"http://i.imgur.com/pAiW6Ta.jpg"}, 56 | {"note":"I am a desc","imageUrl":"http://i.imgur.com/oylBqOd.jpg"} 57 | ], 58 | "search_terms": [ "happy" ] 59 | } 60 | ``` 61 | **three** fields are of no use as of now, they are commented in the above snippet. 62 | 63 | there is another file in the `/src/bot/` directory called `done_pins.json`, it contains a list done imageUrls that are already uploaded. you don't have to update that, `create_post_from_provided.py` will update and use it to not upload the same image twice. Also, initially the `done_pins.json` file should look like this, just an empty array. 64 | ``` 65 | [] 66 | ``` 67 | 68 | ## Usage 69 | 70 | ### create_post_from_provided.py 71 | takes in `posts` from `pinterestBot.json` checks with if the imageUrl is in `done_pins.json` 72 | if not then uploads the pin with the given `note`. 73 | - `python3 create_post_from_provided.py` 74 | - okay if ran twice a day with `periods.posts_to_post_per_day` less than 4 (just a guess) 75 | 76 | ### follow_users_boards.py 77 | searches pinterest once for each term in the `search_terms` array in `pinterestBot.json` then 78 | scrolls `board.scrolls` times and gathers all the boards and their users. 79 | Then follows boards and users based on how many users and boards to follow from `board.follow` and `user.follow` 80 | - `python3 follow_users_boards.py` 81 | - okay if ran once a day with 2 or less `term` elements in `search_terms` and `board.follow` and `user.follow` set to less than 10 82 | - Important note: in pinterest, if you follow a board, you automatically follow the user 83 | - also, `scrolls` is the number of times the page is scrolled in pinterest infinite scroll pages, the lesser the faster results you'll get 84 | 85 | 86 | ### unfollow_users_boards.py 87 | gets all the following boards and users, then unfollows them based on `board.unfollow` and `user.unfollow` 88 | - `python3 unfollow_users_boards.py` 89 | - okay if ran twice a week or something 90 | 91 | ## cronjobs 92 | 93 | use `crontab -e` and put these lines in the bottom, just change the path to where you have kept the script 94 | you can change the timings too, 95 | 96 | - `create_post_from_provided` runs at 2:30am and 3:30pm everyday. 97 | - `follow_users_boards` runs at 5:25am and 5:25pm everyday. 98 | - `unfollow_users_boards` runs at 1:30am every week on sundays. 99 | 100 | ``` 101 | 30 2,15 * * * python3 /root/pinterest-dashbot/src/bot/create_post_from_provided.py 102 | 25 5,17 * * * python3 /root/pinterest-dashbot/src/bot/follow_users_boards.py 103 | 30 1 * * 0 python3 /root/pinterest-dashbot/src/bot/unfollow_users_boards.py 104 | ``` 105 | 106 | ## Instruction for heroku 107 | 108 | The bot needs a few `buildpackages` in Heroku, buildpackages are just dependencies that you can install from packagemanager in traditional server boxes. 109 | the dependencies are: 110 | 111 | buildpackages 112 | ``` 113 | https://github.com/heroku/heroku-buildpack-apt (apt-get package) 114 | heroku/python (official python) 115 | https://github.com/geekodour/heroku-buildpack-phantomjs (custom phantomjs) 116 | ``` 117 | 118 | if the heroku app is not already created you can do `heroku create`, in our case it's already created. 119 | so there's a remote link to a heroku git repository, if you cloned this repository there won't be a remote link to heroku, you'll have to explitly set that. 120 | to do that do: 121 | 122 | ``` 123 | git remote add heroku https://git.heroku.com/pinstabot.git 124 | 125 | ``` 126 | 127 | after doing that we can start pushing changes to our heroku app. but before that, we need to put in our buildpackages in place. 128 | you can do that `https://dashboard.heroku.com/apps/pinstabot/settings` page, just click `add buildpack` and put in the above links one by one. 129 | Another way to do the same is from the command line(please do a check on `heroku/python`, it should work from the command line, it works perfectly from the heroku webapp): 130 | 131 | ``` 132 | heroku buildpacks:add https://github.com/heroku/heroku-buildpack-apt 133 | heroku buildpacks:add heroku/python 134 | heroku buildpacks:add https://github.com/geekodour/heroku-buildpack-phantomjs 135 | ``` 136 | 137 | after the `buildpacks` are added, it's time to push our changes, I've added a file named `Aptfile` inside `/src/bot`. Heroku will use that file to install dependencies. 138 | 139 | update any changes, for example if you change configurations in `/src/bot/pinterestBot.json` 140 | 141 | type in the following commands from project root 142 | ``` 143 | git add -A 144 | git commit -m 'i am commit message' 145 | git push origin master (optional) 146 | git subtree push --prefix src/bot heroku master 147 | ``` 148 | 149 | The git subtree command puts the `src/bot` directory as the root directory for your app in heroku, after the last command, the heroku deploy should be successful and there will be an `application error` shown in the **browser** if you try to go to the heroku link, this is fine because it's not a webapp/website. 150 | 151 | now to run the scripts you can simply do 152 | 153 | ``` 154 | heroku run python create_post_from_provided.py 155 | heroku run python follow_users_boards.py 156 | heroku run python unfollow_users_boards.py 157 | ``` 158 | 159 | Now if you want to change the frequency or follow count or something, you can just update the `src/bot/pinterestBot.json` file accordingly and `git push` it using the subtree command. 160 | To run these three scripts periodically, you can use the `herokuscheduler` addon that has been already installed on the app, the same commands will work for the scheduler. 161 | i.e, these 3 are valid commands for the scheduler, just set the timing as you wish. 162 | 163 | ``` 164 | python create_post_from_provided.py 165 | python follow_users_boards.py 166 | python unfollow_users_boards.py 167 | ``` 168 | --------------------------------------------------------------------------------