Skip to content

Instantly share code, notes, and snippets.

@DosAmp
Last active September 6, 2017 05:53
Show Gist options
  • Save DosAmp/6484554 to your computer and use it in GitHub Desktop.
Save DosAmp/6484554 to your computer and use it in GitHub Desktop.
Parse output of `pm list packages -f` on Android
import fileinput
import re
import http.client
import html.parser
URI_PREFIX = '/store/apps/details?id='
REGEXP_JAVA_PACKAGE = r"(?P<pkg>([a-z_][a-z0-9_]*(\.[a-z_][a-z0-9_]*)*))$"
REGEXP_PACKAGE_LIST = r"package:(?P<path>/.*\.apk)=" + REGEXP_JAVA_PACKAGE
#REQUEST_HEADERS = {'Accept-Language': 'en'}
empty_none = lambda s: s or ''
csv = lambda i: ';'.join(i)
class PlayStoreAppNameHTMLParser(html.parser.HTMLParser):
def __init__(self):
super().__init__()
# __app_name_found replaced by truth check on app_name
self.__inner_div_follows = False
self.__app_name_follows = False
self.app_name = None
def handle_starttag(self, tag, attrs):
if tag != 'div' or self.app_name:
return
if self.__inner_div_follows:
self.__app_name_follows = True
self.__inner_div_follows = False
elif ('itemprop', 'name') in attrs:
self.__inner_div_follows = True
def handle_data(self, data):
if self.__app_name_follows:
self.app_name = data.strip()
self.__app_name_follows = False
def app_type(path):
if path.startswith('/system/app'):
return 'System'
elif path.startswith('/data/app'):
return 'Store'
elif path.startswith('/mnt/asec'):
return 'Protected'
else:
return 'Other'
def app_name(conn, package):
conn.request('GET', URI_PREFIX + package)
response = conn.getresponse()
# read all the data before next request, even if we don't have to parse it
data = response.read()
if (response.status != http.client.OK): return
# TODO just decoding the first ~128K seems enough, use errors='ignore' then
parser = PlayStoreAppNameHTMLParser()
parser.feed(data.decode('UTF-8'))
return parser.app_name
playstore = http.client.HTTPSConnection('play.google.com')
print(csv(['Name', 'Type', 'Package name']))
for line in fileinput.input():
linematch = re.match(REGEXP_PACKAGE_LIST, line)
if (not linematch): continue
atype = app_type(linematch.group('path'))
aname = app_name(playstore, linematch.group('pkg'))
print(csv([empty_none(aname), atype, linematch.group('pkg')]), flush=True)
playstore.close()
@hram
Copy link

hram commented Sep 6, 2017

print(csv([empty_none(aname), atype, linematch.group('pkg')]), flush=True)
^
SyntaxError: invalid syntax

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment