-
-
Save Earthnuker/a475e18d95c20e3149990ab8080a1781 to your computer and use it in GitHub Desktop.
Automatically scrape and submit SHiFT codes for borderlands
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import mechanicalsoup | |
from getpass import getpass | |
import requests as RQ | |
from bs4 import BeautifulSoup as BS | |
from concurrent.futures import ThreadPoolExecutor,as_completed | |
import time | |
import sys | |
import re | |
import json | |
from pprint import pformat | |
from tqdm import tqdm | |
import os | |
responses=[] | |
if os.path.isfile("responses.json"): | |
pass | |
def fetch_codes(): | |
shift_codes=[] | |
shift_re=re.compile(r"[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}") | |
shift_urls=["http://orcz.com/Borderlands:_Golden_Key", | |
"http://orcz.com/Borderlands_2:_Golden_Key", | |
"http://orcz.com/Borderlands_Pre-Sequel:_Shift_Codes", | |
"http://orcz.com/Borderlands_3:_Shift_Codes", | |
] | |
for url in shift_urls: | |
soup=BS(RQ.get(url).text,'lxml').find_all('table',{'class':'wikitable'}) | |
for table in soup: | |
for td in table.find_all('td'): | |
shift_codes+=shift_re.findall(td.text) | |
return sorted(set(shift_codes)) | |
AUTH_HEADERS={ | |
'Host': "api.2k.com", | |
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0", | |
'Accept': "*/*", | |
'Accept-Language': "en-US,en;q=0.5", | |
'Accept-Encoding': "gzip, deflate, br", | |
'Access-Control-Request-Method': "POST", | |
'Access-Control-Request-Headers': "content-type", | |
'Referer': "https://borderlands.com/en-US/", | |
'Origin': "https://borderlands.com", | |
'Connection': "keep-alive", | |
'Pragma': "no-cache", | |
'Cache-Control': "no-cache", | |
'cache-control': "no-cache", | |
} | |
def cors_rq(method,url,*args,**kwargs): | |
opts=browser.request('OPTIONS',url,*args,headers=AUTH_HEADERS,**kwargs) | |
opts.raise_for_status() | |
resp=browser.request(method,url,*args,headers=AUTH_HEADERS,**kwargs) | |
return resp | |
def code_info(shift_code): | |
info_url='https://api.2k.com/borderlands/code/{}/info'.format(shift_code) | |
return cors_rq('GET',info_url).json() | |
def redeem(code): | |
redeem_url="https://api.2k.com/borderlands/code/{code}/redeem/{offer_service}".format(**code) | |
while True: | |
resp=cors_rq('POST',redeem_url) | |
info=resp.json() | |
if info.get('error',{}).get('code')!='RATE_LIMITED': | |
break | |
time.sleep(300) | |
if info.get('message')=='REDEMPTION_QUEUED': | |
job_id=info.get('job_id') | |
if job_id: | |
delay=info['max_wait_milliseconds']/1000 | |
time.sleep(delay) | |
resp=cors_rq('GET','https://api.2k.com/borderlands/code/{0}/job/{1}'.format(code['code'],job_id)) | |
return {'url':redeem_url,'code':code,'result':resp.text} | |
return info | |
browser=mechanicalsoup.StatefulBrowser(user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0') | |
browser.open("https://borderlands.com/en-US/") | |
email=input("E-Mail: ") | |
passwd=getpass() | |
resp=cors_rq('POST','https://api.2k.com/borderlands/users/authenticate',json={"username":email,"password":passwd}) | |
AUTH_HEADERS['X-Session']=resp.headers['X-SESSION-SET'] | |
account_info=resp.json() | |
acct_key=[] | |
for game in account_info['playedGames']: | |
for platform in game['platforms']: | |
acct_key.append((platform['service'],game['title'])) | |
def can_redeem(code,acct_key): | |
if not code.get('is_active'): | |
return False | |
if (code['offer_service'],code['offer_title']) not in acct_key: | |
return False | |
return True | |
codes=[] | |
with ThreadPoolExecutor(32) as pool: | |
jobs=[] | |
for code in tqdm(fetch_codes(),ascii=True,desc="Submiting Jobs"): | |
jobs.append(pool.submit(code_info,code)) | |
pbar=tqdm(as_completed(jobs),total=len(jobs),ascii=True,desc="Fetching infos") | |
for code_info in pbar: | |
code_info=code_info.result() | |
if not code_info: | |
continue | |
if not 'entitlement_offer_codes' in code_info: | |
continue | |
codes+=code_info['entitlement_offer_codes'] | |
codes=list(filter(lambda c:can_redeem(c,acct_key),codes)) | |
responses=[] | |
for code in codes: | |
resp=redeem(code) | |
responses.append(resp) | |
print(pformat(resp)) | |
print("="*20) | |
json.dump(responses,open("responses.json","w")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment