Merge pull request #5 from stilManiac/dev-v2

v2 release
This commit is contained in:
Tim 2020-06-27 12:13:18 +03:00 committed by GitHub
commit a154488711
Signed by: GitHub
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 314 additions and 157 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
env/
*.ini
__pycache__/

View file

@ -1,27 +1,29 @@
![](https://i.imgur.com/dKA3udT.png)
![](https://i.imgur.com/oCob3wQ.gif)
### About
The bot is specially designed for [SteamGifts.com](https://www.steamgifts.com/)
## TODO
* Add GUI
### Features
- Automatically enters giveaways.
- Undetectable.
- Сonvenient user interface.
- Сonfigurable.
- Sleeps to restock the points.
- Can run 24/7.
### Instructions
### How to run
1. Download the latest version: https://github.com/stilManiac/steamgifts-bot/releases
2. Sign in on [SteamGifts.com](https://www.steamgifts.com/) by Steam.
3. Find `PHPSESSID` cookie in your browser and write it in `cookie.txt` file.
4. Make sure your cookie is right.
5. Start the bot.
3. Find `PHPSESSID` cookie in your browser.
4. Start the bot and follow instructions.
### Commands
`!sleep [arg]` - change a sleeping interval in sec. Default and recommended is 900 sec (15 min.).
`!page` - set a final websites page bot reaches
### Run from sources
```bash
python -m venv env
source env/bin/activate
pip install -r requirements.txt
python src/cli.py
```
### Help
Please leave your feedback and bugs in `Issues` page. Thank you!
Please leave your feedback and bugs in `Issues` page.

145
main.py
View file

@ -1,145 +0,0 @@
import sys
import requests
from bs4 import BeautifulSoup
import json
import time
import threading
from requests import RequestException
try:
file = open('cookie.txt', 'r')
cook = file.readline()
if len(cook) == 0:
print('There is no cookie in cookie.txt file')
time.sleep(30)
sys.exit(0)
except FileNotFoundError:
print('Cant find cookie.txt file')
time.sleep(30)
sys.exit(0)
timeout = 900
pages = 1
def get_soup_from_page(url):
global cookies
cookies = {'PHPSESSID': cook}
r = requests.get(url, cookies=cookies)
soup = BeautifulSoup(r.text, 'html.parser')
return soup
def get_page():
global xsrf_token, points
try:
soup = get_soup_from_page('https://www.steamgifts.com')
xsrf_token = soup.find('input', {'name': 'xsrf_token'})['value']
points = soup.find('span', {'class': 'nav__points'}).text # storage points
except RequestException:
print('Cant connect to the site')
print('Waiting 2 minutes and reconnect...')
time.sleep(120)
get_page()
except TypeError:
print('Cant recognize your cookie value.')
time.sleep(30)
sys.exit(0)
# get codes of the games
def get_games():
global game_name
global pages
n = 1
while n <= pages:
print('Proccessing games from %d page.' % n)
soup = get_soup_from_page('https://www.steamgifts.com/giveaways/search?page=' + str(n))
try:
gifts_list = soup.find_all(lambda tag: tag.name == 'div' and tag.get('class') == ['giveaway__row-inner-wrap'])
for item in gifts_list:
if int(points) == 0:
print('> Sleeping to get 6 points')
time.sleep(timeout)
get_games()
break
game_cost = item.find_all('span', {'class': 'giveaway__heading__thin'})
last_div = None
for last_div in game_cost:
pass
if last_div:
game_cost = last_div.getText().replace('(', '').replace(')', '').replace('P', '')
game_name = item.find('a', {'class': 'giveaway__heading__name'}).text.encode('utf-8')
if int(points) - int(game_cost) < 0:
print('Not enough points to enter: ' + game_name)
continue
elif int(points) - int(game_cost) > 0:
entry_gift(item.find('a', {'class': 'giveaway__heading__name'})['href'].split('/')[2])
n = n+1
except AttributeError as e:
break
print('List of games is ended. Waiting 2 min to update...')
time.sleep(120)
get_page()
get_games()
def entry_gift(code):
payload = {'xsrf_token': xsrf_token, 'do': 'entry_insert', 'code': code}
entry = requests.post('https://www.steamgifts.com/ajax.php', data=payload, cookies=cookies)
json_data = json.loads(entry.text)
get_page()
# print(json_data)
# updating points after entered a giveaway
if json_data['type'] == 'success':
print('> Bot has entered giveaway: ' + game_name)
time.sleep(5)
def inputs_data():
global timeout
global pages
while 1:
cmd = input().split()
if cmd == '!help':
print(' [ HELP BOX ]')
print('!sleep [arg]\t- change a sleeping interval in sec (default is 900 sec)')
print('!page [arg]\t- set a final page')
if len(cmd) == 1:
print('!help to see available commands')
if cmd[0] == '!sleep':
try:
timeout = int(cmd[1])
print('Successfuly set interval to ' + (timeout))
except ValueError:
print('Expect a digit!')
elif cmd[0] == '!page':
try:
pages = int(cmd[1])
print('Successfuly set final page to ' + str(pages))
except ValueError:
print('Expect a digit!')
if __name__ == '__main__':
thread = threading.Thread(target=inputs_data)
thread.start()
get_page()
get_games()

23
requirements.txt Normal file
View file

@ -0,0 +1,23 @@
astroid==2.4.2
beautifulsoup4==4.9.1
certifi==2020.6.20
chardet==3.0.4
idna==2.9
isort==4.3.21
lazy-object-proxy==1.4.3
mccabe==0.6.1
prompt-toolkit==1.0.14
pyconfigstore3==1.0.1
pyfiglet==0.8.post1
Pygments==2.6.1
PyInquirer==1.0.3
pylint==2.5.3
regex==2020.6.8
requests==2.24.0
six==1.15.0
soupsieve==2.0.1
termcolor==1.1.0
toml==0.10.1
urllib3==1.25.9
wcwidth==0.2.5
wrapt==1.12.1

0
src/__init__.py Normal file
View file

127
src/cli.py Normal file
View file

@ -0,0 +1,127 @@
import six
import configparser
import re
from pyfiglet import figlet_format
from pyconfigstore import ConfigStore
from PyInquirer import (Token, ValidationError, Validator, print_json, prompt,
style_from_dict)
from prompt_toolkit import document
try:
import colorama
colorama.init()
except ImportError:
colorama = None
try:
from termcolor import colored
except ImportError:
colored = None
config = configparser.ConfigParser()
style = style_from_dict({
Token.QuestionMark: '#fac731 bold',
Token.Answer: '#4688f1 bold',
Token.Selected: '#0abf5b', # default
Token.Pointer: '#673ab7 bold',
})
def log(string, color, font="slant", figlet=False):
if colored:
if not figlet:
six.print_(colored(string, color))
else:
six.print_(colored(figlet_format(
string, font=font), color))
else:
six.print_(string)
class PointValidator(Validator):
def validate(self, document: document.Document):
value = document.text
try:
value = int(value)
except Exception:
raise ValidationError(message = 'Value should be greater than 0', cursor_position = len(document.text))
if value <= 0:
raise ValidationError(message = 'Value should be greater than 0', cursor_position = len(document.text))
return True
def ask(type, name, message, validate=None, choices=[]):
questions = [
{
'type': type,
'name': name,
'message': message,
'validate': validate,
},
]
if choices:
questions[0].update({
'choices': choices,
})
answers = prompt(questions, style=style)
return answers
def run():
from main import SteamGifts as SG
def askCookie():
cookie = ask(type='input',
name='cookie',
message='Enter PHPSESSID cookie (Only needed to provide once):')
config['DEFAULT']['cookie'] = cookie['cookie']
with open('config.ini', 'w') as configfile:
config.write(configfile)
return cookie['cookie']
log("SteamGifts Bot", color="blue", figlet=True)
log("Welcome to SteamGifts Bot!", "green")
log("Created by: github.com/stilManiac", "white")
config.read('config.ini')
if not config['DEFAULT'].get('cookie'):
cookie = askCookie()
else:
re_enter_cookie = ask(type='confirm',
name='reenter',
message='Do you want to enter new cookie?')['reenter']
if re_enter_cookie:
cookie = askCookie()
else:
cookie = config['DEFAULT'].get('cookie')
pinned_games = ask(type='confirm',
name='pinned',
message='Should bot enter pinned games?')['pinned']
gift_type = ask(type='list',
name='gift_type',
message='Select type:',
choices=[
'All',
'Wishlist',
'Recommended',
'Copies',
'DLC',
'New'
])['gift_type']
min_points = ask(type='input',
name='min_points',
message='Enter minimum points to start working (bot will try to enter giveaways until minimum value is reached):',
validate=PointValidator)['min_points']
s = SG(cookie, gift_type, pinned_games, min_points)
s.start()
if __name__ == '__main__':
run()

147
src/main.py Normal file
View file

@ -0,0 +1,147 @@
import sys
import configparser
import requests
import json
import threading
from requests.adapters import HTTPAdapter
from urllib3.util import Retry
from time import sleep
from random import randint
from requests import RequestException
from bs4 import BeautifulSoup
from cli import log
class SteamGifts:
def __init__(self, cookie, gifts_type, pinned, min_points):
self.cookie = {
'PHPSESSID': cookie
}
self.gifts_type = gifts_type
self.pinned = pinned
self.min_points = int(min_points)
self.base = "https://www.steamgifts.com"
self.session = requests.Session()
self.filter_url = {
'All': "search?page=%d",
'Wishlist': "search?page=%d&type=wishlist",
'Recommended': "search?page=%d&type=recommended",
'Copies': "search?page=%d&copy_min=2",
'DLC': "search?page=%d&dlc=true",
'New': "search?page=%d&type=new"
}
def requests_retry_session(
self,
retries=5,
backoff_factor=0.3
):
session = self.session or requests.Session()
retry = Retry(
total=retries,
read=retries,
connect=retries,
backoff_factor=backoff_factor,
status_forcelist=(500, 502, 504),
)
adapter = HTTPAdapter(max_retries=retry)
session.mount('http://', adapter)
session.mount('https://', adapter)
return session
def get_soup_from_page(self, url):
r = self.requests_retry_session().get(url)
r = requests.get(url, cookies=self.cookie)
soup = BeautifulSoup(r.text, 'html.parser')
return soup
def update_info(self):
soup = self.get_soup_from_page(self.base)
try:
self.xsrf_token = soup.find('input', {'name': 'xsrf_token'})['value']
self.points = int(soup.find('span', {'class': 'nav__points'}).text) # storage points
except TypeError:
log("⛔ Cookie is not valid.", "red")
sleep(10)
exit()
def get_game_content(self, page=1):
n = page
while True:
txt = "⚙️ Retrieving games from %d page." % n
log(txt, "magenta")
filtered_url = self.filter_url[self.gifts_type] % n
paginated_url = f"{self.base}/giveaways/{filtered_url}"
soup = self.get_soup_from_page(paginated_url)
game_list = soup.find_all('div', {'class': 'giveaway__row-inner-wrap'})
if not len(game_list):
log("⛔ Page is empty. Please, select another type.", "red")
sleep(10)
exit()
for item in game_list:
if len(item.get('class', [])) == 2 and not self.pinned:
continue
if self.points == 0 or self.points < self.min_points:
txt = f"🛋️ Sleeping to get 6 points. We have {self.points} points, but we need {self.min_points} to start."
log(txt, "yellow")
sleep(900)
self.start()
break
game_cost = item.find_all('span', {'class': 'giveaway__heading__thin'})[-1]
if game_cost:
game_cost = game_cost.getText().replace('(', '').replace(')', '').replace('P', '')
else:
continue
game_name = item.find('a', {'class': 'giveaway__heading__name'}).text
if self.points - int(game_cost) < 0:
txt = f"⛔ Not enough points to enter: {game_name}"
log(txt, "red")
continue
elif self.points - int(game_cost) >= 0:
game_id = item.find('a', {'class': 'giveaway__heading__name'})['href'].split('/')[2]
res = self.entry_gift(game_id)
if res:
self.points -= int(game_cost)
txt = f"🎉 One more game! Has just entered {game_name}"
log(txt, "green")
sleep(randint(3, 7))
n = n+1
log("🛋️ List of games is ended. Waiting 2 mins to update...", "yellow")
sleep(120)
self.start()
def entry_gift(self, game_id):
payload = {'xsrf_token': self.xsrf_token, 'do': 'entry_insert', 'code': game_id}
entry = requests.post('https://www.steamgifts.com/ajax.php', data=payload, cookies=self.cookie)
json_data = json.loads(entry.text)
if json_data['type'] == 'success':
return True
def start(self):
self.update_info()
if self.points > 0:
txt = "🤖 Hoho! I am back! You have %d points. Lets hack." % self.points
log(txt, "blue")
self.get_game_content()