apksearch 1.2.6__py3-none-any.whl → 1.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- apksearch/__init__.py +13 -2
- apksearch/cli.py +65 -2
- apksearch/sites/apkad.py +1 -1
- apksearch/sites/apkmonk.py +108 -0
- apksearch/sites/apkpure.py +59 -0
- apksearch/sites/aptoide.py +118 -0
- {apksearch-1.2.6.dist-info → apksearch-1.3.0.dist-info}/METADATA +21 -7
- apksearch-1.3.0.dist-info/RECORD +18 -0
- {apksearch-1.2.6.dist-info → apksearch-1.3.0.dist-info}/WHEEL +1 -1
- apksearch-1.2.6.dist-info/RECORD +0 -16
- {apksearch-1.2.6.dist-info → apksearch-1.3.0.dist-info}/entry_points.txt +0 -0
- {apksearch-1.2.6.dist-info → apksearch-1.3.0.dist-info/licenses}/LICENSE +0 -0
- {apksearch-1.2.6.dist-info → apksearch-1.3.0.dist-info}/top_level.txt +0 -0
apksearch/__init__.py
CHANGED
@@ -3,6 +3,17 @@ from .sites.apkmirror import APKMirror
|
|
3
3
|
from .sites.appteka import AppTeka
|
4
4
|
from .sites.apkcombo import APKCombo
|
5
5
|
from .sites.apkfab import APKFab
|
6
|
-
from .sites.apkad import
|
6
|
+
from .sites.apkad import APKad
|
7
|
+
from .sites.aptoide import Aptoide
|
8
|
+
from .sites.apkmonk import APKMonk
|
7
9
|
|
8
|
-
__all__ = [
|
10
|
+
__all__ = [
|
11
|
+
"APKPure",
|
12
|
+
"APKMirror",
|
13
|
+
"AppTeka",
|
14
|
+
"APKCombo",
|
15
|
+
"APKFab",
|
16
|
+
"APKad",
|
17
|
+
"Aptoide",
|
18
|
+
"APKMonk",
|
19
|
+
]
|
apksearch/cli.py
CHANGED
@@ -1,7 +1,16 @@
|
|
1
1
|
import argparse
|
2
2
|
|
3
3
|
from collections.abc import Callable
|
4
|
-
from apksearch import
|
4
|
+
from apksearch import (
|
5
|
+
APKPure,
|
6
|
+
APKMirror,
|
7
|
+
AppTeka,
|
8
|
+
APKCombo,
|
9
|
+
APKFab,
|
10
|
+
APKad,
|
11
|
+
Aptoide,
|
12
|
+
APKMonk,
|
13
|
+
)
|
5
14
|
from requests.exceptions import ConnectionError, ConnectTimeout
|
6
15
|
|
7
16
|
# Color codes
|
@@ -80,7 +89,7 @@ def search_apkfab(pkg_name: str, version: str | None) -> None:
|
|
80
89
|
|
81
90
|
|
82
91
|
def search_apkad(pkg_name: str, version: str | None) -> None:
|
83
|
-
apkad =
|
92
|
+
apkad = APKad(pkg_name)
|
84
93
|
try:
|
85
94
|
result_apkad: tuple[str, str] | None = apkad.search_apk()
|
86
95
|
except (ConnectionError, ConnectTimeout):
|
@@ -167,6 +176,56 @@ def search_appteka(pkg_name: str, version: str | None) -> None:
|
|
167
176
|
print(f"{BOLD}AppTeka:{NC} No Results!")
|
168
177
|
|
169
178
|
|
179
|
+
def search_aptoide(pkg_name: str, version: str | None) -> None:
|
180
|
+
aptoide = Aptoide(pkg_name)
|
181
|
+
try:
|
182
|
+
result_aptoide: tuple[str, str] | None = aptoide.search_apk()
|
183
|
+
except (ConnectionError, ConnectTimeout):
|
184
|
+
result_aptoide = None
|
185
|
+
print(f"{RED}Failed to resolve 'aptoide.com'!{NC}")
|
186
|
+
if result_aptoide:
|
187
|
+
title, apk_link = result_aptoide
|
188
|
+
print(f"{BOLD}Aptoide:{NC} Found {GREEN}{title}{NC}") if title else None
|
189
|
+
print(f" ╰─> {BOLD}Link: {YELLOW}{apk_link}{NC}") if not version else None
|
190
|
+
if version:
|
191
|
+
versions: list[str | None] = aptoide.find_versions(apk_link)
|
192
|
+
if versions:
|
193
|
+
if version in versions:
|
194
|
+
print(
|
195
|
+
f" ╰─> {BOLD}Version: {GREEN}{version}{NC} - {YELLOW}{apk_link}versions{NC}"
|
196
|
+
)
|
197
|
+
else:
|
198
|
+
print(f"{BOLD}Aptoide:{NC} Version {RED}{version}{NC} not found!")
|
199
|
+
else:
|
200
|
+
print(f"{BOLD}Aptoide:{NC} No Results!")
|
201
|
+
|
202
|
+
|
203
|
+
def search_apkmonk(pkg_name: str, version: str | None) -> None:
|
204
|
+
apkmonk = APKMonk(pkg_name)
|
205
|
+
try:
|
206
|
+
result_apkmonk: tuple[str, str] | None = apkmonk.search_apk()
|
207
|
+
except (ConnectionError, ConnectTimeout):
|
208
|
+
result_apkmonk = None
|
209
|
+
print(f"{RED}Failed to resolve 'apkmonk.com'!{NC}")
|
210
|
+
if result_apkmonk:
|
211
|
+
title, apk_link = result_apkmonk
|
212
|
+
print(f"{BOLD}APKMonk:{NC} Found {GREEN}{title}{NC}") if title else None
|
213
|
+
print(f" ╰─> {BOLD}Link: {YELLOW}{apk_link}{NC}") if not version else None
|
214
|
+
if version:
|
215
|
+
versions: list[tuple[str, str]] = apkmonk.find_versions(apk_link)
|
216
|
+
if versions:
|
217
|
+
for version_tuple in versions:
|
218
|
+
if version_tuple[0] == version:
|
219
|
+
print(
|
220
|
+
f" ╰─> {BOLD}Version: {GREEN}{version}{NC} - {YELLOW}{version_tuple[1]}{NC}"
|
221
|
+
)
|
222
|
+
break
|
223
|
+
else:
|
224
|
+
print(f"{BOLD}APKMonk:{NC} Version {RED}{version}{NC} not found!")
|
225
|
+
else:
|
226
|
+
print(f"{BOLD}APKMonk:{NC} No Results!")
|
227
|
+
|
228
|
+
|
170
229
|
def main():
|
171
230
|
parser = argparse.ArgumentParser(
|
172
231
|
prog="APKSearch", description="Search for APKs on various websites"
|
@@ -186,6 +245,8 @@ def main():
|
|
186
245
|
search(search_apkpure, pkg_name, version, log_err)
|
187
246
|
# Initiate search on apkmirror
|
188
247
|
search(search_apkmirror, pkg_name, version, log_err)
|
248
|
+
# Initiate search on aptoide
|
249
|
+
search(search_aptoide, pkg_name, version, log_err)
|
189
250
|
# Initiate search on appteka
|
190
251
|
search(search_appteka, pkg_name, version, log_err)
|
191
252
|
# Initiate search on apkcombo
|
@@ -194,6 +255,8 @@ def main():
|
|
194
255
|
search(search_apkfab, pkg_name, version, log_err)
|
195
256
|
# Initiate search on apkad
|
196
257
|
search(search_apkad, pkg_name, version, log_err)
|
258
|
+
# Initiate search on apmonk
|
259
|
+
search(search_apkmonk, pkg_name, version, log_err)
|
197
260
|
|
198
261
|
|
199
262
|
if __name__ == "__main__":
|
apksearch/sites/apkad.py
CHANGED
@@ -0,0 +1,108 @@
|
|
1
|
+
import re
|
2
|
+
import requests
|
3
|
+
from bs4 import BeautifulSoup
|
4
|
+
|
5
|
+
|
6
|
+
class APKMonk:
|
7
|
+
"""
|
8
|
+
This class provides methods to search for an APK on APKMonk based on package name,
|
9
|
+
and to find available versions and their download links for a given APK link.
|
10
|
+
|
11
|
+
Parameters:
|
12
|
+
pkg_name (str): The package name of the APK to search for.
|
13
|
+
|
14
|
+
Attributes:
|
15
|
+
pkg_name (str): The package name of the APK to search for.
|
16
|
+
base_url (str): The base URL of the APKMonk website.
|
17
|
+
search_url (str): The URL used to search for APKs on APKMonk.
|
18
|
+
headers (dict): The headers used for making HTTP requests.
|
19
|
+
session (requests.Session): The session object used for making HTTP requests.
|
20
|
+
|
21
|
+
Methods:
|
22
|
+
search_apk() -> None | tuple[str, str]:
|
23
|
+
Searches for the APK on APKMonk and returns the title and link if found.
|
24
|
+
|
25
|
+
find_versions(apk_link: str) -> list[tuple[str, str]]:
|
26
|
+
Finds and returns a list of versions and their download links for the given APK link.
|
27
|
+
"""
|
28
|
+
|
29
|
+
def __init__(self, pkg_name: str):
|
30
|
+
self.pkg_name = pkg_name
|
31
|
+
self.base_url = "https://www.apkmonk.com"
|
32
|
+
self.search_url = self.base_url + "/ssearch?q="
|
33
|
+
self.headers = {
|
34
|
+
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
35
|
+
"accept-language": "en-US,en;q=0.9,en-IN;q=0.8",
|
36
|
+
"cache-control": "no-cache",
|
37
|
+
"dnt": "1",
|
38
|
+
"pragma": "no-cache",
|
39
|
+
"priority": "u=0, i",
|
40
|
+
"referer": "https://www.apkmonk.com/",
|
41
|
+
"sec-ch-ua": '"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
|
42
|
+
"sec-ch-ua-mobile": "?0",
|
43
|
+
"sec-ch-ua-platform": '"Windows"',
|
44
|
+
"sec-fetch-dest": "document",
|
45
|
+
"sec-fetch-mode": "navigate",
|
46
|
+
"sec-fetch-site": "same-origin",
|
47
|
+
"sec-fetch-user": "?1",
|
48
|
+
"upgrade-insecure-requests": "1",
|
49
|
+
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0",
|
50
|
+
}
|
51
|
+
self.session = requests.Session()
|
52
|
+
|
53
|
+
def search_apk(self) -> None | tuple[str, str]:
|
54
|
+
"""
|
55
|
+
Searches for the APK on APKMonk and returns the title and link if found.
|
56
|
+
|
57
|
+
Returns:
|
58
|
+
None: If no matching APK is found.
|
59
|
+
tuple[str, str]: A tuple containing the title and link of the matching APK if found.
|
60
|
+
"""
|
61
|
+
pkg_name = self.pkg_name
|
62
|
+
url = self.search_url + pkg_name
|
63
|
+
response: requests.Response = self.session.get(url, headers=self.headers)
|
64
|
+
soup = BeautifulSoup(response.text, "html.parser")
|
65
|
+
search_results = soup.find("a", {"title": re.compile(".*apk$")})
|
66
|
+
if search_results:
|
67
|
+
link = search_results["href"]
|
68
|
+
title = search_results.find("span", {"class": "af-title truncate"}).text
|
69
|
+
if link == f"/app/{pkg_name}/":
|
70
|
+
return title, f"{self.base_url}{link}"
|
71
|
+
return None
|
72
|
+
|
73
|
+
def find_versions(self, apk_link: str) -> list[tuple[str, str]]:
|
74
|
+
"""
|
75
|
+
Finds and returns a list of versions and their download links for the given APK link.
|
76
|
+
|
77
|
+
Parameters:
|
78
|
+
apk_link (str): The link to the APK on the APKMonk website.
|
79
|
+
|
80
|
+
Returns:
|
81
|
+
list[tuple[str, str]]: A list of tuples, where each tuple contains the version number
|
82
|
+
and its corresponding download link. If no versions are found, an empty list is returned.
|
83
|
+
"""
|
84
|
+
versions_info = []
|
85
|
+
if apk_link.startswith(self.base_url):
|
86
|
+
url = apk_link
|
87
|
+
response: requests.Response = self.session.get(url, headers=self.headers)
|
88
|
+
soup = BeautifulSoup(response.text, "html.parser")
|
89
|
+
|
90
|
+
version_header = soup.find(
|
91
|
+
"div",
|
92
|
+
{"class": "box-title"},
|
93
|
+
text=re.compile("All Versions", re.IGNORECASE),
|
94
|
+
)
|
95
|
+
|
96
|
+
if version_header:
|
97
|
+
versions_table = version_header.find_next("table", {"class": "striped"})
|
98
|
+
|
99
|
+
if versions_table:
|
100
|
+
rows = versions_table.find_all("tr")
|
101
|
+
for row in rows:
|
102
|
+
version_link = row.find("a", href=True)
|
103
|
+
if version_link:
|
104
|
+
version_number = version_link.text.strip()
|
105
|
+
download_url = self.base_url + version_link["href"]
|
106
|
+
versions_info.append((version_number, download_url))
|
107
|
+
|
108
|
+
return versions_info
|
apksearch/sites/apkpure.py
CHANGED
@@ -32,6 +32,19 @@ class APKPure:
|
|
32
32
|
self.cdn_url = "https://d.cdnpure.com/b/APK/"
|
33
33
|
self.cdn_version = "?version="
|
34
34
|
self.search_url = self.base_url + "/search?q="
|
35
|
+
self.api_url = "https://tapi.pureapk.com/v3/get_app_his_version"
|
36
|
+
self.api_headers = {
|
37
|
+
"User-Agent-WebView": "Mozilla/5.0 (Linux; Android 13; Pixel 5 Build/TQ3A.230901.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/132.0.6834.122 Safari/537.36",
|
38
|
+
"User-Agent": "Dalvik/2.1.0 (Linux; U; Android 13; Pixel 5 Build/TQ3A.230901.001); APKPure/3.20.34 (Aegon)",
|
39
|
+
"Ual-Access-Businessid": "projecta",
|
40
|
+
"Ual-Access-ProjectA": """{"device_info":{"abis":["x86_64","arm64-v8a","x86","armeabi-v7a","armeabi"],"android_id":"50f838123d9a9c94","brand":"google","country":"United States","country_code":"US","imei":"","language":"en-US","manufacturer":"Google","mode":"Pixel 5","os_ver":"33","os_ver_name":"13","platform":1,"product":"redfin","screen_height":1080,"screen_width":1920},"host_app_info":{"build_no":"468","channel":"","md5":"6756e53158d6f6c013650a40d8f1147b","pkg_name":"com.apkpure.aegon","sdk_ver":"3.20.34","version_code":3203427,"version_name":"3.20.34"}}""",
|
41
|
+
"Ual-Access-ExtInfo": """{"ext_info":"{\"gaid\":\"\",\"oaid\":\"\"}","lbs_info":{"accuracy":0.0,"city":"","city_code":0,"country":"","country_code":"","district":"","latitude":0.0,"longitude":0.0,"province":"","street":""}}""",
|
42
|
+
"Ual-Access-Sequence": "",
|
43
|
+
"Ual-Access-Nonce": "21448252",
|
44
|
+
"Ual-Access-Timestamp": "1738560597165",
|
45
|
+
"Connection": "Keep-Alive",
|
46
|
+
"Accept-Encoding": "gzip",
|
47
|
+
}
|
35
48
|
self.headers = {
|
36
49
|
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
37
50
|
"accept-language": "en-US,en;q=0.9,en-IN;q=0.8",
|
@@ -52,6 +65,40 @@ class APKPure:
|
|
52
65
|
}
|
53
66
|
self.session = requests.Session()
|
54
67
|
|
68
|
+
def _api_search(self) -> None | tuple[str, list[tuple[str, str]]]:
|
69
|
+
"""
|
70
|
+
Attempts to fetch app information using API.
|
71
|
+
|
72
|
+
Returns:
|
73
|
+
None: If API request fails or no data found
|
74
|
+
tuple[str, list[tuple[str, str]]]: App title and list of (version, download_url) tuples
|
75
|
+
"""
|
76
|
+
try:
|
77
|
+
params = {"package_name": self.pkg_name, "hl": "en"}
|
78
|
+
response = self.session.get(
|
79
|
+
self.api_url, headers=self.api_headers, params=params
|
80
|
+
)
|
81
|
+
data = response.json()
|
82
|
+
|
83
|
+
if not data.get("version_list"):
|
84
|
+
return None
|
85
|
+
|
86
|
+
versions_info = []
|
87
|
+
title = None
|
88
|
+
|
89
|
+
for version in data["version_list"]:
|
90
|
+
version_name = version["version_name"]
|
91
|
+
if not title:
|
92
|
+
title = version["title"]
|
93
|
+
if version.get("asset", {}).get("urls"):
|
94
|
+
download_url = version["asset"]["urls"][0]
|
95
|
+
versions_info.append((version_name, download_url))
|
96
|
+
|
97
|
+
return (title, versions_info) if title and versions_info else None
|
98
|
+
|
99
|
+
except Exception:
|
100
|
+
return None
|
101
|
+
|
55
102
|
def search_apk(self) -> None | tuple[str, str]:
|
56
103
|
"""
|
57
104
|
Searches for the APK on APKPure and returns the title and link if found.
|
@@ -60,6 +107,14 @@ class APKPure:
|
|
60
107
|
None: If no matching APK is found.
|
61
108
|
tuple[str, str]: A tuple containing the title and link of the matching APK if found.
|
62
109
|
"""
|
110
|
+
# Try API first
|
111
|
+
api_result = self._api_search()
|
112
|
+
if api_result:
|
113
|
+
title, versions = api_result
|
114
|
+
if versions:
|
115
|
+
return title, versions[0][1]
|
116
|
+
|
117
|
+
# Fall back to web scrapping
|
63
118
|
pkg_name = self.pkg_name
|
64
119
|
url = self.search_url + pkg_name
|
65
120
|
response: requests.Response = self.session.get(url, headers=self.headers)
|
@@ -110,6 +165,10 @@ class APKPure:
|
|
110
165
|
list[tuple[str, str]]: A list of tuples, where each tuple contains the version number
|
111
166
|
and its corresponding download link. If no versions are found, an empty list is returned.
|
112
167
|
"""
|
168
|
+
api_result = self._api_search()
|
169
|
+
if api_result:
|
170
|
+
return api_result[1]
|
171
|
+
|
113
172
|
versions_info = []
|
114
173
|
if apk_link.startswith(self.base_url):
|
115
174
|
url = apk_link + "/versions"
|
@@ -0,0 +1,118 @@
|
|
1
|
+
import re
|
2
|
+
from bs4 import BeautifulSoup
|
3
|
+
import requests
|
4
|
+
|
5
|
+
|
6
|
+
class Aptoide:
|
7
|
+
"""
|
8
|
+
This class provides methods to search for an APK on Aptoide based on package name,
|
9
|
+
and to find available versions and their download links for a given APK link.
|
10
|
+
|
11
|
+
Parameters:
|
12
|
+
pkg_name (str): The package name of the APK to search for.
|
13
|
+
|
14
|
+
Attributes:
|
15
|
+
pkg_name (str): The package name of the APK to search for.
|
16
|
+
api_url (str): The base URL for the Aptoide API.
|
17
|
+
search_url (str): The URL used to search for APKs on Aptoide.
|
18
|
+
headers (dict): The headers used for making HTTP requests.
|
19
|
+
session (requests.Session): The session object used for making HTTP requests.
|
20
|
+
|
21
|
+
Methods:
|
22
|
+
search_apk() -> None | tuple[str, str]:
|
23
|
+
Searches for the APK on Aptoide and returns the title and link if found.
|
24
|
+
|
25
|
+
find_versions(apk_link: str) -> list[str | None]:
|
26
|
+
Finds and returns a list of versions for the given APK link.
|
27
|
+
"""
|
28
|
+
|
29
|
+
def __init__(self, pkg_name: str):
|
30
|
+
self.pkg_name = pkg_name
|
31
|
+
self.api_url = "https://ws75.aptoide.com/api/7"
|
32
|
+
self.search_url = f"{self.api_url}/apps/search"
|
33
|
+
self.headers = {
|
34
|
+
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
35
|
+
"accept-language": "en-US,en;q=0.9,en-IN;q=0.8",
|
36
|
+
"cache-control": "no-cache",
|
37
|
+
"dnt": "1",
|
38
|
+
"pragma": "no-cache",
|
39
|
+
"priority": "u=0, i",
|
40
|
+
"referer": "https://en.aptoide.com/",
|
41
|
+
"sec-ch-ua": '"Not A(Brand";v="8", "Chromium";v="132", "Microsoft Edge";v="132"',
|
42
|
+
"sec-ch-ua-mobile": "?0",
|
43
|
+
"sec-ch-ua-platform": '"Windows"',
|
44
|
+
"sec-fetch-dest": "document",
|
45
|
+
"sec-fetch-mode": "navigate",
|
46
|
+
"sec-fetch-site": "same-origin",
|
47
|
+
"sec-fetch-user": "?1",
|
48
|
+
"upgrade-insecure-requests": "1",
|
49
|
+
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0",
|
50
|
+
}
|
51
|
+
self.params = {
|
52
|
+
"cdn": "web",
|
53
|
+
"q": "bXlDUFU9YXJtNjQtdjhhLGFybWVhYmktdjdhLGFybWVhYmkmbGVhbmJhY2s9MA",
|
54
|
+
"aab": "1",
|
55
|
+
"mature": "false",
|
56
|
+
"language": "en_US",
|
57
|
+
"country": "US",
|
58
|
+
"not_apk_tags": "",
|
59
|
+
"query": self.pkg_name,
|
60
|
+
"limit": "1",
|
61
|
+
"offset": "0",
|
62
|
+
"origin": "SITE",
|
63
|
+
"store_name": "aptoide-web",
|
64
|
+
}
|
65
|
+
self.session = requests.Session()
|
66
|
+
|
67
|
+
def search_apk(self) -> None | tuple[str, str]:
|
68
|
+
"""
|
69
|
+
Searches for the APK on Aptoide and returns the title and link if found.
|
70
|
+
|
71
|
+
Returns:
|
72
|
+
None: If no matching APK is found.
|
73
|
+
tuple[str, str]: A tuple containing the title and link of the matching APK if found.
|
74
|
+
"""
|
75
|
+
pkg_name = self.pkg_name
|
76
|
+
url = self.search_url
|
77
|
+
response: requests.Response = self.session.get(
|
78
|
+
url, headers=self.headers, params=self.params
|
79
|
+
)
|
80
|
+
data = response.json()
|
81
|
+
if data and data["info"]["status"] == "OK":
|
82
|
+
lis = data["datalist"]["list"]
|
83
|
+
if lis:
|
84
|
+
package = data["datalist"]["list"][0]["package"]
|
85
|
+
apk_title = data["datalist"]["list"][0]["name"]
|
86
|
+
if package == pkg_name:
|
87
|
+
app_id: int = data["datalist"]["list"][0]["id"]
|
88
|
+
meta_url = self.api_url + f"/app/getMeta?app_id={app_id}"
|
89
|
+
meta_response: requests.Response = self.session.get(
|
90
|
+
meta_url, headers=self.headers
|
91
|
+
)
|
92
|
+
meta_data = meta_response.json()
|
93
|
+
if meta_data and meta_data["info"]["status"] == "OK":
|
94
|
+
url = meta_data["data"]["urls"]["w"].split("?")[0]
|
95
|
+
return apk_title, url
|
96
|
+
return None
|
97
|
+
|
98
|
+
def find_versions(self, apk_link: str) -> list[str | None]:
|
99
|
+
"""
|
100
|
+
Finds and returns a list of versions for the given APK link.
|
101
|
+
|
102
|
+
Parameters:
|
103
|
+
apk_link (str): The link to the APK on the Aptoide website.
|
104
|
+
|
105
|
+
Returns:
|
106
|
+
list[str | None]: A list of version strings for the given APK link.
|
107
|
+
"""
|
108
|
+
versions_info = []
|
109
|
+
|
110
|
+
url = apk_link + "/versions"
|
111
|
+
response: requests.Response = self.session.get(url, headers=self.headers)
|
112
|
+
soup = BeautifulSoup(response.content, "html.parser")
|
113
|
+
version_spans = soup.find_all("span", string=re.compile(r"^\d+\.\d+\.\d+$"))
|
114
|
+
for span in version_spans:
|
115
|
+
version = span.text
|
116
|
+
versions_info.append(version)
|
117
|
+
|
118
|
+
return versions_info
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: apksearch
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.3.0
|
4
4
|
Summary: Search for apks on varius websites
|
5
5
|
Author-email: Abhi <allinoneallinone00@gmail.com>
|
6
6
|
License: MIT License
|
@@ -49,6 +49,7 @@ Provides-Extra: dev
|
|
49
49
|
Requires-Dist: pytest>=7.4.3; extra == "dev"
|
50
50
|
Requires-Dist: black>=23.12.1; extra == "dev"
|
51
51
|
Requires-Dist: flake8>=6.1.0; extra == "dev"
|
52
|
+
Dynamic: license-file
|
52
53
|
|
53
54
|
<h1 align="center">apksearch</h1>
|
54
55
|
|
@@ -76,6 +77,7 @@ There were countless occasions when I needed a specific APK for a package name,
|
|
76
77
|
|
77
78
|
- [APKPure](https://apkpure.net/)
|
78
79
|
- [APKMirror](https://www.apkmirror.com/)
|
80
|
+
- [Aptoide](https://en.aptoide.com/)
|
79
81
|
- [APKCombo](https://apkcombo.app/)
|
80
82
|
- [APKFab](https://apkfab.com/)
|
81
83
|
- [Appteka](https://appteka.store/)
|
@@ -89,7 +91,7 @@ There were countless occasions when I needed a specific APK for a package name,
|
|
89
91
|
|
90
92
|
## Installation
|
91
93
|
|
92
|
-
To install the `apksearch` library, use the following command:
|
94
|
+
To install/upgrade the `apksearch` library, use the following command:
|
93
95
|
|
94
96
|
```sh
|
95
97
|
pip install -U git+https://github.com/AbhiTheModder/apksearch.git
|
@@ -101,6 +103,12 @@ OR, through pip:
|
|
101
103
|
pip install -U apksearch
|
102
104
|
```
|
103
105
|
|
106
|
+
OR, if you've cloned the repository locally you can do so via:
|
107
|
+
|
108
|
+
```sh
|
109
|
+
pip install -U . # or path to the local clone
|
110
|
+
```
|
111
|
+
|
104
112
|
## Usage
|
105
113
|
|
106
114
|
### Command-Line Interface
|
@@ -144,19 +152,25 @@ if result:
|
|
144
152
|
#### `APKPure` | `APKCombo` | `APKFab`
|
145
153
|
|
146
154
|
- **`__init__(self, pkg_name: str)`**: Initializes with the package name.
|
147
|
-
- **`search_apk(self) -> None | tuple[str, str]`**: Searches for the APK
|
155
|
+
- **`search_apk(self) -> None | tuple[str, str]`**: Searches for the APK and returns the title and link if found.
|
148
156
|
- **`find_versions(self, apk_link: str) -> list[tuple[str, str]]`**: Finds and returns a list of versions and their download links for the given APK link.
|
149
157
|
|
150
158
|
#### `APKMirror`
|
151
159
|
|
152
160
|
- **`__init__(self, pkg_name: str)`**: Initializes with the package name.
|
153
|
-
- **`search_apk(self) -> None | tuple[str, str]`**: Searches for the APK
|
161
|
+
- **`search_apk(self) -> None | tuple[str, str]`**: Searches for the APK and returns the title and link if found.
|
154
162
|
- **`find_version(self, apk_link: str, version: str) -> str`**: Finds and returns the download link for the given APK link and version.
|
155
163
|
|
156
164
|
#### `AppTeka` | `APKAD`
|
157
165
|
|
158
166
|
- **`__init__(self, pkg_name: str)`**: Initializes with the package name.
|
159
|
-
- **`search_apk(self, version: str = None) -> None | tuple[str, str]`**: Searches for the APK
|
167
|
+
- **`search_apk(self, version: str = None) -> None | tuple[str, str]`**: Searches for the APK and returns the title and link if found. If a version is provided, it checks if that version is available and returns the corresponding download link, None otherwise. If no version is provided, it returns the link for the latest version available.
|
168
|
+
|
169
|
+
#### `Aptoide`
|
170
|
+
|
171
|
+
- **`__init__(self, pkg_name: str)`**: Initializes with the package name.
|
172
|
+
- **`search_apk(self) -> None | tuple[str, str]`**: Searches for the APK and returns the title and link if found.
|
173
|
+
- **`find_versions(self, apk_link: str, version: str) -> list[str]`**: Finds and returns the download links for the given APK link and versions list.
|
160
174
|
|
161
175
|
### Testing
|
162
176
|
|
@@ -173,7 +187,7 @@ pytest
|
|
173
187
|
## Acknowledgements
|
174
188
|
|
175
189
|
- [APKUpdater](https://github.com/rumboalla/apkupdater) for APKMirror API.
|
176
|
-
|
190
|
+
~~- [apkeep](https://github.com/EFForg/apkeep) for APKPure API.~~ (not used anymore)
|
177
191
|
|
178
192
|
## License
|
179
193
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
apksearch/__init__.py,sha256=QvfqsYdMwBGKWiCEnADT1E1m74n5jjjSnrzvasbbZcs,415
|
2
|
+
apksearch/__main__.py,sha256=MSmt_5Xg84uHqzTN38JwgseJK8rsJn_11A8WD99VtEo,61
|
3
|
+
apksearch/cli.py,sha256=gpWmMXzcfGbLUnouSVUZzcxjP7ujWnf0sfqvdwkUIU8,10076
|
4
|
+
apksearch/sites/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
apksearch/sites/apkad.py,sha256=x5nnI20Rj1LysZQc7-vFEbooxXb0vkmHzFpHoUvF_SA,4811
|
6
|
+
apksearch/sites/apkcombo.py,sha256=AiJhSb0subQLb51dr8MQaxgeEZ77wI99InfigYfrcl4,4718
|
7
|
+
apksearch/sites/apkfab.py,sha256=5f0fOBmQk0E30NcVE2cF80soJqI5ziOukU6_xMPtgFQ,5502
|
8
|
+
apksearch/sites/apkmirror.py,sha256=IpS6r7ovM3g2dZrkR_a9zQpHy-jqrU2nJ3ykVkWxers,3127
|
9
|
+
apksearch/sites/apkmonk.py,sha256=85bidRBz6RfZOaS9WEZfTXGnrMVsJEstMJT10XltWus,4657
|
10
|
+
apksearch/sites/apkpure.py,sha256=iXZPzecdBy8JlJmC_yFCQrPi3hXnulRbqg7xCSd3Ppk,8975
|
11
|
+
apksearch/sites/appteka.py,sha256=in04JYF043n0fUvBW1QQeXnNbYekGUIh4qeame951nA,6372
|
12
|
+
apksearch/sites/aptoide.py,sha256=5RruPDwyo5z0E2XesX4Mi41ONdn26SxN0dH36eRolNQ,4816
|
13
|
+
apksearch-1.3.0.dist-info/licenses/LICENSE,sha256=Icu9iAY9cAaraq-HaAk8aWpXS1nE-3U_wfaOhN-HQUw,1061
|
14
|
+
apksearch-1.3.0.dist-info/METADATA,sha256=FXDYFNkHiFEupZa-Y7II6pla6inP8cF6oAjHpUlB_IA,8230
|
15
|
+
apksearch-1.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
16
|
+
apksearch-1.3.0.dist-info/entry_points.txt,sha256=FeAPgNPSU1tCwQNaKAmk6eQYbMHtsltcgeWSGUTxu0k,49
|
17
|
+
apksearch-1.3.0.dist-info/top_level.txt,sha256=VguZMODhlXWwDyJJNJms5syJ4EHmWSQOS45J9I5Cv5o,10
|
18
|
+
apksearch-1.3.0.dist-info/RECORD,,
|
apksearch-1.2.6.dist-info/RECORD
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
apksearch/__init__.py,sha256=ktoWOmWE68fx36Wz8DZWu6E85FXTVjBEuJtvqFxqsI8,288
|
2
|
-
apksearch/__main__.py,sha256=MSmt_5Xg84uHqzTN38JwgseJK8rsJn_11A8WD99VtEo,61
|
3
|
-
apksearch/cli.py,sha256=KjN9UWX_Qt5au05wDJfzUJqmOLnL8-kSI_FzRubrCUk,7670
|
4
|
-
apksearch/sites/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
-
apksearch/sites/apkad.py,sha256=ny7LxUU7vS4o4DT4-uT5SZDgoUd5DnZdMqgXcFYO_ME,4811
|
6
|
-
apksearch/sites/apkcombo.py,sha256=AiJhSb0subQLb51dr8MQaxgeEZ77wI99InfigYfrcl4,4718
|
7
|
-
apksearch/sites/apkfab.py,sha256=5f0fOBmQk0E30NcVE2cF80soJqI5ziOukU6_xMPtgFQ,5502
|
8
|
-
apksearch/sites/apkmirror.py,sha256=IpS6r7ovM3g2dZrkR_a9zQpHy-jqrU2nJ3ykVkWxers,3127
|
9
|
-
apksearch/sites/apkpure.py,sha256=7IUY4u6q6ga_8CFQ1DCaeU_WS2xE70T_7PUU0o20NCk,5941
|
10
|
-
apksearch/sites/appteka.py,sha256=in04JYF043n0fUvBW1QQeXnNbYekGUIh4qeame951nA,6372
|
11
|
-
apksearch-1.2.6.dist-info/LICENSE,sha256=Icu9iAY9cAaraq-HaAk8aWpXS1nE-3U_wfaOhN-HQUw,1061
|
12
|
-
apksearch-1.2.6.dist-info/METADATA,sha256=pK9nEbUbjpcsfvf6WaTvrU_K1btWT29P6QfVFjbdau8,7699
|
13
|
-
apksearch-1.2.6.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
14
|
-
apksearch-1.2.6.dist-info/entry_points.txt,sha256=FeAPgNPSU1tCwQNaKAmk6eQYbMHtsltcgeWSGUTxu0k,49
|
15
|
-
apksearch-1.2.6.dist-info/top_level.txt,sha256=VguZMODhlXWwDyJJNJms5syJ4EHmWSQOS45J9I5Cv5o,10
|
16
|
-
apksearch-1.2.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|