# Steam Relationships ## A tool to discover friend relationships between steam profiles Ever ran into a cheater, looked at their profile, and realized all their friends are cheaters too? I have, and this tool is a way to measure degrees of separation from a specific individual Steam Relationships querries the Steam WebAPI to get public friends lists, and then recursively search those friend lists as well. This process repeats until a certain number of "degrees" have been met (a set recursion level specified by the user). The results of these querries are put in a database that can then be shared and used for other purposes ## REQUIREMENTS 1. Python 3.10 or greater 2. [Requests](https://docs.python-requests.org/en/latest/index.html) 2.31.0 or greater 3. A [Steam Developer API key](https://steamcommunity.com/dev/apikey) If using [Poetry](https://python-poetry.org/), all Python dependencies are fetched automatically ## INSTALLATION ### Pip version 1. Run `pip install steamrelationships` ### Poetry Version 1. In a poetry shell, run `poetry add steamrelationships` 2. Import the package `import steamrelationships` 3. See the documentation on methods & objects ## DOCUMENTATION ### Objects | Object | Full Name | Description | | :----: | :-------: | :---------- | | SteamRelationships | steamrelationships.sr.SteamRelationships | A class implementing Steam friends list scanning | | Object | steamrelationships.constants._Const | A class containing constant values used throughout the SteamRelationships Class | ### Constants | Name | Value | Description | | :-- | ---: | ----------- | | STEAMAPI_MAXREQ | 100000 | Steam's daily API request limit | | DAY_IN_NANO | 8.64 * (10 ** 13) | The amount of nanoseconds in 24 hours | | JSON_INDENT | 4 | The indent used when dumping a Python object to a .json file | ### `steamrelationships.sr.SteamRelationships()` parameters | Parameter | Expected Value | Description | | :-------: | :------------- | :---------- | | webapikey | `str` **(REQUIRED)** | A [Steam Dev API Key](https://steamcommunity.com/dev/apikey) | | timeout | `int` (Default: 30) | The number of seconds to wait for a response from Steam before timing out | | timeout_retries | `int` (Default: 5) | The number of times to retry after a timeout | | reqdelay | `float` (Default: 0.5) | The base number of seconds to wait between requests | | delayrand | `int` (Default: 25) | The percentage up or down a delay may vary. *Clamped between 0 and 99, negative values made positive* | | reqsafetybuffer | `float` (Default: 0.9) | A percentage of Steam's daily api request limit to stop at. *0.9 stops at 90% of the max* | | reqjson | `str` (Default: "requests.json") | Filepath to where the requests json file should be stored | ### `steamrelationships.sr.SteamRelationships()` methods | Function | Params | Return Values | Description | | :------: | :----- | :------------ | :---------- | | basicscan | **`(str) steamid64`** - A 64 bit decimal Steam id | **`(dict)`** A dict with a single key, that of the scanned user, which maps to a list of the users's friends. **Empty on error** | Send a request to Steam's API to retrieve a specified user's friends list | | recursivescan | **`(str) steamid64`** - A 64 bit decimal Steam id; **`(int, Default = 2) recurselevel`** - The number of recursive scans to complete | **`(dict)`** A dict containing the starting steamid, then the friends contained in the original scan with the results of their scan. **Empty on error** | Scan a person's friends list, then scan for their friends' lists. This process repeats for every level of "`recurselevel`" |
Private steamrelationships.sr.SteamRelationships() methods ### Private `steamrelationships.sr.SteamRelationships()` methods | Function | Params | Return Values | Description | | :------: | :----- | :------------ | :---------- | | __readjsonfile | **`(str) filepath`** - Path to json file | **`(dict)`** The contents of the json file. **Empty on error** | Read the specified json file for previous requests. Will create an "empty" json file if the specified file at the `filepath` doesn't exist | | __checkrequests | **`(str) filename`** - filepath to requests log | **`(int)`** The number of requests in the last 24 hours. **`-1` on error**, `0` *on too many requests*, and `>1` if a valid number of requests | Check the requests log to make sure Steam's request limit hasn't been passed. Will create a file at `filepath` if it doesn't exist, also will *never go over 100,000 requests*, regardless of what `reqsafetybuffer` is | | __getFriendsList | **`(str) steamid64`** - A Steam User's id, in the steamid64 format; **`(int, Default = 0) _retries`** - An internal value used to limit the number of retries after a timeout. Increments by one automatically on every timeout | **`(dict)`** The json representation of Steam's response. **Empty on error** | Send a request to the Steam Web API to get a user's friends list | | __parseFriendsList | **`(dict) friendsdict`** - The return value of `__getFriendsList` | **`(list)`** The steamid64's of a user's friends. **Empty on error** | Parse a response from Steam and extract a user's friend's Steam IDs |
Example program ```python #!/usr/bin/env -S python3 -i import steamrelationships from steamrelationships.constants import _Const CONST = _Const() if __name__ == "__main__": print(f"Constants:\n\t> Max API Requests per Day: {CONST.STEAMAPI_MAXREQ}\n\t> Number of Nanoseconds In a Day: {CONST.DAY_IN_NANO}\n\t> .json File Indent: {CONST.JSON_INDENT}") # Replace the XXXX's with your dev api key steamuser: object = steamrelationships.SteamRelationships(webapikey="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", reqsafetybuffer=0.01) # Replace the XXXX's with the steam id of the guy you want to scan bigscan: dict = steamuser.recursivescan("XXXXXXXXXXXXXXXXX", recurselevel=1) littlescan: dict = steamuser.basicscan("XXXXXXXXXXXXXXXXX") del steamuser print(f'Original scanned user: {list(littlescan.keys())[0]}\nOriginal Friends: {littlescan[list(littlescan.keys())[0]]}') totalscanned: int = 0 alreadyscanned: list = [] for scanned in bigscan.keys(): totalscanned += 1 alreadyscanned.append(scanned) for friend in bigscan[scanned]: if friend not in alreadyscanned: totalscanned += 1 alreadyscanned.append(friend) print(f"Total users found: {totalscanned}") ``` ## LICENSE Steam Relationships is licensed under [GPLv3.0](LICENSE)