Last active
October 19, 2016 14:24
-
-
Save Higgs1/7c33128a38e4f7b4b28c to your computer and use it in GitHub Desktop.
Super Basic Python 3 Google Play Downloader with Python-Requests
This file contains hidden or 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
# Read title! Should be able to download any apk of any version, as long | |
# as it's free. Paid apps are not supported, even if you've paid for them | |
# (should be easy to implement, but I haven't bought any apps yet). | |
# PyPI "requests" | |
import requests | |
import io | |
# Step 0. Google Constants + Inputs | |
url_root = 'https://android.clients.google.com/' | |
# Enter your login details here | |
email = '[email protected]' | |
password = 'Password' | |
android_id = 'FFFFFFFFFFFFFFFF' | |
# APK name you want to download here. | |
packname = 'com.google.android.gms' | |
# APK version you want, or None for latest. | |
version = None | |
def rbitshift(v, b): | |
return v >> b, v & (2**b - 1) | |
def read_uleint(s, l = 4): | |
b = s.read(l) | |
if not b: | |
raise EOFError | |
return int.from_bytes(b, 'little') | |
def read_ulelong(s): | |
return read_uleint(s, 8) | |
def read_uleb128(s): | |
c, d, v = 1, 0, 0 | |
while c: | |
c, b = rbitshift(read_uleint(s, 1), 7) | |
v += b << d | |
d += 7 | |
return v | |
def read_pb_bytes(s): | |
return s.read(read_uleb128(s)) | |
pb_codecs = [ | |
read_uleb128, # 0 | |
read_ulelong, # 1 | |
read_pb_bytes, # 2 | |
None, None, | |
read_uleint # 5 | |
] | |
def read_pb_key(s): | |
return rbitshift(read_uleb128(s), 3) | |
def read_pb_field(s): | |
k, t = read_pb_key(s) | |
return k, pb_codecs[t](s) | |
def parse_pb_dict(data): | |
data, d = io.BytesIO(data), {} | |
try: | |
while True: | |
d.update([read_pb_field(data)]) | |
except EOFError: | |
pass | |
return d | |
def parse_pb_path(v, *path): | |
if len(path): | |
return parse_pb_path(parse_pb_dict(v)[path[0]], *path[1:]) | |
return v | |
def parse_utf8(s): | |
return s.decode('UTF-8') | |
# Step 1. Login to Google | |
session = requests.Session() | |
data = session.post( | |
url_root + 'auth', | |
data = { | |
"Email": email, | |
"Passwd": password, | |
"service": 'androidmarket', | |
}).text | |
auth = dict(map(lambda s: s.split('='), data.split()))['Auth'] | |
session.headers = { | |
'Authorization': 'GoogleLogin auth=' + auth, | |
'User-Agent': 'Android- (api=1,versionCode=8011000)', | |
'X-DFE-Device-Id': android_id, | |
} | |
# Step 2. Get Latest Version | |
if not version: | |
data = session.get( | |
url_root + 'fdfe/details', | |
params = { | |
'doc': packname | |
}).content | |
version = parse_pb_path(data, 1, 2, 4, 13, 1, 3) | |
# Step 3. Get Download URL + Auth | |
data = session.post( | |
url_root + 'fdfe/purchase', | |
data = { | |
'doc': packname, | |
'vc': version, | |
#'ot': 1, # not needed? | |
}).content | |
tmp = parse_pb_path(data, 1, 4, 39, 8) | |
url = parse_pb_path(tmp, 3) | |
mda = parse_pb_path(tmp, 5, 2) | |
# Step 4. Download APK file | |
apk = requests.get( | |
parse_utf8(url), | |
cookies = { | |
'MarketDA': str(int(mda)) | |
} | |
).content | |
# 'apk' is now your apk file ready to read or save to file! | |
# Alternatively, open as a zip file to read: | |
import zipfile | |
zf = zipfile.ZipFile(io.BytesIO(apk)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Currently no longer works - Google changed the interface slightly - the APK version number is no longer stored in 1/2/4/13/1/3.