Python. Создаем Steam бота.

Предисловие.

В этом уроке вы научитесь работать с библиотекой steampy, на которой можно создать steam бота.

Подготовка

Первым делом, получите steam_api ключ, он нам понадобится для получения информации о трейдах. Получить его можно на сайте steam: https://steamcommunity.com/dev/apikey

Далее, понадобятся shared_secret и identity_secret, дающие полный доступ к вашему аккаунту.

Получить его можно в SDA в папке maFiles, при условии что вы не шифровали этот файл. Или на телефоне под управлением android с рут правами, к которому привязан steam.

Создайте текстовый файл steam_guard.json, и поместите туда следующий текст.

{
    "steamid": "YOUR_STEAM_ID_64",
    "shared_secret": "YOUR_SHARED_SECRET",
    "identity_secret": "YOUR_IDENTITY_SECRET"
}

Steamid берем тут. В поле сайта, введите ссылку на аккаунт.

И установите библиотеку steampy, введя данную комманду в консоли.

Подтверждаем обмен.

Напишем основу стим бота.

from steampy.client import SteamClient #импортируем библиотеку

steam_client = SteamClient('MY_API_KEY') 
steam_client.login('MY_USERNAME', 'MY_PASSWORD', 'steam_guard.json') #авторизируемся в аккаунте

Данный код отвечает за авторизацию на аккаунте.

Далее, попросите друга или бота кинуть трейд, чтобы на аккаунте висел не принятый обмен.

И пройдите по данной ссылке.

STEAM_API_KEY — замените на свой.

Данная ссылка, это api запрос, который выводит информацию о входящих трейдах в json формате, подробнее здесь.

Нас, во всем этом месиве, интересует только tradeofferid. Он понадобится для подтверждения обмена. Теперь, скопируйте следующие строки в свой скрипт.

trade_id = ваш_trade_id
steam_client.accept_trade_offer(trade_id)

trade_id — замените на собственный.

И запустите скрипт.

В итоге, обмен принят без нашего участия, что круто.

Кидаем обмен.

Создайте новый скрипт, и поместите туда следующий код:

from steampy.client import SteamClient, Asset
from steampy.utils import GameOptions, get_key_value_from_url, account_id_to_steam_id

def find_item_in_inventory(item_hash_name, items):
    for item in items.values():
        market_hash_name = item['market_hash_name']
        if market_hash_name != item_hash_name:
            continue
        return {
            'market_hash_name': market_hash_name,
            'id': item['id']
        }

def make_trade_1_item(give_item, get_item, trade_link):
    game = GameOptions.TF2
    my_items = steam_client.get_my_inventory(game)
    my_item_give = find_item_in_inventory(give_item, my_items)
    my_asset = [Asset(my_item_give['id'], game)]

    partner_account_id = get_key_value_from_url(trade_link, 'partner', True)
    partner_steam_id = account_id_to_steam_id(partner_account_id)
    partner_items = steam_client.get_partner_inventory(partner_steam_id, game)
        
    partner_item_give = find_item_in_inventory(get_item, partner_items)
    partner_asset = [Asset(partner_item_give['id'], game)]

    steam_client.make_offer_with_url(my_asset, partner_asset, trade_link)

steam_client = SteamClient('secret')
steam_client.login('secret', 'secret', "steam_guard.json")
trade_link = 'https://randomSteamTradeOfferLink1234_under_prog_ru'
make_trade_1_item('Refined Metal', 'Refined Metal', trade_link)

За отправку трейда отвечает функция make_trade_1_item, разберем её.

game = GameOptions.TF2

В качестве инвентаря выбрали инвентарь TF2

my_items = steam_client.get_my_inventory(game)
my_item_give = find_item_in_inventory(my_items, give_item)

Получаем информацию о предметах инвентаря. И отсеиваем ненужное, с помощью функции find_item_in_inventory. На выходе, получаем словарь такого формата:

{
  'market_hash_name': напзвание_предмета,
  'id': id_предмета
}

Далее, запаковываем предмет в Asset.

my_asset = [Asset(my_item_give['id'], game)]

Asset принимает 2 аргумента:

  • id предмета
  • код игры (для TF2, это 440)

Наши предметы готовы, осталось подготовить предметы партнера. Сперва, получим инвентарь партнера.

partner_account_id = get_key_value_from_url(trade_link, 'partner', True) #получаем id аккаунта из трейд ссылки
partner_steam_id = account_id_to_steam_id(partner_account_id) # id аккаунта преводим в steam_id
partner_items = steam_client.get_partner_inventory(partner_steam_id, game) #получаем инвентарь партнера

Отсеем все ненужное, и закинем в Asset.

partner_item_give = find_item_in_inventory(get_item, partner_items)
partner_asset = [Asset(partner_item_give['id'], game)]

Ассеты собраны, время посылать трейд.

steam_client.make_offer_with_url(my_asset, partner_asset, trade_link)

Пишем бота для торговой площадки Steam (SCM).

Чтобы получить цену предмета предмета с тп (торговой площадки).

from steampy.client import SteamClient
from steampy.models import GameOptions, Currency

itemName = "Winter 2021 Cosmetic Case"
resp = steam_client.market.fetch_price(itemName,game=GameOptions.TF2)
print(resp)

Необходимо воспользоваться методом fetch_price, который имеет следующий синтаксис

steam_client.market.fetch_price(имя_предмета, game=тип_игры)

Данный код не будет работать, если вы в объекте steam_client не залогинились.

Таким образом, код выше, ищет на тп цену Winter 2021 Cosmetic Case, и выводит её на экран (print).

Похожим образом, методом fetch_price_history, вы можете получить историю цен предмета.

steam_client.market.fetch_price_history(имя_предмета, game=тип_игры)

Покупаем предмет с торговой площадки Steam.

В данном примере мы установим заявку на покупку Winter 2021 Cosmetic Case, за 0.06 р.

Перепишите данный код:

from steampy.client import SteamClient
from steampy.models import GameOptions, Currency

itemName = "Winter 2021 Cosmetic Case"
    response = steam_client.market.create_buy_order(itemName, "6", 1, GameOptions.TF2, Currency.RUB)
    buy_order_id = response["buy_orderid"]

У метода create_buy_order, следующий синтаксис:

steam_client.market.create_buy_order(имя_предмета, цена_предмета*100, количество_заявок_на_покупку, тип_игры, тип_валюты)
  • имя_предмета — имя предмета для покупки
  • цена_предмета*100 — цена предмета помноженная на 100 (в примере цена = 6, валюта рубль, значит ордер создастся на цену 0.06 р)
  • количество_заявок_на_покупку — количество предметов на покупку

Таким образом, вы можете автоматизировать покупку предметов на тп.

Продаем предмет на тп.

Перепишите данный код:

from steampy.models import GameOptions, Currency
from steampy.client import SteamClient, Asset

from steampy.utils import GameOptions, get_key_value_from_url, account_id_to_steam_id

def find_item_in_inventory(item_hash_name, items):
    for item in items.values():
        market_hash_name = item['market_hash_name']
        if market_hash_name != item_hash_name:
            continue
        return {
            'market_hash_name': market_hash_name,
            'id': item['id']
        }

steam_client = None


def initSteam():
    global steam_client
    print("Signing in steam account")
    steam_client = SteamClient(ваш_апи_ключ_стим) 
    steam_client.login(ваш_логин_стим, ваш_пароль_стим, "steam_secret.json") #авторизируемся в аккаунте
    itemName = "Winter 2021 Cosmetic Case"
    my_items = steam_client.get_my_inventory(GameOptions.TF2) #Получаем свой инвентарь
    my_item_sell = find_item_in_inventory(itemName, my_items) #Из него извлекаем нужный предмет на имени
    sell_response = steam_client.market.create_sell_order(my_item_sell["id"], GameOptions.TF2, "4") #Выставляем на продажу за 4 копейки
    print(sell_response)

initSteam()

За выставления лота на продажу отвечает метод steam_client.market.create_sell_order:

steam_client.market.create_sell_order(id_предмета, тип_игры, цена_продажи*100)
  • id_предемета — id предмета в твоем инвентаре.
  • тип_игры — переменная типа GameOptions
  • цена_продажи*100 — цена, за которую продается предмет, без учета комиссии стим.

Чтобы получить id_предмета, сперва, я получил свой инвентарь (массив предметов), и, с помощью метода find_item_in_inventory, получил предмет с именем Winter 2021 Cosmetic Case

itemName = "Winter 2021 Cosmetic Case"
my_items = steam_client.get_my_inventory(GameOptions.TF2) #Получаем свой инвентарь
my_item_sell = find_item_in_inventory(itemName, my_items) #Из него извлекаем нужный предмет на имени

И передал id этого предмета в метод steam_client.market.create_sell_order

sell_response = steam_client.market.create_sell_order(my_item_sell["id"], GameOptions.TF2, "4") #Выставляем на продажу за 4 копейки

В итоге, Winter 2021 Cosmetic Case выставился на продажу за 0.06р (4 копейки + комиссия стима).

Сохранение сессии.

Каждый раз запуская бота, вы заново логинитесь в стиме. И все бы ничего, только вот, у стима есть ограничение на количество авторизаций. Решить проблему, можно с помощью сохранения сессии, и последующей её загрузки.

steam_client.login(api_keys.steam_login, api_keys.steam_password, "steam_secret.json")

Используя метод steam_client.login мы получаем сессию (набор куки, заголовков). По ключам которые находятся в куки, сайт стима понимает что мы авторизированны. Следовательно, сохранив сессию в файл, а позже загрузив, мы можем получить доступ к аккаунту, минуя авторизацию.

Для сохранения, будем использовать библиотеку pickle, позволяющую сохранять объекты языка Python, в файл. В своем примере, я сохранил весь обьект steam_client в файл.

import os
from steampy.models import GameOptions, Currency
from steampy.client import SteamClient, Asset
from steampy.utils import GameOptions, get_key_value_from_url, account_id_to_steam_id
import pickle

steam_client = None

def initSteam():
    global steam_client
    if(os.path.isfile("steamClient.pkl")):
        print("Using previous session")
        with open('steamClient.pkl', 'rb') as f: 
            steam_client = pickle.load(f) 
    else:
        print("You not authorized, trying to login into Steam")
        print("Signing in steam account")
        steam_client = SteamClient(api_keys.steam_api_key) 
        steam_client.login(ваш_стим_логин, ваш_стим_пароль, "steam_secret.json") #авторизируемся в аккаунте
        print("Saving session")
        with open('steamClient.pkl', 'wb') as f: 
            pickle.dump(steam_client, f) 
  • Если файл steamClient.pkl существует, то подгружаем его pickle.load(f) в переменную steam_client.
  • Если отсутствует, то логинимся в стиме steam_client.login, и объект steam_client сохраняем в файл steamClient.pkl.

Таким образом, бот авторизируется в стиме 1 раз, а дальше, будет подгружать сессию из файла.

Заключение.

Данная библиотека, мне очень помогла в написании tf2.tm бота, который я упоминал здесь. Применив знания с данной статьи отсюда и отсюда, вы сможете написать похожего бота.

Итоговый результат.