GithubHelp home page GithubHelp logo

nomore201 / googleplay-api Goto Github PK

View Code? Open in Web Editor NEW
401.0 40.0 206.0 2.88 MB

Google Play Unofficial Python API

License: Other

Python 98.15% Shell 1.85%
google googleplay-api playstore api apk download

googleplay-api's Introduction

Google play python API Build Status

This project contains an unofficial API for google play interactions. The code mainly comes from GooglePlayAPI project which is not maintained anymore. The code was updated with some important changes:

  • ac2dm authentication with checkin and device info upload
  • updated search and download calls
  • select the device you want to fake from a list of pre-defined values (check device.properties) (defaults to a OnePlus One)

Build

This is the recommended way to build the package, since setuptools will take care of generating the googleplay_pb2.py file needed by the library (check the setup.py)

$ python setup.py build

Usage

Check scripts in test directory for more examples on how to use this API.

from gpapi.googleplay import GooglePlayAPI

mail = "[email protected]"
passwd = "mypasswd"

api = GooglePlayAPI(locale="en_US", timezone="UTC", device_codename="hero2lte")
api.login(email=mail, password=passwd)

result = api.search("firefox")

for doc in result:
    if 'docid' in doc:
        print("doc: {}".format(doc["docid"]))
    for cluster in doc["child"]:
        print("\tcluster: {}".format(cluster["docid"]))
        for app in cluster["child"]:
            print("\t\tapp: {}".format(app["docid"]))

For first time logins, you should only provide email and password. The module will take care of initalizing the api, upload device information to the google account you supplied, and retrieving a Google Service Framework ID (which, from now on, will be the android ID of your fake device).

For the next logins you should save the gsfId and the authSubToken, and provide them as parameters to the login function. If you login again with email and password, this is the equivalent of re-initalizing your android device with a google account, invalidating previous gsfId and authSubToken.

googleplay-api's People

Contributors

ahnmo avatar antoinet avatar gurnec avatar kar avatar matlink avatar nomore201 avatar sebsz avatar sweisgerber-dev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

googleplay-api's Issues

versionString is empty for all bulk AppDetails

When using the api.bulkDetails method, versionString is empty for each app I've tried so far. The versionCode is returned correctly.
When using api.details with the same apps, versionString is set.

However, I'm unsure whether this is a problem of this implementation or Googles API.

Configurable device.properties path

Related to matlink/gplaycli#158, do you think it could be interesting to make the device.properties file configurable?
For example, having

  • one option to specify another path for the device.properties to use
  • one option to force the SDK version to use, independently of the device

Python2

Is supporting python2 something conceivable for you?

Device should be initialized before login()

With previous versions, UserAgent string was fixed, so if the user selected another device, requests were always sent as a Nexus 6P.

With commit 5bbdd19, UserAgent string is based on the selected device. This introduce a problem, since the UserAgent string is needed before the call to getAndroidCheckinRequest(device_codename), resulting in error because the device in config.py isn't initialized.

headers = self.getDefaultHeaders()
headers["Content-Type"] = "application/x-protobuffer"
request = config.getAndroidCheckinRequest(device_codename)

As a temporary workaround, I initialized the device variable right before definition, with default values.

device = {}
# initialize device, because we need to setup UserAgent
# before the end of login method. If the login defines a different
# device, it won't cause conflicts
for (key, value) in config.items('angler'):
device[key] = value

A better approach would be to initialize the device before the login method, for example during the __init__ function, rather than login. This means that the device_codename variable should be supplied to the constructor, rather than the login() function. This of course means also that the current API will break, but I think the changes are minimal.

bulkDetails is down?

I got the following error when using the bulkDetails methods:

/gpapi/googleplay.py:297: RuntimeWarning: Unexpected end-group tag: Not all data was converted
message = googleplay_pb2.ResponseWrapper.FromString(response.content)

Infinite Loops in Login if 401

message = googleplay_pb2.ResponseWrapper.FromString(response.content)

In that line above, I think this should be added response.raise_for_status().

When Logging in with a bad auth token, the code will 401 and loop infinitely when testing the login, eventually hitting a rate limit and getting a 429. We should raise an exception to prevent this from happening.

An unexpected keyword argument "file" on Python2.7

Protobuf version is 3.2.0, i think it should be python version difference. right ?

Error as below:
C:\Users\xxxx\Downloads\googleplay-api-master>python test.py
Traceback (most recent call last):
File "test.py", line 1, in
from gpapi.googleplay import GooglePlayAPI, RequestError
File "C:\Users\xxxx\Downloads\googleplay-api-master\gpapi\googleplay.py", line 14, in
from . import googleplay_pb2, config, utils
File "C:\Users\xxxx\Downloads\googleplay-api-master\gpapi\googleplay_pb2.py", line 41, in
options=None, file=DESCRIPTOR),
TypeError: init() got an unexpected keyword argument 'file'

LoginError: 'server says: NeedsBrowser'

Using python 3 (3.4.3) i get this:

python3 test.py

Logging in with email and password

Traceback (most recent call last):
  File "test.py", line 14, in <module>
    server.login(EMAIL, PASSWD, None, None)
  File "/home/wetterfroschdus/googleplay-api/gpapi/googleplay.py", line 198, in login
    raise LoginError("server says: " + params["error"])
gpapi.googleplay.LoginError: "server says: NeedsBrowser"

Any ideas? I actually never used a phone on the account I'm trying to use. Could it be related to that?

Ability to reuse gsf-ids instead of creating new ones each time?

Hello @NoMore201,

It seems that I'm a bit confused right now on how to properly use this. I've noticed that NoMore201/googleplay-api supports two methods to authenticate with Google - either I

  1. specify a token and gsf-id, or
  2. specify an email and password

If I use method 1. Everything works as long as I specify a valid token and gsf-id in the constructor, and that device already exists in the Google account.
If I use method 2, every time it creates a new gsf-id and uploads my device config using uploadDeviceConfig(). This works the way I want it to, but it feels like creating new gsf-ids every single time for the same device is a waste.

What I'm looking for is a way to reuse gsf-ids but create new ones only when they expire or stop working.

Ideally googleplay-api would accept an auth token as well as an email, password, gsf-id and device codename. It should then check if the auth token and gsf-id are valid. If they are not, it could use the email and password to create a new gsf-id and upload the device config. However, it should return the gsf-id and auth token to me somehow so I can store it somewhere. Then I also don't need to use token-dispenser.

I also use @matlink gplaycli, but I'm working on modifying it to better suit my needs (I added a command line parameter to get --details). I feel like these libraries can work better together. Why are we using token-dispenser to get authentication tokens, when NoMore201/googleplay-api also supports getting authentication tokens?

I hope what I managed to type makes sense. Please let me know if I got any of this wrong. Thanks for all your work.

No exception when 'RuntimeWarning: Unexpected end-group tag: Not all data was converted'

When token is expired or invalid, the login() method throws a warning in search('firefox', 1, None):

RuntimeWarning: Unexpected end-group tag: Not all data was converted
  message = googleplay_pb2.ResponseWrapper.FromString(response.content)

However, since it's not an exception, program is waiting on this instruction.
I found something interesting, I don't know if you find another better way to achieve it:

https://github.com/matlink/googleplay-api/blob/0bc1382be545e7d99321cfd6b1207f9158d4c7ba/gpapi/googleplay.py#L201-L206

"GET /fdfe/delivery HTTP/1.1" 400 1555

I am able to retrieve the download token after sending the purchase request. But while trying to get the download URL while sending he delivery request, I'm facing the Bad Request error. Could anyone please help me with this?

Play Store Rate-limits Requests

As described in my PR (#41), the current implementation of the code doesn't handle Google's rate-limiting gracefully.

However, there is also the question of why I'm encountering rate-limiting in the first place. I've created this issue to track my investigations into that problem.

Improve test file

test.py should include the following APIs:

  • reviews
  • details (single)
  • browse
  • list

Progress bar slows down download

Using progress_bar ETA slows down a lot the download speed.

$ time gplaycli -d com.android.chrome
Download complete

real	0m56,885s
user	0m1,216s
sys	0m1,732s

$ time gplaycli -pd com.android.chrome
[################################] 65251/65251 - 00:06:51
Download complete

real	6m57,780s
user	4m33,336s
sys	2m17,204s

This is due to the chunk_size in the progress.bar which should be bigger, except that I can't find a way not to break the real progression.

ValueError: Unknown format code 'x' for object of type 'str'

Thanks for this amazing code. While trying to login with gsfid and token, I get an error ValueError: Unknown format code 'x' for object of type 'str' (Python 2.7.12). Am I getting this error due to my Python version? If yes, then is there any fix for the version 2.7.x? Thanks in advance.

p.s. I tested with Python Python 3.5.2 and still get ValueError: Unknown format code 'x' for object of type 'str' error

The new Dynamic Delivery and split APKs

https://developer.android.com/guide/app-bundle/configure#split_apks

This is a huge problem for us, I really hope there's a flag to ask Google Play for the most complete APK somehow.

Now not only will Google Play start serving variants/splits based on the usual dpi/minapi/arch but also now based on locale/language. And further, much worse, there are now dynamic feature apks coming.

So one app on the same device can be comprised of several APKs - base, configuration, and feature APKs.

And the number of permutations is now huge.

How do we overcome this? What I'm really hoping for is a flag of some sort for the API that would instruct it to serve the fullest APK available - the app bundle itself - instead of the split APKs, but I'm not optimistic.

@NoMore201 @matlink @SeBsZ

Some FREE apps aren't being downloaded

com.ea.gp.fifaworld is a free game but it can't be downloaded. Can anyone please provide a hardware profile that allows me to download this game? I have tried all devices (profiles) provided with this package with no luck. Any help will be highly appreciated.

search: IndexError: list index out of range

>>> server.search('phongit.quickreboot', 1, None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/site-packages/gpapi/googleplay.py", line 315, in search
    if cluster.doc[0].containerMetadata.nextPageUrl != "":
IndexError: list index out of range

No LICENSE yet

To make redistribution of this software possible, please add a LICENSE to it.
Thankyou for sharing your code - make it legally usable now!

locales without '_' produce runtime error

"POSIX" or "C" are valid locales, but will produce a runtime error, because they don't contain '_'.
This is because of line 98: "Accept-Language": self.deviceBuilder.locale.replace('_', '-')

I would suggest to check it after line 55: if locale is not None:

How to create device profile from a real device?

First, thank you for your amazing project!

I have a given device, And i want to create device.properties entry for it.
What is the most simple way to do so?
Is there any script that can do that?
Thanks!

ImportError: No module named 'gpapi.googleplay'

I work with python 3.5. When I run test.py file I getting following error:

Traceback (most recent call last):
File "test.py", line 1, in
from gpapi.googleplay import GooglePlayAPI, RequestError
ImportError: No module named 'gpapi.googleplay'

Not found gpapi.googleplay but this module is exist. How can ı run this project . Thanks..

gpapi: Security check is needed

Hi all,

I just used the API for about a month or two in the Ubuntu server for downloading APKs for security checking. In the early December, it still worked. But when I just wanted to modify my program and then run again, it shows the followings:

File "/[my program folder]/googleplay.py", line xxx, in login
raise LoginError("Security check is needed, try to visit "
googleplay.LoginError: 'Security check is needed, try to visit https://accounts.google.com/b/0/DisplayUnlockCaptcha to unlock, or setup an app-specific password'

I just provided the GOOGLE_LOGIN and GOOGLE_PASSWORD for the first login. Then I tried to unlock using browser, but it still does not work. So what happened? Thanks!

Keeping device profiles active so Google doesn't think they're not used and mark them inactive?

I've been using DummyDroid to create fake profiles for various devices for years, and recently I noticed some of them stopped working in gplacli, and they also stopped showing up in the dropdown when logged into Google Play on the web.

For example, I was no longer able to download https://play.google.com/store/apps/details?id=com.samsung.android.email.provider with a Samsung profile.

I re-registered the same device specs with DummyDroid, got a new GSFID, and that profile worked right away downloading that Samsung APK.

So obviously Google marks older profiles obsolete, and even downloading using them (with gplaycli) isn't enough to keep them active.

Any idea what API call makes a profile active and keeps it active? A no-op of sorts that tells Google - "hey I'm still alive."

Thanks!

com.asus.deskclock can't download

it report gpapi.googleplay.RequestError: u'\u60a8\u7684\u8bbe\u5907\u4e0e\u6b64\u5546\u54c1\u4e0d\u517c\u5bb9\u3002'

which device id can be used??

Verify changing device is working

I tried to download the com.asus.email app with the t00q device (Asus Zenfone 4), but I still get the Error while retrieving information from server. [DF-DLA-26] error.
Does changing device work for you?

Need setup.py

You need to provide a setup.py script for pip to be able to install it as a dependency.

APK's version code problem

Hi! I'm now facing another problem. When I download the APKs for security checking, I also need to get the information about them, including version code and date. However, what I got about version code is the number that can be larger than 10000, instead of the format as 1.X.XX.XXX. I've just checked the program, finding that the code is come from the line "versionCode": app.details.appDetails.versionCode in line 27 of utils.py. So I wish to know how I can convert the version code to be the one as shown in google play store page? Thanks!

How can I download multiple apk files at the same time?

I started multiple threads to download multiple apk files, but when I downloaded a file and prompted "Segmentation fault", is it that "google play" restricts an account to download only one file at the same time? I don't know, I hope to get help, I am grateful.

list: offset doesn't work

Hi,

I'm trying to list all top free apps in GAME category by changing offset in a loop. But it doesn't work at all. Whatever the offset is, it always returns apps from the beginning.
Ex.
offset=None
appList = server.list(cat, catList[0], nb_results='10')
Ouput
list?c=3&cat=GAME&ctr=apps_topselling_free&n=10
jp.colopl.dpuzzle
com.square_enix.android_googleplay.DQRivals
com.gamecaff.hero
com.bandainamcoent.ninjaborutage_app
jp.co.bandainamcoonline.grasma
com.tiles.piano.animemusic
com.linecorp.LGTMTM
com.YoStarJP.AzurLane
com.nintendo.zara
com.gamestart.fill

offset='5'
appList = server.list(cat, catList[0], nb_results='10', offset='5')
Output
list?c=3&cat=GAME&ctr=apps_topselling_free&n=10&o=5
jp.colopl.dpuzzle
com.square_enix.android_googleplay.DQRivals
com.gamecaff.hero
com.bandainamcoent.ninjaborutage_app
jp.co.bandainamcoonline.grasma
com.tiles.piano.animemusic
com.linecorp.LGTMTM
com.YoStarJP.AzurLane
com.nintendo.zara
com.gamestart.fill

Token expires after a short time

After some time of "inactivity" during a session, google starts answering with empty responses like this:

>>> server.bulkDetails(['org.mozilla.focus'])
[{'docId': '', 'title': '', 'author': '', 'offer': [], 'images': [], 'versionCode': 0, 'installationSize': 0, 'numDownloads': '', 'uploadDate': '', 'files': [], 'unstable': False, 'containsAds': '', 'aggregateRating': {'type': 0, 'starRating': 0.0, 'ratingsCount': 0, 'oneStarRatings': 0, 'twoStarRatings': 0, 'threeStarRatings': 0, 'fourStarRatings': 0, 'fiveStarRatings': 0, 'commentCount': 0}, 'dependencies': [], 'category': {'appType': '', 'appCategory': ''}, 'detailsUrl': ''}]
>>> server.search('termux', 1)
Unexpected behaviour
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/nomore/workspace/nogoogle/googleplay-api/gpapi/googleplay.py", line 292, in search
    cluster = response.payload.listResponse.cluster[0]
IndexError: list index out of range

If you login again, API starts working again until another 5 minutes of inactivity. It seems like the token expires after a short time, but this is strange since auth tokens were thought to be valid for months. I'm quite sure it doesn't depend on gpapi code, but it is a google break.

Steps to reproduce issue:

  • Open a python interactive shell
  • Initialize object and login
from gpapi.googleplay import GooglePlayAPI
server = GooglePlayAPI()
server.login(EMAIL,  PASSWD, None, None)
  • Start playing around with the api, it should work without problems
  • Leave the shell open for some minutes without interaction (in my case 5 minutes was enough)
  • Try to execute another query

Let me know if you can reproduce this behaviour

Implement pytest Test Suite

Before I invest time in solving #43, I plan to implement a simple pytest test suite for the methods I will be changing. I will include instructions for using the test suite in the README.

gpapi-0.3.2: __init__() got an unexpected keyword argument 'file'

this library is used in GPlayCli and it was working fine with v0.3.1.

However, I'm getting the following error with the latest release (0.3.2):

Traceback (most recent call last):
  File "/usr/lib/python-exec/python3.5/gplaycli", line 11, in <module>
    load_entry_point('GPlayCli==3.15', 'console_scripts', 'gplaycli')()
  File "/usr/lib64/python3.5/site-packages/pkg_resources/__init__.py", line 572, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/usr/lib64/python3.5/site-packages/pkg_resources/__init__.py", line 2769, in load_entry_point
    return ep.load()
  File "/usr/lib64/python3.5/site-packages/pkg_resources/__init__.py", line 2422, in load
    return self.resolve()
  File "/usr/lib64/python3.5/site-packages/pkg_resources/__init__.py", line 2428, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/usr/lib64/python3.5/site-packages/gplaycli/gplaycli.py", line 30, in <module>
    from gpapi.googleplay import GooglePlayAPI
  File "/usr/lib64/python3.5/site-packages/gpapi/googleplay.py", line 14, in <module>
    from . import googleplay_pb2, config, utils
  File "/usr/lib64/python3.5/site-packages/gpapi/googleplay_pb2.py", line 41, in <module>
    options=None, file=DESCRIPTOR),
TypeError: __init__() got an unexpected keyword argument 'file'

Would you have any idea what's wrong?

Downloading slows down

Related to matlink/gplaycli#156
In fact, we should find a way to yield chunks of data instead of returning the whole binary data. I found that CPU is at 100% when downloading, which is, I think, due to the memory reallocation of the string.

For now, I have 2 ways to achieve that:

  • yielding chunks in _deliver_data() and in delivery()
  • passing a filename argument to delivery() to directly write down the response

The first one appears to be the most elegant way to me, but it requires more changes in the code.
What do you think?

Apps unavailable due to SharedLibraries line

Steps to reproduce:

  1. Initialize a GooglePlayAPI object with device_codename='bullhead'
  2. Log in to Google account
  3. Request details for package com.wsl.noom
  4. No version code is returned (i.e., app is unavailable for the device)

Steps to resolve:

  1. In device.properties, under the bullhead section, append com.google.android.maps to the SharedLibraries line
  2. Follow steps to reproduce
  3. A valid version code is returned (i.e., app is available for this device)

Other apps fail to download due to different missing SharedLibraries.

I have a physical bullhead (Nexus 5X) device that shows that this app is indeed available for this platform, but gpapi receives a response from the Play Store that it's not. This is because gpapi's bullhead definition is missing a SharedLibraries entry. Given this target device, how do I regenerate and update bullhead's SharedLibraries line to accurately reflect what's really available on the Nexus 5X, allowing me to use gpapi to download apps that will run on this?

Ability to retrieve Play Store last updated date?

Hey,

I'm wondering if it's possible to make an API call to retrieve the date an app was last updated on the Play Store? It's listed on the Play Store under additional information where it says "Updated": eg. https://play.google.com/store/apps/details?id=com.android.chrome

I looked through the protobuf definition as well as googleplay.py and googleplay_pb2.py but I doesn't look like this field is currently returned.

Does anyone have an idea? Thanks in advance!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.