#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
########################################################################
####### Pinterest P!nBoT from a True LinuxLover ♥ ###########
########################################################################
# This program can be freely used, copied, derived
# and redistributed by anyone.
#
# While loading pinterest, this will eat your system memory :(
# So Please dont use this if you have only 512 MB or below Ram.
# BCoz, Pinterest is designed for chrome, not for firefox.
########################################################################
### Install Dependencies: ###########
### python, python-webkit, python-beautifulsoup, ###########
### wmctrl, Gtk2-engines-pixbuf ###########
########################################################################
import splinter
import string
import requests
import json
import ast
import subprocess
import pygtk
import re
import urllib2
pygtk.require('2.0')
import sys
import threading
import time
import socket
from BeautifulSoup import BeautifulSoup
from gi.repository import Gtk, Gdk
from gi.repository import GObject, GLib
pin_array = []
### Enable logging ###
## This will create a log file inside the current directory with
## file name 'log.txt'
class Logger(object):
def __init__(self):
self.terminal = sys.stdout
self.log = open("log.txt", "w")
def write(self, message):
self.terminal.write(message)
self.log.write(message)
self.terminal.flush()
self.log.flush()
sys.stdout = Logger()
sys.stderr = Logger()
### PinBot Starts ###
class pinbot:
def __init__(self):
self.StopPinning = False
self.isLoggedIn = False
self.iSPinGrabbed = False
self.TotalNoPins = None
self.ProgressBarStop = False
self.iSBoardAssigned = False
self.PinterestUserName = ""
self.GtkChangeStyle()
self.CheckIfAlreadyAfireFox()
self.splinter_init()
self.plug_id()
self.create_interior()
self.attach_socket(self.win_id)
self.window.show_all()
### Create GUI and Widget Packing
def create_interior(self):
self.window = Gtk.Window()
self.window.set_default_size(1024, 700)
self.window.connect("delete-event", Gtk.main_quit)
self.window.set_border_width(0)
self.mainvbox = Gtk.VBox(False, 0)
self.separator = Gtk.HSeparator()
self.LoginSeparator = Gtk.HSeparator()
self.HboxLogin = Gtk.HBox(False, 0)
self.hbox = Gtk.HBox(False, 0)
self.UserNameEntry = Gtk.Entry()
self.UserNameEntry.set_placeholder_text("Username")
self.UserNameEntry.set_size_request(125, 25)
self.PasswordEntry = Gtk.Entry()
self.PasswordEntry.set_placeholder_text("Password")
self.PasswordEntry.set_size_request(125, 25)
self.PasswordEntry.set_visibility(False)
self.LoginBtn = Gtk.Button("Login")
self.LoginBtn.set_size_request(70, 30)
self.LoginBtn.connect( "clicked", self.LoginThreadStart)
self.LogoutBtn = Gtk.Button("Logout")
self.LogoutBtn.set_size_request(70, 30)
self.LogoutBtn.set_sensitive(False)
self.LogoutBtn.connect( "clicked", self.LogOutThreadStart)
self.DebugLabel = Gtk.Label("♥ PinBot Activated ♥")
self.search_entry = Gtk.Entry()
self.PinItBtn = Gtk.Button("Pin It")
self.PinItBtn.set_size_request(70, 30)
self.PinItBtn.connect( "clicked", self.PinItThreadStart)
self.StopButton = Gtk.Button("STOP")
self.StopButton.set_size_request(70, 30)
self.StopButton.set_sensitive(False)
self.StopButton.connect( "clicked", self.StopBtnPressed)
self.search_btn = Gtk.Button("Search")
self.search_btn.set_size_request(70, 30)
self.search_btn.connect( "clicked", self.PinSearchThread)
self.FetchBtn = Gtk.Button("Refresh")
self.FetchBtn.set_size_request(70, 30)
self.FetchBtn.connect( "clicked", self.FetchBoardsByApi)
self.btn2 = Gtk.ToggleButton("Fetch Pins")
self.btn2.set_size_request(80, 30)
self.btn2.connect( "clicked", self.scroll_down)
self.ProgressBar = Gtk.ProgressBar()
self.ProgressBar.set_size_request(70, 20)
HeaderBar = Gtk.HeaderBar()
HeaderBar.set_show_close_button(True)
HeaderBar.props.title = "♚ P!nBoT ♚ By Pr0H4ck3R"
self.window.set_titlebar(HeaderBar)
FooterBar = Gtk.HeaderBar()
self.combo_board = Gtk.ComboBoxText.new()
self.combo_board.connect("changed", self.PinBoardChanged)
self.combo_board.append_text("Select Board")
self.combo_board.set_active(0)
self.window.add(self.mainvbox)
self.HboxLogin.pack_start(self.UserNameEntry, False, False, 10)
self.HboxLogin.pack_start(self.PasswordEntry, False, False, 5)
self.HboxLogin.pack_start(self.LoginBtn, False, False, 5)
self.HboxLogin.pack_start(self.LogoutBtn, False, False, 5)
self.HboxLogin.pack_start(self.DebugLabel, False, False, 50)
self.HboxLogin.pack_end(self.ProgressBar, False, False, 10)
self.HboxLogin.set_visible(False)
self.hbox.pack_start(self.search_entry, False, False, 10)
self.hbox.pack_start(self.search_btn, False, False, 1)
self.hbox.pack_start(self.btn2, False, False, 1)
self.hbox.pack_start(self.combo_board, False, False, 1)
self.hbox.pack_start(self.FetchBtn, False, False, 1)
self.hbox.pack_start(self.PinItBtn, False, False, 5)
self.hbox.pack_end(self.StopButton, False, False, 10)
self.mainvbox.pack_start(self.HboxLogin, False, False, 5)
self.mainvbox.pack_start(self.LoginSeparator, False, True, 5)
self.mainvbox.pack_start(self.hbox, False, False, 0)
self.mainvbox.pack_start(self.separator, False, True, 5)
self.mainvbox.pack_end(FooterBar, False, True, 0)
### Check Internet connection
def iSNetConnected(self):
REMOTE_SERVER = "www.google.com"
try:
# see if we can resolve the host name -- tells us if there is
# a DNS listening
host = socket.gethostbyname(REMOTE_SERVER)
# connect to the host -- tells us if the host is actually
# reachable
s = socket.create_connection((host, 80), 2)
return True
except:
pass
return False
### Login button thread
def LoginThreadStart(self, btn):
isConnected = self.iSNetConnected()
UserName = self.UserNameEntry.get_text()
PassWord = self.PasswordEntry.get_text()
if not all([UserName, PassWord]):
print "Username and Password Empty"
self.UserNameEntry.grab_focus()
return
elif isConnected:
self.ProgressBarStop = False
GObject.timeout_add(100, self.UpdateProgressBar)
print "Trying to Login"
self.DebugLabel.set_label("Trying to Login....")
thread = threading.Thread(target=self.PinterestLogin,
args=(btn, UserName, PassWord, self.ProgressBarStop))
thread.daemon = True
thread.start()
print thread
else:
print "Connection Lost"
self.DebugLabel.set_label("Internet Connection Lost!!!")
alert_message = "Please check the internet connection! "
self.DisplayAlert(self, alert_message)
#self.ProgressBarStop = False
#GObject.timeout_add(450, self.UpdateProgressBar)
#if self.progress_bar_lock.acquire(False):
#GObject.idle_add(self.LoginProgressBarUpdate, 250)
### Logout button thread
def LogOutThreadStart(self, logoutbtn):
isConnected = self.iSNetConnected()
if isConnected:
self.DebugLabel.set_label("Trying to Logout....")
self.LogoutBtn.set_sensitive(False)
thread = threading.Thread(target=self.PinterestLogOut, args=(logoutbtn))
thread.daemon = True
thread.start()
else:
self.DebugLabel.set_label("Internet Connection Lost!!!")
alert_message = "Please check the internet connection! "
self.DisplayAlert(self, alert_message)
### pinning thread start
def PinItThreadStart(self, btn):
if not all([self.isLoggedIn, self.iSPinGrabbed, self.iSBoardAssigned]):
if not self.isLoggedIn:
alert_message = "Please Login first!"
self.DisplayAlert(self, alert_message)
return
if not self.iSPinGrabbed:
alert_message = "Please Grab some pins!"
self.DisplayAlert(self, alert_message)
return
else:
alert_message = "Please Select a board to pin!"
self.DisplayAlert(self, alert_message)
return
else:
isConnected = self.iSNetConnected()
if isConnected:
self.StopPinning = False
self.StopButton.set_sensitive(True)
self.PinItBtn.set_sensitive(False)
self.DebugLabel.set_label("Pinning started")
self.ProgressBarStop = False
GObject.timeout_add(100, self.UpdateProgressBar)
thread = threading.Thread(target=self.LetsStartPinning, args=(btn))
thread.start()
### Progressbar stop
def StopBtnPressed(self, btn):
self.StopPinning = True
self.ProgressBarStop = True
self.StopButton.set_sensitive(False)
self.PinItBtn.set_sensitive(True)
return
### Progressbar stop
def UpdateProgressBar(self):
if not self.ProgressBarStop:
self.ProgressBar.pulse()
return True
else:
print "prgrsbr Stopped"
self.ProgressBar.set_fraction(0.0)
### Check if already a firefox running.
def CheckIfAlreadyAfireFox(self):
print "Checking if already a firefox running..."
iSFire = subprocess.Popen(['ps', 'ax'], stdout=subprocess.PIPE).communicate()[0]
if 'firefox' in iSFire:
print "Firefox alredy running"
alert_message = "Please close all running firefox"
self.DisplayAlert(self, alert_message)
sys.exit()
### Start pinning
### Please don't change time.sleep() here.
def LetsStartPinning(self, btn):
count = 0
self.ToPinBoard = self.ToPinBoard.decode('utf-8')
for pin in self.pin_array:
if not self.StopPinning:
time.sleep(2)
count += 1
print count
print pin
self.browser.visit("http://www.pinterest.com/pin/"+pin+"/")
time.sleep(0.8)
Pinitbtn = "button.Module.ShowModalButton.Button.btn.rounded.medium.primary.primaryOnHover.repin.pinActionBarButton"
self.browser.find_by_css(Pinitbtn).click()
time.sleep(0.5)
self.browser.find_by_css('div.ajax.BoardPickerOld.medium.Module').click()
el = self.browser.find_by_css('div.boardPickerInner')
BrdList = el.find_by_tag('li')
print "pinning board :- "+str(self.ToPinBoard.encode('utf-8'))
for item in BrdList:
if item.text == self.ToPinBoard:
time.sleep(0.5)
item.click()
self.browser.find_by_css('button.rounded.Button.repinSmall.pinIt.primary.Module.ajax.btn').click()
time.sleep(0.5)
self.DebugLabel.set_label(str(count)+"/"+str(self.TotalNoPins)+str(" Pins Completed!"))
break
else:
print "Stop button Pressed"
break
return
### User Login
def PinterestLogin(self, LoginBtn, UserName, PassWord, ProgressBarStop):
self.browser.visit('https://www.pinterest.com/login/')
self.browser.find_by_name('username_or_email').fill(UserName)
time.sleep(2)
self.browser.find_by_name('password').fill(PassWord)
self.browser.find_by_css('.rounded.Button.primary.Module.large.hasText.btn').first.click()
self.browser.visit('http://www.pinterest.com/')
LoggedinHtml = self.browser.html
if not '{"prompted_signup":' in LoggedinHtml:
print "Login Successfull"
self.ProgressBarStop = True
time.sleep(3)
self.DebugLabel.set_label("Login Successfull")
self.isLoggedIn = True
LoginBtn.set_sensitive(False)
self.LogoutBtn.set_sensitive(True)
self.UserNameEntry.set_editable(False)
self.UserNameEntry.set_sensitive(False)
self.PasswordEntry.set_editable(False)
self.PasswordEntry.set_sensitive(False)
time.sleep(1)
if self.browser.is_element_present_by_css('.usernameLink'):
self.browser.find_by_css(".usernameLink").click();
self.browser.find_by_css(".myBoards").click();
PinterestUrl = self.browser.url
self.PinterestUserName = re.search(r'com/(.*)/', PinterestUrl).group(1)
print "Username :- "+str(self.PinterestUserName)
else:
print "Unable to Login"
self.ProgressBarStop = True
time.sleep(3)
self.DebugLabel.set_label("☹ Unable to Login ☹")
### User LogOut
def PinterestLogOut(self, logoutBtn):
self.browser.visit('https://www.pinterest.com/logout/')
self.isLoggedIn = False
time.sleep(3)
self.DebugLabel.set_label("{。^◕‿◕^。} GoodBye!! {。^◕‿◕^。}")
logoutBtn.set_sensitive(False)
self.LoginBtn.set_sensitive(True)
self.UserNameEntry.set_editable(True)
self.PasswordEntry.set_editable(True)
### Search thread start
def PinSearchThread(self, btn):
threading.Thread(target=self.pinterest_search, args=(None,)).start()
### Search starts
def pinterest_search(self, search_btn):
query = self.search_entry.get_text()
if query:
self.DebugLabel.set_label("Searching for '"+str(query)+"'")
print "searching for :- "+str(query)
query = urllib2.quote(query)
self.browser.visit('http://www.pinterest.com/search/pins/?q='+query)
self.DebugLabel.set_label("Search completed")
else:
print "Please enter a search query"
self.search_entry.grab_focus()
### Combo selected
def PinBoardChanged(self, combobox):
model = combobox.get_model()
BoardName = combobox.get_active_text()
print "Boardname :- "+str(BoardName)
self.ToPinBoard = str(BoardName)
if not BoardName == "Select Board":
print "Boardname selected"
self.iSBoardAssigned = True
### Fetch pinterest userboard, This will only fetch first 50 boards. :(
### I am working on another api. :)
def FetchBoardsByApi(self, fetchbtn):
try:
print self.isLoggedIn
except NameError:
self.isLoggedIn = False
## Check whether isLoggedIn is False
if self.isLoggedIn is False:
alert_message = "Plesae login first"
self.DisplayAlert(self, alert_message)
self.iSBoardAssigned = False
else:
print "Fetching boards"
self.DebugLabel.set_label("☣ Fetching Boards ☣")
UserUrl = "http://pinterestapi.co.uk/"+str(self.PinterestUserName)+"/boards"
print UserUrl
response = requests.get(UserUrl)
json_data = json.loads(response.text)
jsonData = json_data["body"]
self.combo_board.remove_all()
count = 0
for item in jsonData:
board_name = item.get("name")
PinBoardNames = board_name.splitlines()[0]
self.combo_board.append_text(PinBoardNames)
count += 1
print "Total "+str(count)+" Boards fetched!"
self.DebugLabel.set_label("Total "+str(count)+" Boards fetched!")
self.iSBoardAssigned = True
### Scrolling thread start
def scroll_down(self, scroll):
if not scroll.get_active():
self.iSPinGrabbed = False
self.ProgressBarStop = True
self.ProgressBar.set_fraction(0.0)
self.stopthread.set()
print "SCrolling Thread Stopped"
scroll.set_label("Fetch Pins")
## Save all source to html
time.sleep(1)
## Calling scrapped_pins to seperate pinteret pins from html
threading.Thread(target=self.scrapped_pins, args=(None,)).start()
#self.scrapped_pins(html)
## Set stop thread
else:
self.ProgressBarStop = False
GObject.timeout_add(50, self.UpdateProgressBar)
print "fetching pins..."
self.DebugLabel.set_label("fetching pins...")
## Start a thread and call scrolling function and stop the thread when the STOP button pressed.
self.thread = threading.Thread(target=self.start_scrolling, args=(scroll,))
self.stopthread= threading.Event()
## Set the label 'STOP' to toggle button
scroll.set_label("STOP")
self.thread.start()
### Start scrolling
def start_scrolling(self, sroll):
while not self.stopthread.isSet():
ExeScript = self.browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2)
### Seperate fetched pins
def scrapped_pins(self, scrl):
pin = ""
pin_href = ""
self.pin_array = []
time.sleep(4)
print self.browser.url
try:
html = self.browser.html
print "Got html in first try"
except Exception:
print "Exception raised"
time.sleep(1)
html = self.browser.html
print "Scrapping pins"
soup = BeautifulSoup(html)
for div in soup.findAll('div', attrs={'class':'pinHolder'}):
pin_href = div.find('a')['href']
pin = re.match(r'\/pin/(\d+)\/', pin_href).group(1)
self.pin_array.extend([pin])
if self.pin_array:
self.iSPinGrabbed = True
count = 0
for x in self.pin_array:
count += 1
print x
time.sleep(1)
self.TotalNoPins = count
self.DebugLabel.set_label(str(count)+" pins scrapped!")
return
### Alert messages
def DisplayAlert(self, test, message):
window = Gtk.Window()
md = Gtk.MessageDialog(window, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.CANCEL, message)
md.run()
md.destroy()
### Get running firefox process id and return that id
### to plug-socket function.
def plug_id(self):
firecmd="ps aux | grep '/usr/lib/firefox/firefox -foreground' | grep -v grep | awk -F ' ' '{print $2}'"
pid = subprocess.check_output(firecmd, shell=True)
print "pid id : "+ str(pid).rstrip()
pid = pid.rstrip()
find_wm_id="wmctrl -lp | grep %s | cut -d' ' -f1" % (pid)
time.sleep(1)
self.win_id = subprocess.check_output(find_wm_id, shell=True)
self.win_id = self.win_id.rstrip()
self.win_id = ast.literal_eval(self.win_id)
self.win_id = long(self.win_id)
self.win_id = str(self.win_id)+"L"
self.win_id = ast.literal_eval(self.win_id)
return self.win_id
### Attach firefox to application window
def attach_socket(self, win_id):
self.socket = Gtk.Socket()
print "firefox id : "+str(win_id)
self.socket.show()
self.mainvbox.pack_start(self.socket, fill=True, expand=True, padding=0)
self.socket.add_id(win_id)
### Init browser
def splinter_init(self):
self.browser = splinter.Browser('firefox')
### SOme stylish tweaks.
def GtkChangeStyle(self):
css = b"""
* {
-GtkProgressBar-min-horizontal-bar-height: 10;
-GtkProgressBar-min-vertical-bar-width: 10;
}
GtkWindow {
background: #4C0B5F;
}
GtkProgressBar {
padding: 0;
border-width: 1px;
}
.progressbar {
border: 7px solid transparent;
background-color: blue;
}
GtkHeaderBar {
color : yellow;
}
.button {
color: white;
background:black;
background-color: black;
padding: 1px 1px;
}
.button:hover {
color: yellow;
padding: 1px 1px;
background-color: #FF0080;
}
.button:insensitive {
background-color: grey;
color: white;
}
.button *:hover {
color: white;
}
.button:hover:active,
.button:active {
color: red;
background-color: #993401;
}
/*********
* entry *
*********/
.entry {
}
/******************
* combobox entry *
******************/
GtkComboBox.combobox-entry .entry:first-child,
GtkComboBox.combobox-entry .button:first-child {
border-image-width: 10px 1px 10px 12px;
border-radius: 8px 0 0 8px;
border-right-width: 0;
}
GtkComboBox.combobox-entry .entry:last-child,
GtkComboBox.combobox-entry .button:last-child {
border-image-width: 10px 12px 10px 1px;
border-radius: 0 8px 8px 0;
border-left-width: 0;
}
"""
style_provider = Gtk.CssProvider()
style_provider.load_from_data(css)
Gtk.StyleContext.add_provider_for_screen(
Gdk.Screen.get_default(),
style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
)
def main(self):
Gtk.main()
### Main ####
if __name__ == "__main__":
GObject.threads_init()
app = pinbot()
Gtk.main()