#!/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¤cy=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¤cy=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¤cy=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¤cy=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¤cy=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¤cy=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.
2 Answers 2
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¤cy=2&market_hash_name=StatTrak%E2%84%A2%20{gun}%20|%20{name}%20({wear})"
KNIFE_URL = "http://steamcommunity.com/market/priceoverview/?appid=730¤cy=2&market_hash_name=★%20{gun}%20|%20{name}%20({wear})"
GUN_URL = "http://steamcommunity.com/market/priceoverview/?appid=730¤cy=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)
-
\$\begingroup\$ I do not understand your "yield" command, care to explain it to me? \$\endgroup\$Elijah D-R– Elijah D-R2017年05月07日 14:10:54 +00:00Commented 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 normalreturn
) If you then callnext
in it it executes further until the nextyield
or until the end of the function. Have a look here for a more complete description of generators. \$\endgroup\$Graipher– Graipher2017年05月07日 15:04:27 +00:00Commented 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– Elijah D-R2017年05月07日 15:13:35 +00:00Commented May 7, 2017 at 15:13
-
\$\begingroup\$ i added
extra_letters = int(len(price) - 1
andreturn price[-int(extra_letters):]
to the end ofget_price()
\$\endgroup\$Elijah D-R– Elijah D-R2017年05月07日 15:40:35 +00:00Commented May 7, 2017 at 15:40 -
\$\begingroup\$ @Elijah Well, that part I copied from your code ^^ \$\endgroup\$Graipher– Graipher2017年05月07日 17:23:20 +00:00Commented May 7, 2017 at 17:23
Rather than using
urllib2
userequests
. 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))