3
\$\begingroup\$
#!/usr/bin/python
# -*- coding: utf-8 -*-
import urllib2
import json
import datetime
import time

global file_name
file_name = "skins 2017-05-05 23-15-16.txt"

wear_list = ["Factory New", "Minimal Wear", "Field-Tested", "Well-Worn", "Battle-Scarred"]
wear_val = {"Factory New": 1, "Minimal Wear": 2, "Field-Tested": 3, "Well-Worn": 4, "Battle-Scarred": 5}
items = []
item_prices = {}

def getInventory(steamid):
    try:
        data = urllib2.urlopen('http://steamcommunity.com/profiles/'+steamid+'/inventory/json/730/2')
    except:
        print("Overloaded the server...")
        print("Waiting...")
        time.sleep(60)
        data = urllib2.urlopen('http://steamcommunity.com/profiles/'+steamid+'/inventory/json/730/2')
    json_data = json.loads(data.read())
    descriptions = json_data['rgDescriptions']
    now = datetime.datetime.now()
    date = now.strftime("%Y-%m-%d %H-%M-%S")
    global file_name
    file_name = "skins " + str(date) + ".txt"
    txt = open(file_name, "w+")
    for v in descriptions:
        name = str([descriptions[v]['market_name']])
        name = name[3:]
        name = name[:-2]
        if name.endswith("Flip Knife | Rust Coat (Battle-Scarred)"):
            name = name[7:]
        if name.startswith("StatTrak"):
            name = name[15:]
            name = 'StatTrak ' + name
        if name.endswith("(Dragon King) (Minimal Wear)"):
            name = "M4A4 | Dragon King (Minimal Wear"
        txt.write(name)
        txt.write('\n')
        #txt.write(str(descriptions[v]))
        #txt.write('\n')
        print(name)
    txt.close()
    print('Done!')
    return

def getPrice():
    x = 1
    gun_name_wear = 0
    txt = open(file_name, "r+")
    for line in txt:
        stattrak = 0
        wear = line[line.find("(")+1:line.find(")")]
        if wear in wear_list:
            print(wear)
            wear = wear.replace(" ","%20")
            gun = line.split(' |', 1)[0].replace('.', '')
            print(gun)
            if "StatTrak" in gun:
                stattrak = 1
                gun = gun.replace("StatTrak","")
            if gun.startswith(" "):
                gun = gun[1:]
            gun = gun.replace(" ", "%20")
            name = line[line.find("| ")+1:line.find(" (")]
            if name.startswith(" "):
                name = name[1:]
            print(name)
            name = name.replace(" ", "%20")
            if stattrak == 1:
                try:
                    data = urllib2.urlopen("http://steamcommunity.com/market/priceoverview/?appid=730&currency=2&market_hash_name=StatTrak%E2%84%A2%20" + gun + "%20|%20" + name + "%20(" + wear + ")")
                except:
                    print("Overloaded the server...")
                    print("Waiting...")
                    time.sleep(60)
                    data = urllib2.urlopen("http://steamcommunity.com/market/priceoverview/?appid=730&currency=2&market_hash_name=StatTrak%E2%84%A2%20" + gun + "%20|%20" + name + "%20(" + wear + ")")
                json_data = json.loads(data.read())
                print(json_data)
                try:
                    price = json_data['lowest_price']
                except KeyError:
                    price = json_data['median_price']
                price = price[-4:]
                print(price)
                gun = gun.replace("%20", " ")
                name = name.replace("%20", " ")
                wear = wear.replace("%20", " ")
                item_prices[str("StatTrak " + gun + " " + name + " " + wear)] = price
                continue
            if "knife" in line.lower():
                try:
                    data = urllib2.urlopen("http://steamcommunity.com/market/priceoverview/?appid=730&currency=2&market_hash_name=★%20" + gun + "%20|%20" + name + "%20(" + wear + ")")
                except:
                    print("Overloaded the server...")
                    print("Waiting...")
                    time.sleep(60)
                    data = urllib2.urlopen("http://steamcommunity.com/market/priceoverview/?appid=730&currency=2&market_hash_name=★%20" + gun + "%20|%20" + name + "%20(" + wear + ")")
                json_data = json.loads(data.read())
                print(json_data)
                try:
                    price = json_data['lowest_price']
                except KeyError:
                    price = json_data['median_price']
                price = price[-4:]
                print(price)
                gun = gun.replace("%20", " ")
                name = name.replace("%20", " ")
                wear = wear.replace("%20", " ")
                item_prices[str(gun + " " + name + " " + wear)] = price
                continue
            else:
                try:
                    data = urllib2.urlopen("http://steamcommunity.com/market/priceoverview/?appid=730&currency=2&market_hash_name=" + gun + "%20|%20" + name + "%20(" + wear + ")")
                except:
                    print("Overloaded the server...")
                    print("Waiting...")
                    time.sleep(60)
                    data = urllib2.urlopen("http://steamcommunity.com/market/priceoverview/?appid=730&currency=2&market_hash_name=" + gun + "%20|%20" + name + "%20(" + wear + ")")
                json_data = json.loads(data.read())
                print(json_data)
                try:
                    price = json_data['lowest_price']
                except KeyError:
                    price = json_data['median_price']
                price = price[-4:]
                print(price)
                gun = gun.replace("%20", " ")
                name = name.replace("%20", " ")
                wear = wear.replace("%20", " ")
                gun_name_wear = str(gun + " " + name + " " + wear)
                price = price.replace 
                item_prices[str(gun + " " + name + " " + wear)] = price
            time.sleep(5)
        else:
            continue
    print(item_prices)
    print(item_prices[gun_name_wear])

getInventory('76561198216481185')
getPrice()

my code gets a players inventory, writes it to a text file, then works out the prices of said inventory.

I know I repeat myself when I get the JSON data for each of the different types of weapons (knife/statrak/normal) but i will most likely write function at a later date.

Anything would help, thank you.

Edit: Please ignore the "global file_name" and the line underneath that. I used that when tweaking only small parts of the script and to avoid mass requests to the server.

\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

There are quite a few improvements possible. I will try to describe all the changes I made in your code.

First, you should define that function that just gets data from an URL and retries if there have been too many requests recently. For this you should try to except the most specific exception possible. This way the user can abort e.g. the 60s waiting period. Also, even if you only except urllib2.HTTPError, you still want to be more specific (and not except e.g. Error 500, the internal server error if you wrongly escape spaces in the URL).

Put all the URLs into constants at the top of the file.

x in d works for dictionaries and sees if x is a key of the dictionary d, so you don't need wear_list (you also never use the values of wear_val, but I left it there).

I made get_inventory a generator that just returns the retrieved items and a second function that saves it to a file. This way you can skip the saving part if you ever want to, or do something else with it.

The same for the prices. I added one function whose sole purpose it is to retrieve the price of one item and then another function to call this function for all items.

Both these methods take a file_name argument, which gets rid of the global file_name.

You should use str.format throughout, because it is better than string addition. Note also that it can take a custom formatting string, which makes formatting dates a lot more concise.

Get rid of all the replacing of " " with "%20" and vice-versa by just quoting the variables that need to be url-encoded using urllib2.quote.

I removed a lot of the intermediate debugging output.

I think I found some bugs with your building of name, where your hardcoded indices for the "StatTrak" etc seemed to be off. I made this more explicitly deleting all unicode symbols using a REGEX found here.

Use str.strip where needed to get rid of leftover white-space at the beginning or end of strings.

At the end I added a if __name__ == "__main__": guard to ensure the code there is only run when directly invoking this script via python csgo_inventory.py.

#!/usr/bin/python
# -*- coding: utf-8 -*-
import urllib2
import json
import datetime
import time
import re


wear_val = {"Factory New": 1, "Minimal Wear": 2,
            "Field-Tested": 3, "Well-Worn": 4, "Battle-Scarred": 5}

INVENTORY_URL = 'http://steamcommunity.com/profiles/{}/inventory/json/730/2'
STATTRAK_URL = "http://steamcommunity.com/market/priceoverview/?appid=730&currency=2&market_hash_name=StatTrak%E2%84%A2%20{gun}%20|%20{name}%20({wear})"
KNIFE_URL = "http://steamcommunity.com/market/priceoverview/?appid=730&currency=2&market_hash_name=★%20{gun}%20|%20{name}%20({wear})"
GUN_URL = "http://steamcommunity.com/market/priceoverview/?appid=730&currency=2&market_hash_name={gun}%20|%20{name}%20({wear})"


def get_data(url):
    while True:
        try:
            return urllib2.urlopen(url)
        except urllib2.HTTPError as e:
            if e.code == 429:
                print("Overloaded the server, waiting 60s...")
                time.sleep(60)
            else:
                print(url)
                raise


def get_inventory(steamid):
    data = get_data(INVENTORY_URL.format(steamid))
    descriptions = json.loads(data.read())['rgDescriptions'].values()
    for description in descriptions:
        name = description['market_name']
        name = re.sub(r'[^\x00-\x7f]', r'', name)
        if name.endswith("(Dragon King) (Minimal Wear)"):
            name = "M4A4 | Dragon King (Minimal Wear)"
        yield name


def save_inventory(steamid, file_name):
    with open(file_name, "w+") as txt:
        for item in get_inventory(steamid):
            txt.write(item + '\n')
    print('Done!')


def get_price(url, gun, name, wear):
    data = get_data(url.format(**locals()))
    json_data = json.loads(data.read())
    try:
        price = json_data['lowest_price']
    except KeyError:
        price = json_data['median_price']
    return price[-4:]


def get_info(item):
    # print(item)
    wear = item[item.find("(") + 1:item.find(")")]
    if wear not in wear_val:
        return "", None

    gun = item.split(' |', 1)[0].replace('.', '')
    stattrak = "StatTrak" in gun
    gun = gun.replace("StatTrak", "").strip()

    name = item[item.find("| ") + 1:item.find(" (")].strip()

    if stattrak:
        url = STATTRAK_URL
    elif "knife" in item.lower():
        url = KNIFE_URL
    else:
        url = GUN_URL
    price = get_price(url, urllib2.quote(gun), urllib2.quote(name), urllib2.quote(wear))
    return "{gun} {name} {wear}".format(**locals()), price


def get_prices(file_name):
    item_prices = {}
    with open(file_name, "r+") as txt:
        for item in txt:
            name, price = get_info(item)
            if price is not None:
                item_prices[name] = price
                print(name, price)
                time.sleep(5)
    return item_prices


if __name__ == "__main__":
    now = datetime.datetime.now()
    # file_name = "skins 2017-05-05 23-15-16.txt"
    file_name = "skins {:%Y-%m-%d %H-%M-%S}.txt".format(now)
    save_inventory('76561198216481185', file_name)
    item_prices = get_prices(file_name)
\$\endgroup\$
5
  • \$\begingroup\$ I do not understand your "yield" command, care to explain it to me? \$\endgroup\$
    – Elijah D-R
    May 7, 2017 at 14:10
  • \$\begingroup\$ @Elijah This makes the function a generator. A generator basically executes until it reaches a yield, where it yields whatever is after it to the outside (like a normal return) If you then call next in it it executes further until the next yield or until the end of the function. Have a look here for a more complete description of generators. \$\endgroup\$
    – Graipher
    May 7, 2017 at 15:04
  • \$\begingroup\$ Thanks, one problem with the code above is it doesn't allow you to have an item above 9.99 as it cannot do tens. \$\endgroup\$
    – Elijah D-R
    May 7, 2017 at 15:13
  • \$\begingroup\$ i added extra_letters = int(len(price) - 1 and return price[-int(extra_letters):] to the end of get_price() \$\endgroup\$
    – Elijah D-R
    May 7, 2017 at 15:40
  • \$\begingroup\$ @Elijah Well, that part I copied from your code ^^ \$\endgroup\$
    – Graipher
    May 7, 2017 at 17:23
2
\$\begingroup\$
  • Rather than using urllib2 use requests. It's simpler to use and makes the code much nicer to read. Also the Python docs recommend it as well:

    See also: The Requests package is recommended for a higher-level HTTP client interface.

  • Rather than mutating the name a lot use the data you're given. The JSON object contains a tags object that can tell you the weapon, wear and if it's StatTraked. Using this instead is a much better idea to extracting the information.

  • Rather than manually making the market_hash_name, you can also use the one provided by Steam.

  • Rather than making a dictionary of name: price, you can instead add the price to item objects, and have all the information in one place.

Instead I'd use the following, which should show you most of extract_information is unneeded.

#!/usr/bin/python
# -*- coding: utf-8 -*-
import time

import requests

wear_list = ['Factory New', 'Minimal Wear', 'Field-Tested', 'Well-Worn', 'Battle-Scarred']
INVENTORY_URL = 'http://steamcommunity.com/profiles/{}/inventory/json/730/2'
MARKET_URL = 'http://steamcommunity.com/market/priceoverview/'


def get_inventory(steamid):
    r = requests.get(STEAM_URL.format(steamid))
    return r.json()['rgDescriptions']


def extract_information(descriptions):
    for _, item in descriptions.items():
        tags = {i['category']: i for i in item['tags']}
        name = tags['market_name']
        yield {
            'name': name[name.find('|')+1:name.find('(')].strip()
            'market_name': name
            'market_hash_name': item['market_hash_name']
            'wear': tags['Exterior']['name']
            'gun': tags['Weapon']['name']
            'stattrak': 'StatTrak' in tags['Quality']['name']
            'marketable': item['marketable'],
        }

def get_prices(items):
    for item in items:
        if not item['marketable']:
            continue
        if item['wear'] not in wear_list:
            continue

        r = requests.get(
            MARKET_URL,
            params={
                'appid': '730',
                'currency': '2',
                'market_hash_name': item['market_hash_name']
            }
        )
        json_data = r.json()
        try:
            price = json_data['lowest_price']
        except KeyError:
            price = json_data['median_price']

        item['price'] = price[-4:]
        time.sleep(5)
        yield item

if __name__ == '__main__':
    inventory = get_inventory('76561198216481185')
    item_information = extract_information(inventory)
    items = get_prices(item_information)
    for item in items:
        print('{name}: {price}'.format(**item))
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.