Skip to content

API Reference#

APKCombo #

This class provides methods to search for an APK on APKCombo based on package name, and to find available versions and their download links for a given APK link.

Parameters:

Name Type Description Default
pkg_name str

The package name of the APK to search for.

required

Attributes:

Name Type Description
pkg_name str

The package name of the APK to search for.

base_url str

The base URL of the APKCombo website.

search_url str

The URL used to search for APKs on APKCombo.

headers dict

The headers used for making HTTP requests.

session Session

The session object used for making HTTP requests.

Methods:

Name Description
search_apk

Searches for the APK on APKCombo and returns the title and link if found.

find_versions

str) -> list[tuple[str, str]]: Finds and returns a list of versions and their download links for the given APK link.

Source code in apksearch/sites/apkcombo.py
class APKCombo:
    """
    This class provides methods to search for an APK on APKCombo based on package name,
    and to find available versions and their download links for a given APK link.

    Parameters:
        pkg_name (str): The package name of the APK to search for.

    Attributes:
        pkg_name (str): The package name of the APK to search for.
        base_url (str): The base URL of the APKCombo website.
        search_url (str): The URL used to search for APKs on APKCombo.
        headers (dict): The headers used for making HTTP requests.
        session (requests.Session): The session object used for making HTTP requests.

    Methods:
        search_apk() -> None | tuple[str, str]:
            Searches for the APK on APKCombo and returns the title and link if found.

        find_versions(apk_link: str) -> list[tuple[str, str]]:
            Finds and returns a list of versions and their download links for the given APK link.
    """

    def __init__(self, pkg_name: str):
        self.pkg_name = pkg_name
        self.base_url = "https://apkcombo.com"
        self.search_url = self.base_url + "/search"
        self.headers = {
            "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",
            "accept-language": "en-US,en;q=0.9,en-IN;q=0.8",
            "cache-control": "no-cache",
            "cookie": "__apkcombo_lang=en",
            "dnt": "1",
            "pragma": "no-cache",
            "priority": "u=0, i",
            "referer": "https://apkcombo.com/",
            "sec-ch-ua": '"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": '"Windows"',
            "sec-fetch-dest": "document",
            "sec-fetch-mode": "navigate",
            "sec-fetch-site": "same-origin",
            "sec-fetch-user": "?1",
            "upgrade-insecure-requests": "1",
            "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",
        }
        self.session = requests.Session()

    def search_apk(self) -> None | tuple[str, str]:
        """
        Searches for the APK on APKCombo and returns the title and link if found.

        Returns:
            None: If no matching APK is found.
            tuple[str, str]: A tuple containing the title and link of the matching APK if found.
        """
        pkg_name = self.pkg_name
        url = self.search_url + "/" + pkg_name
        response: requests.Response = self.session.get(
            url, headers=self.headers, allow_redirects=False
        )
        # Redirect to the APK page if there's only one result. i.e, apk found.
        if response.status_code == 302:
            url = self.search_url + response.headers["Location"]
            response: requests.Response = self.session.get(url, headers=self.headers)
        elif response.status_code == 200:  # Package name not found or multiple results.
            return None
        else:
            raise Exception(f"Error: {response.status_code}")
        soup = BeautifulSoup(response.text, "html.parser")
        try:
            title = soup.find("div", {"class": "app_name"}).text.strip()
        except AttributeError:
            return None
        apk_link = url
        return title, apk_link

    def 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.

        Parameters:
            apk_link (str): The link to the APK on the APKCombo website.

        Returns:
            list[tuple[str, str]]: A list of tuples, where each tuple contains the version number
            and its corresponding download link. If no versions are found, an empty list is returned.
        """
        url = apk_link + "/old-versions"
        response: requests.Response = self.session.get(url, headers=self.headers)
        soup = BeautifulSoup(response.text, "html.parser")
        versions_list = soup.find("ul", {"class": "list-versions"})
        versions_info = []

        if versions_list:
            versions = versions_list.find_all("a", {"class": "ver-item"})
            for version in versions:
                version_number = version.find("span", {"class": "vername"}).text
                version_number = version_number.split(" ")[-1]
                download_url = self.base_url + version["href"]
                versions_info.append((version_number, download_url))

        return versions_info

find_versions(apk_link) #

Finds and returns a list of versions and their download links for the given APK link.

Parameters:

Name Type Description Default
apk_link str

The link to the APK on the APKCombo website.

required

Returns:

Type Description
list[tuple[str, str]]

list[tuple[str, str]]: A list of tuples, where each tuple contains the version number

list[tuple[str, str]]

and its corresponding download link. If no versions are found, an empty list is returned.

Source code in apksearch/sites/apkcombo.py
def 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.

    Parameters:
        apk_link (str): The link to the APK on the APKCombo website.

    Returns:
        list[tuple[str, str]]: A list of tuples, where each tuple contains the version number
        and its corresponding download link. If no versions are found, an empty list is returned.
    """
    url = apk_link + "/old-versions"
    response: requests.Response = self.session.get(url, headers=self.headers)
    soup = BeautifulSoup(response.text, "html.parser")
    versions_list = soup.find("ul", {"class": "list-versions"})
    versions_info = []

    if versions_list:
        versions = versions_list.find_all("a", {"class": "ver-item"})
        for version in versions:
            version_number = version.find("span", {"class": "vername"}).text
            version_number = version_number.split(" ")[-1]
            download_url = self.base_url + version["href"]
            versions_info.append((version_number, download_url))

    return versions_info

search_apk() #

Searches for the APK on APKCombo and returns the title and link if found.

Returns:

Name Type Description
None None | tuple[str, str]

If no matching APK is found.

None | tuple[str, str]

tuple[str, str]: A tuple containing the title and link of the matching APK if found.

Source code in apksearch/sites/apkcombo.py
def search_apk(self) -> None | tuple[str, str]:
    """
    Searches for the APK on APKCombo and returns the title and link if found.

    Returns:
        None: If no matching APK is found.
        tuple[str, str]: A tuple containing the title and link of the matching APK if found.
    """
    pkg_name = self.pkg_name
    url = self.search_url + "/" + pkg_name
    response: requests.Response = self.session.get(
        url, headers=self.headers, allow_redirects=False
    )
    # Redirect to the APK page if there's only one result. i.e, apk found.
    if response.status_code == 302:
        url = self.search_url + response.headers["Location"]
        response: requests.Response = self.session.get(url, headers=self.headers)
    elif response.status_code == 200:  # Package name not found or multiple results.
        return None
    else:
        raise Exception(f"Error: {response.status_code}")
    soup = BeautifulSoup(response.text, "html.parser")
    try:
        title = soup.find("div", {"class": "app_name"}).text.strip()
    except AttributeError:
        return None
    apk_link = url
    return title, apk_link

APKCube #

This class provides methods to search for an APK on APKCube based on package name, and to find available versions and their download links for a given APK link.

Parameters:

Name Type Description Default
pkg_name str

The package name of the APK to search for.

required

Attributes:

Name Type Description
pkg_name str

The package name of the APK to search for.

base_url str

The base URL of the APKCube website.

search_url str

The URL used to search for APKs on APKCube.

headers dict

The headers used for making HTTP requests.

session Session

The session object used for making HTTP requests.

Methods:

Name Description
search_apk

Searches for the APK on APKCube and returns the title and link if found.

find_versions

str) -> list[tuple[str, str]]: Finds and returns a list of versions and their download links for the given APK link.

Source code in apksearch/sites/apkcube.py
class APKCube:
    """
    This class provides methods to search for an APK on APKCube based on package name,
    and to find available versions and their download links for a given APK link.

    Parameters:
        pkg_name (str): The package name of the APK to search for.

    Attributes:
        pkg_name (str): The package name of the APK to search for.
        base_url (str): The base URL of the APKCube website.
        search_url (str): The URL used to search for APKs on APKCube.
        headers (dict): The headers used for making HTTP requests.
        session (requests.Session): The session object used for making HTTP requests.

    Methods:
        search_apk() -> None | tuple[str, str]:
            Searches for the APK on APKCube and returns the title and link if found.

        find_versions(apk_link: str) -> list[tuple[str, str]]:
            Finds and returns a list of versions and their download links for the given APK link.
    """

    def __init__(self, pkg_name: str):
        self.pkg_name = pkg_name
        self.base_url = "https://apkcube.com"
        self.search_url = self.base_url + "/search?q="
        self.headers = {
            "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",
            "accept-language": "en-US,en;q=0.9,en-IN;q=0.8",
            "cache-control": "no-cache",
            "dnt": "1",
            "pragma": "no-cache",
            "priority": "u=0, i",
            "referer": "https://apkcube.com/",
            "sec-ch-ua": '"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": '"Windows"',
            "sec-fetch-dest": "document",
            "sec-fetch-mode": "navigate",
            "sec-fetch-site": "same-origin",
            "sec-fetch-user": "?1",
            "upgrade-insecure-requests": "1",
            "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",
        }
        self.session = requests.Session()

    def search_apk(self) -> None | tuple[str, str]:
        """
        Searches for the APK on APKCube and returns the title and link if found.

        Returns:
            None: If no matching APK is found.
            tuple[str, str]: A tuple containing the title and link of the matching APK if found.
        """
        pkg_name = self.pkg_name
        url = self.search_url + pkg_name
        params = {"headers": self.headers}
        if curl:
            params["impersonate"] = "chrome"

        response: requests.Response = self.session.get(url, **params)
        app_path = None
        if (
            response.status_code in (301, 302, 307, 308)
            and "Location" in response.headers
        ):
            app_path = response.headers["Location"]
        elif response.status_code == 200:
            soup = BeautifulSoup(response.text, "html.parser")
            meta = soup.find("meta", {"id": "__next-page-redirect"}) or soup.find(
                "meta", attrs={"http-equiv": lambda x: x and x.lower() == "refresh"}
            )
            if meta and "url=" in meta.get("content", ""):
                app_path = meta["content"].split("url=")[-1].strip()
            elif "NEXT_REDIRECT" in response.text:
                match = re.search(r"NEXT_REDIRECT;[^;]*;([^;]+);", response.text)
                if match:
                    app_path = match.group(1)

            if not app_path:
                for a in soup.find_all("a", href=True):
                    href = a["href"].split("?")[0].rstrip("/")
                    if href.endswith("/" + pkg_name):
                        app_path = a["href"]
                        break
        else:
            return None

        if not app_path:
            return None

        apk_link = urllib.parse.urljoin(self.base_url, app_path)
        if apk_link.split("?")[0].rstrip("/").split("/")[-1] != pkg_name:
            return None

        app_response: requests.Response = self.session.get(apk_link, **params)
        if app_response.status_code != 200:
            return None

        app_soup = BeautifulSoup(app_response.text, "html.parser")
        h1 = app_soup.find("h1")
        if h1:
            apk_title = h1.text.strip()
        elif app_soup.title and app_soup.title.string:
            apk_title = app_soup.title.string.split(" APK")[0].strip()
        else:
            apk_title = pkg_name

        return apk_title, apk_link

    def 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.

        Parameters:
            apk_link (str): The link to the APK on the APKCube website.

        Returns:
            list[tuple[str, str]]: A list of tuples, where each tuple contains the version number
            and its corresponding download link. If no versions are found, an empty list is returned.
        """
        versions_info = []
        seen = set()
        params = {"headers": self.headers}
        if curl:
            params["impersonate"] = "chrome"

        if apk_link.startswith(self.base_url):
            clean_link = apk_link.split("?")[0].rstrip("/")
            url = (
                clean_link
                if clean_link.endswith("/old-versions")
                else clean_link + "/old-versions"
            )
            response: requests.Response = self.session.get(url, **params)
            if response.status_code == 200:
                soup = BeautifulSoup(response.text, "html.parser")
                base_dl_path = clean_link.replace("/old-versions", "") + "/download"
                for a in soup.find_all("a", href=True):
                    href = a["href"]
                    if "/download" in href:
                        parsed = urllib.parse.urlparse(href)
                        # Exclude the general 'Latest version' button without query params
                        if (
                            href.split("?")[0].rstrip("/") == base_dl_path
                            and not parsed.query
                        ):
                            continue
                        qs = urllib.parse.parse_qs(parsed.query)
                        apk_version = qs.get("version", [None])[0]
                        if not apk_version:
                            aria = a.get("aria-label", "")
                            match = re.search(
                                r"Download\s+.*?\s+([0-9]+(?:\.[0-9a-zA-Z\-_]+)+)",
                                aria,
                            )
                            if match:
                                apk_version = match.group(1)
                        if apk_version and apk_version not in seen:
                            seen.add(apk_version)
                            download_url = urllib.parse.urljoin(self.base_url, href)
                            versions_info.append((apk_version, download_url))

            if not versions_info:
                # Fallback to main app page if old-versions was not available
                main_url = clean_link.replace("/old-versions", "")
                response = self.session.get(main_url, **params)
                if response.status_code == 200:
                    soup = BeautifulSoup(response.text, "html.parser")
                    apk_version = None
                    if soup.title and soup.title.string:
                        m = re.search(
                            r"APK\s+([0-9]+(?:\.[0-9a-zA-Z\-_]+)+)\s+Download",
                            soup.title.string,
                        )
                        if m:
                            apk_version = m.group(1)
                    if not apk_version:
                        p = soup.find("p", class_=lambda c: c and "font-mono" in c)
                        if p and re.match(
                            r"^[0-9]+(?:\.[0-9a-zA-Z\-_]+)+$", p.text.strip()
                        ):
                            apk_version = p.text.strip()
                    if apk_version:
                        download_url = main_url + "/download"
                        versions_info.append((apk_version, download_url))

        return versions_info

find_versions(apk_link) #

Finds and returns a list of versions and their download links for the given APK link.

Parameters:

Name Type Description Default
apk_link str

The link to the APK on the APKCube website.

required

Returns:

Type Description
list[tuple[str, str]]

list[tuple[str, str]]: A list of tuples, where each tuple contains the version number

list[tuple[str, str]]

and its corresponding download link. If no versions are found, an empty list is returned.

Source code in apksearch/sites/apkcube.py
def 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.

    Parameters:
        apk_link (str): The link to the APK on the APKCube website.

    Returns:
        list[tuple[str, str]]: A list of tuples, where each tuple contains the version number
        and its corresponding download link. If no versions are found, an empty list is returned.
    """
    versions_info = []
    seen = set()
    params = {"headers": self.headers}
    if curl:
        params["impersonate"] = "chrome"

    if apk_link.startswith(self.base_url):
        clean_link = apk_link.split("?")[0].rstrip("/")
        url = (
            clean_link
            if clean_link.endswith("/old-versions")
            else clean_link + "/old-versions"
        )
        response: requests.Response = self.session.get(url, **params)
        if response.status_code == 200:
            soup = BeautifulSoup(response.text, "html.parser")
            base_dl_path = clean_link.replace("/old-versions", "") + "/download"
            for a in soup.find_all("a", href=True):
                href = a["href"]
                if "/download" in href:
                    parsed = urllib.parse.urlparse(href)
                    # Exclude the general 'Latest version' button without query params
                    if (
                        href.split("?")[0].rstrip("/") == base_dl_path
                        and not parsed.query
                    ):
                        continue
                    qs = urllib.parse.parse_qs(parsed.query)
                    apk_version = qs.get("version", [None])[0]
                    if not apk_version:
                        aria = a.get("aria-label", "")
                        match = re.search(
                            r"Download\s+.*?\s+([0-9]+(?:\.[0-9a-zA-Z\-_]+)+)",
                            aria,
                        )
                        if match:
                            apk_version = match.group(1)
                    if apk_version and apk_version not in seen:
                        seen.add(apk_version)
                        download_url = urllib.parse.urljoin(self.base_url, href)
                        versions_info.append((apk_version, download_url))

        if not versions_info:
            # Fallback to main app page if old-versions was not available
            main_url = clean_link.replace("/old-versions", "")
            response = self.session.get(main_url, **params)
            if response.status_code == 200:
                soup = BeautifulSoup(response.text, "html.parser")
                apk_version = None
                if soup.title and soup.title.string:
                    m = re.search(
                        r"APK\s+([0-9]+(?:\.[0-9a-zA-Z\-_]+)+)\s+Download",
                        soup.title.string,
                    )
                    if m:
                        apk_version = m.group(1)
                if not apk_version:
                    p = soup.find("p", class_=lambda c: c and "font-mono" in c)
                    if p and re.match(
                        r"^[0-9]+(?:\.[0-9a-zA-Z\-_]+)+$", p.text.strip()
                    ):
                        apk_version = p.text.strip()
                if apk_version:
                    download_url = main_url + "/download"
                    versions_info.append((apk_version, download_url))

    return versions_info

search_apk() #

Searches for the APK on APKCube and returns the title and link if found.

Returns:

Name Type Description
None None | tuple[str, str]

If no matching APK is found.

None | tuple[str, str]

tuple[str, str]: A tuple containing the title and link of the matching APK if found.

Source code in apksearch/sites/apkcube.py
def search_apk(self) -> None | tuple[str, str]:
    """
    Searches for the APK on APKCube and returns the title and link if found.

    Returns:
        None: If no matching APK is found.
        tuple[str, str]: A tuple containing the title and link of the matching APK if found.
    """
    pkg_name = self.pkg_name
    url = self.search_url + pkg_name
    params = {"headers": self.headers}
    if curl:
        params["impersonate"] = "chrome"

    response: requests.Response = self.session.get(url, **params)
    app_path = None
    if (
        response.status_code in (301, 302, 307, 308)
        and "Location" in response.headers
    ):
        app_path = response.headers["Location"]
    elif response.status_code == 200:
        soup = BeautifulSoup(response.text, "html.parser")
        meta = soup.find("meta", {"id": "__next-page-redirect"}) or soup.find(
            "meta", attrs={"http-equiv": lambda x: x and x.lower() == "refresh"}
        )
        if meta and "url=" in meta.get("content", ""):
            app_path = meta["content"].split("url=")[-1].strip()
        elif "NEXT_REDIRECT" in response.text:
            match = re.search(r"NEXT_REDIRECT;[^;]*;([^;]+);", response.text)
            if match:
                app_path = match.group(1)

        if not app_path:
            for a in soup.find_all("a", href=True):
                href = a["href"].split("?")[0].rstrip("/")
                if href.endswith("/" + pkg_name):
                    app_path = a["href"]
                    break
    else:
        return None

    if not app_path:
        return None

    apk_link = urllib.parse.urljoin(self.base_url, app_path)
    if apk_link.split("?")[0].rstrip("/").split("/")[-1] != pkg_name:
        return None

    app_response: requests.Response = self.session.get(apk_link, **params)
    if app_response.status_code != 200:
        return None

    app_soup = BeautifulSoup(app_response.text, "html.parser")
    h1 = app_soup.find("h1")
    if h1:
        apk_title = h1.text.strip()
    elif app_soup.title and app_soup.title.string:
        apk_title = app_soup.title.string.split(" APK")[0].strip()
    else:
        apk_title = pkg_name

    return apk_title, apk_link

APKFab #

This class provides methods to search for an APK on APKFab based on package name, and to find available versions and their download links for a given APK link.

Parameters:

Name Type Description Default
pkg_name str

The package name of the APK to search for.

required

Attributes:

Name Type Description
pkg_name str

The package name of the APK to search for.

base_url str

The base URL of the APKFab website.

search_url str

The URL used to search for APKs on APKFab.

headers dict

The headers used for making HTTP requests.

session Session

The session object used for making HTTP requests.

Methods:

Name Description
search_apk

Searches for the APK on APKFab and returns the title and link if found.

find_versions

str) -> list[tuple[str, str]]: Finds and returns a list of versions and their download links for the given APK link.

Source code in apksearch/sites/apkfab.py
class APKFab:
    """
    This class provides methods to search for an APK on APKFab based on package name,
    and to find available versions and their download links for a given APK link.

    Parameters:
        pkg_name (str): The package name of the APK to search for.

    Attributes:
        pkg_name (str): The package name of the APK to search for.
        base_url (str): The base URL of the APKFab website.
        search_url (str): The URL used to search for APKs on APKFab.
        headers (dict): The headers used for making HTTP requests.
        session (requests.Session): The session object used for making HTTP requests.

    Methods:
        search_apk() -> None | tuple[str, str]:
            Searches for the APK on APKFab and returns the title and link if found.

        find_versions(apk_link: str) -> list[tuple[str, str]]:
            Finds and returns a list of versions and their download links for the given APK link.
    """

    def __init__(self, pkg_name: str):
        self.pkg_name = pkg_name
        self.base_url = "https://apkfab.com"
        self.search_url = self.base_url + "/search?q="
        self.headers = {
            "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",
            "accept-language": "en-US,en;q=0.9,en-IN;q=0.8",
            "cache-control": "no-cache",
            "dnt": "1",
            "pragma": "no-cache",
            "priority": "u=0, i",
            "referer": "https://apkfab.com/search",
            "sec-ch-ua": '"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": '"Windows"',
            "sec-fetch-dest": "document",
            "sec-fetch-mode": "navigate",
            "sec-fetch-site": "same-origin",
            "sec-fetch-user": "?1",
            "upgrade-insecure-requests": "1",
            "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",
        }
        self.session = requests.Session()

    def search_apk(self) -> None | tuple[str, str]:
        """
        Searches for the APK on APKFab and returns the title and link if found.

        Returns:
            None: If no matching APK is found.
            tuple[str, str]: A tuple containing the title and link of the matching APK if found.
        """
        pkg_name = self.pkg_name
        url = self.search_url + pkg_name
        params = {"headers": self.headers}
        if curl:
            params["impersonate"] = "chrome"
        response: requests.Response = self.session.get(url, **params)
        soup = BeautifulSoup(response.text, "html.parser")
        search_result = soup.find("div", {"class": "search-white"})
        if search_result:
            container = search_result.find("div", {"class": "container"})
            if container:
                lists = container.find("div", {"class": "list-template lists"})
                if lists:
                    items = lists.find_all("div", {"class": "list"})
                    if items:
                        item = items[0]
                        apk_title = item.find("div", {"class": "title"}).text
                        apk_link = item.find("a")["href"]
                        package_name = apk_link.split("/")[-1]
                        if package_name == pkg_name:
                            return apk_title, apk_link
        return None

    def 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.

        Parameters:
            apk_link (str): The link to the APK on the APKFab website.

        Returns:
            list[tuple[str, str]]: A list of tuples, where each tuple contains the version number
            and its corresponding download link. If no versions are found, an empty list is returned.
        """
        versions_info = []
        if apk_link.startswith(self.base_url):
            url = apk_link + "/versions"
            response: requests.Response = self.session.get(url, headers=self.headers)
            soup = BeautifulSoup(response.text, "html.parser")
            versions_list = soup.find("div", {"class": "version_history"})

            if versions_list:
                versions = versions_list.find_all("div", {"class": "list"})
                if versions:
                    for version in versions:
                        package_info = version.find(
                            "div", {"class": "package_info open_info"}
                        )
                        if package_info:
                            title = package_info.find("div", {"class": "title"})
                            apk_version = title.find(
                                "span", {"class": "version"}
                            ).text.strip()
                            dl = version.find(
                                "div", {"class": "v_h_button button_down"}
                            )
                            if dl:
                                download_link = dl.find("a")["href"]
                                versions_info.append((apk_version, download_link))
                            else:
                                # Some versions have multiple variants
                                versions_info.append((apk_version, url))

        return versions_info

find_versions(apk_link) #

Finds and returns a list of versions and their download links for the given APK link.

Parameters:

Name Type Description Default
apk_link str

The link to the APK on the APKFab website.

required

Returns:

Type Description
list[tuple[str, str]]

list[tuple[str, str]]: A list of tuples, where each tuple contains the version number

list[tuple[str, str]]

and its corresponding download link. If no versions are found, an empty list is returned.

Source code in apksearch/sites/apkfab.py
def 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.

    Parameters:
        apk_link (str): The link to the APK on the APKFab website.

    Returns:
        list[tuple[str, str]]: A list of tuples, where each tuple contains the version number
        and its corresponding download link. If no versions are found, an empty list is returned.
    """
    versions_info = []
    if apk_link.startswith(self.base_url):
        url = apk_link + "/versions"
        response: requests.Response = self.session.get(url, headers=self.headers)
        soup = BeautifulSoup(response.text, "html.parser")
        versions_list = soup.find("div", {"class": "version_history"})

        if versions_list:
            versions = versions_list.find_all("div", {"class": "list"})
            if versions:
                for version in versions:
                    package_info = version.find(
                        "div", {"class": "package_info open_info"}
                    )
                    if package_info:
                        title = package_info.find("div", {"class": "title"})
                        apk_version = title.find(
                            "span", {"class": "version"}
                        ).text.strip()
                        dl = version.find(
                            "div", {"class": "v_h_button button_down"}
                        )
                        if dl:
                            download_link = dl.find("a")["href"]
                            versions_info.append((apk_version, download_link))
                        else:
                            # Some versions have multiple variants
                            versions_info.append((apk_version, url))

    return versions_info

search_apk() #

Searches for the APK on APKFab and returns the title and link if found.

Returns:

Name Type Description
None None | tuple[str, str]

If no matching APK is found.

None | tuple[str, str]

tuple[str, str]: A tuple containing the title and link of the matching APK if found.

Source code in apksearch/sites/apkfab.py
def search_apk(self) -> None | tuple[str, str]:
    """
    Searches for the APK on APKFab and returns the title and link if found.

    Returns:
        None: If no matching APK is found.
        tuple[str, str]: A tuple containing the title and link of the matching APK if found.
    """
    pkg_name = self.pkg_name
    url = self.search_url + pkg_name
    params = {"headers": self.headers}
    if curl:
        params["impersonate"] = "chrome"
    response: requests.Response = self.session.get(url, **params)
    soup = BeautifulSoup(response.text, "html.parser")
    search_result = soup.find("div", {"class": "search-white"})
    if search_result:
        container = search_result.find("div", {"class": "container"})
        if container:
            lists = container.find("div", {"class": "list-template lists"})
            if lists:
                items = lists.find_all("div", {"class": "list"})
                if items:
                    item = items[0]
                    apk_title = item.find("div", {"class": "title"}).text
                    apk_link = item.find("a")["href"]
                    package_name = apk_link.split("/")[-1]
                    if package_name == pkg_name:
                        return apk_title, apk_link
    return None

APKMirror #

This class provides methods to search for an APK on APKMirror based on package name, and to find available versions and their download links for a given APK link.

Parameters:

Name Type Description Default
pkg_name str

The package name of the APK to search for.

required

Attributes:

Name Type Description
pkg_name str

The package name of the APK to search for.

base_url str

The base URL of the APKMirror website.

api_url str

The base URL for the APKMirror API.

headers dict

The headers used for making HTTP requests.

session Session

The session object used for making HTTP requests.

Methods:

Name Description
search_apk

Searches for the APK on APKMirror and returns the title and link if found.

find_versions

str) -> list[tuple[str, str]]: Finds and returns a list of versions and their download links for the given APK link.

Source code in apksearch/sites/apkmirror.py
class APKMirror:
    """
    This class provides methods to search for an APK on APKMirror based on package name,
    and to find available versions and their download links for a given APK link.

    Parameters:
        pkg_name (str): The package name of the APK to search for.

    Attributes:
        pkg_name (str): The package name of the APK to search for.
        base_url (str): The base URL of the APKMirror website.
        api_url (str): The base URL for the APKMirror API.
        headers (dict): The headers used for making HTTP requests.
        session (requests.Session): The session object used for making HTTP requests.

    Methods:
        search_apk() -> None | tuple[str, str]:
            Searches for the APK on APKMirror and returns the title and link if found.

        find_versions(apk_link: str) -> list[tuple[str, str]]:
            Finds and returns a list of versions and their download links for the given APK link.
    """

    def __init__(self, pkg_name: str):
        self.pkg_name = pkg_name
        self.base_url = "https://www.apkmirror.com"
        self.api_url = self.base_url + "/wp-json/apkm/v1"
        # https://github.com/rumboalla/apkupdater/blob/3.x/app/src/main/kotlin/com/apkupdater/service/ApkMirrorService.kt
        self.headers = {
            "User-Agent": "APKUpdater-v3.0.3",
            "Authorization": "Basic YXBpLWFwa3VwZGF0ZXI6cm01cmNmcnVVakt5MDRzTXB5TVBKWFc4",
            "Content-Type": "application/json",
        }
        self.session = requests.Session()

    def search_apk(self) -> None | tuple[str, str]:
        """
        Searches for the APK on APKMirror and returns the title and link if found.

        Returns:
            None: If no matching APK is found.
            tuple[str, str]: A tuple containing the title and link of the matching APK if found.
        """
        pkg_name = self.pkg_name
        url = self.api_url + "/app_exists"
        json = {"pnames": pkg_name}
        response: requests.Response = self.session.post(
            url, json=json, headers=self.headers
        )
        result = response.json()["data"][0]
        if result and result["exists"]:
            pname = result["pname"]
            if pname == pkg_name:
                title = result["app"]["name"]
                apk_link = self.base_url + result["app"]["link"]
                return title, apk_link
        return None

    @staticmethod
    def _parse_version_tuple(v: str) -> tuple[int, ...]:
        nums = re.findall(r"\d+", v)
        return tuple(int(x) for x in nums) if nums else (0,)

    def _find_version_in_feed(self, apk_link: str, version: str) -> str | None:
        """
        Searches for a version across the app's RSS feed pages using APKUpdater authentication.
        """
        target_tuple = self._parse_version_tuple(version)
        feed_base = apk_link.rstrip("/") + "/feed/"

        response = self.session.get(feed_base, headers=self.headers)
        if response.status_code != 200:
            return None

        def extract_items(xml_text: str):
            res = []
            for item in re.findall(r"<item>(.*?)</item>", xml_text, re.DOTALL):
                t_match = re.search(r"<title>(.*?)</title>", item)
                l_match = re.search(r"<link>(.*?)</link>", item)
                if t_match and l_match:
                    item_title = t_match.group(1).strip()
                    item_link = l_match.group(1).strip()
                    v_match = re.search(r"\b(\d+\.\d+[\.\d]*)\b", item_title)
                    v_tuple = (
                        self._parse_version_tuple(v_match.group(1))
                        if v_match
                        else None
                    )
                    res.append(
                        (
                            item_title,
                            item_link,
                            v_match.group(1) if v_match else "",
                            v_tuple,
                        )
                    )
            return res

        items = extract_items(response.text)
        if not items:
            return None

        for item_title, item_link, v_str, v_tuple in items:
            if v_str == version or version in item_title:
                return item_link

        first_ver = items[0][3]
        if first_ver and target_tuple > first_ver:
            return None

        low = 2
        high = 35
        while low <= high:
            mid = (low + high) // 2
            r_mid = self.session.get(f"{feed_base}?paged={mid}", headers=self.headers)
            if r_mid.status_code == 404:
                high = mid - 1
                continue
            if r_mid.status_code != 200:
                break

            mid_items = extract_items(r_mid.text)
            if not mid_items:
                high = mid - 1
                continue

            for item_title, item_link, v_str, v_tuple in mid_items:
                if v_str == version or version in item_title:
                    return item_link

            mid_first = mid_items[0][3]
            mid_last = mid_items[-1][3]
            if not mid_first or not mid_last:
                break

            if target_tuple > mid_first:
                high = mid - 1
            elif target_tuple < mid_last:
                low = mid + 1
            else:
                return None

        return None

    def find_version(self, apk_link: str, version: str, title: str) -> str | None:
        """
        Finds and returns the download link for the given APK link and version.

        Parameters:
            apk_link (str): The link to the APK on the APKMirror website.
            version (str): The version number of the APK to find.
            title (str): The title of the APK.

        Returns:
            str: The download link for the specified version of the APK.
        """
        name = re.sub(r"[(),]", "", title).lower().replace(" ", "-")
        name = re.sub(r"-+", "-", name)
        version_slug = version.replace(".", "-")
        url = apk_link + name + "-" + version_slug + "-release"
        response = self.session.get(url, headers=self.headers)
        if response.status_code == 200:
            return url
        if response.status_code == 404:
            return None
        # On Cloudflare challenge (403), check the app's RSS feed
        feed_link = self._find_version_in_feed(apk_link, version)
        if feed_link:
            return feed_link
        return None

find_version(apk_link, version, title) #

Finds and returns the download link for the given APK link and version.

Parameters:

Name Type Description Default
apk_link str

The link to the APK on the APKMirror website.

required
version str

The version number of the APK to find.

required
title str

The title of the APK.

required

Returns:

Name Type Description
str str | None

The download link for the specified version of the APK.

Source code in apksearch/sites/apkmirror.py
def find_version(self, apk_link: str, version: str, title: str) -> str | None:
    """
    Finds and returns the download link for the given APK link and version.

    Parameters:
        apk_link (str): The link to the APK on the APKMirror website.
        version (str): The version number of the APK to find.
        title (str): The title of the APK.

    Returns:
        str: The download link for the specified version of the APK.
    """
    name = re.sub(r"[(),]", "", title).lower().replace(" ", "-")
    name = re.sub(r"-+", "-", name)
    version_slug = version.replace(".", "-")
    url = apk_link + name + "-" + version_slug + "-release"
    response = self.session.get(url, headers=self.headers)
    if response.status_code == 200:
        return url
    if response.status_code == 404:
        return None
    # On Cloudflare challenge (403), check the app's RSS feed
    feed_link = self._find_version_in_feed(apk_link, version)
    if feed_link:
        return feed_link
    return None

search_apk() #

Searches for the APK on APKMirror and returns the title and link if found.

Returns:

Name Type Description
None None | tuple[str, str]

If no matching APK is found.

None | tuple[str, str]

tuple[str, str]: A tuple containing the title and link of the matching APK if found.

Source code in apksearch/sites/apkmirror.py
def search_apk(self) -> None | tuple[str, str]:
    """
    Searches for the APK on APKMirror and returns the title and link if found.

    Returns:
        None: If no matching APK is found.
        tuple[str, str]: A tuple containing the title and link of the matching APK if found.
    """
    pkg_name = self.pkg_name
    url = self.api_url + "/app_exists"
    json = {"pnames": pkg_name}
    response: requests.Response = self.session.post(
        url, json=json, headers=self.headers
    )
    result = response.json()["data"][0]
    if result and result["exists"]:
        pname = result["pname"]
        if pname == pkg_name:
            title = result["app"]["name"]
            apk_link = self.base_url + result["app"]["link"]
            return title, apk_link
    return None

APKPure #

This class provides methods to search for an APK on APKPure based on package name, and to find available versions and their download links for a given APK link.

Parameters:

Name Type Description Default
pkg_name str

The package name of the APK to search for.

required

Attributes:

Name Type Description
pkg_name str

The package name of the APK to search for.

base_url str

The base URL of the APKPure website.

search_url str

The URL used to search for APKs on APKPure.

headers dict

The headers used for making HTTP requests.

session Session

The session object used for making HTTP requests.

Methods:

Name Description
search_apk

Searches for the APK on APKPure and returns the title and link if found.

find_versions

str) -> list[tuple[str, str]]: Finds and returns a list of versions and their download links for the given APK link.

Source code in apksearch/sites/apkpure.py
class APKPure:
    """
    This class provides methods to search for an APK on APKPure based on package name,
    and to find available versions and their download links for a given APK link.

    Parameters:
        pkg_name (str): The package name of the APK to search for.

    Attributes:
        pkg_name (str): The package name of the APK to search for.
        base_url (str): The base URL of the APKPure website.
        search_url (str): The URL used to search for APKs on APKPure.
        headers (dict): The headers used for making HTTP requests.
        session (requests.Session): The session object used for making HTTP requests.

    Methods:
        search_apk() -> None | tuple[str, str]:
            Searches for the APK on APKPure and returns the title and link if found.

        find_versions(apk_link: str) -> list[tuple[str, str]]:
            Finds and returns a list of versions and their download links for the given APK link.
    """

    def __init__(self, pkg_name: str):
        self.pkg_name = pkg_name
        self.base_url = "https://apkpure.net"
        self.cdn_url = "https://d.cdnpure.com/b/APK/"
        self.cdn_version = "?version="
        self.search_url = self.base_url + "/search?q="
        self.api_url = "https://tapi.pureapk.com/v3/get_app_his_version"
        self.api_headers = {
            "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",
            "User-Agent": "Dalvik/2.1.0 (Linux; U; Android 13; Pixel 5 Build/TQ3A.230901.001); APKPure/3.20.34 (Aegon)",
            "Ual-Access-Businessid": "projecta",
            "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"}}""",
            "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":""}}""",
            "Ual-Access-Sequence": "",
            "Ual-Access-Nonce": "21448252",
            "Ual-Access-Timestamp": "1738560597165",
            "Connection": "Keep-Alive",
            "Accept-Encoding": "gzip",
        }
        self.headers = {
            "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",
            "accept-language": "en-US,en;q=0.9,en-IN;q=0.8",
            "cache-control": "no-cache",
            "dnt": "1",
            "pragma": "no-cache",
            "priority": "u=0, i",
            "referer": "https://apkpure.net/",
            "sec-ch-ua": '"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": '"Windows"',
            "sec-fetch-dest": "document",
            "sec-fetch-mode": "navigate",
            "sec-fetch-site": "same-origin",
            "sec-fetch-user": "?1",
            "upgrade-insecure-requests": "1",
            "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",
        }
        if curl:
            self.session = requests.Session(impersonate="chrome")
        else:
            self.session = requests.Session()

    def _api_search(self) -> None | tuple[str, list[tuple[str, str]]]:
        """
        Attempts to fetch app information using API.

        Returns:
            None: If API request fails or no data found
            tuple[str, list[tuple[str, str]]]: App title and list of (version, download_url) tuples
        """
        try:
            params = {"package_name": self.pkg_name, "hl": "en"}
            response = self.session.get(
                self.api_url, headers=self.api_headers, params=params
            )
            data = response.json()

            if not data.get("version_list"):
                return None

            versions_info = []
            title = None

            for version in data["version_list"]:
                version_name = version["version_name"]
                if not title:
                    title = version["title"]
                if version.get("asset", {}).get("urls"):
                    download_url = version["asset"]["urls"][0]
                    versions_info.append((version_name, download_url))

            return (title, versions_info) if title and versions_info else None

        except Exception:
            return None

    def search_apk(self) -> None | tuple[str, str]:
        """
        Searches for the APK on APKPure and returns the title and link if found.

        Returns:
            None: If no matching APK is found.
            tuple[str, str]: A tuple containing the title and link of the matching APK if found.
        """
        pkg_name = self.pkg_name
        url = self.search_url + pkg_name
        try:
            response: requests.Response = self.session.get(url, headers=self.headers)
            soup = BeautifulSoup(response.text, "html.parser")
            search_results = soup.find("div", {"class": "apk-list"})
            if search_results:
                apk_items = search_results.find_all("a", {"class": "apk-item"})
                if apk_items:
                    for apk_item in apk_items:
                        apk_link = self.base_url + apk_item["href"]
                        apk_title = apk_item["title"]
                        apk_package_name = apk_item["data-dt-pkg"]
                        if apk_package_name == pkg_name:
                            return apk_title, apk_link
        except Exception:
            pass

        # If site search resulted 0 results, try cdn link
        # https://github.com/AbhiTheModder/apksearch/issues/2
        url = self.cdn_url + pkg_name + self.cdn_version + "latest"
        try:
            response: requests.Response = self.session.get(
                url, headers=self.headers, allow_redirects=False
            )
            try:
                location = response.headers.get("Location")
            except AttributeError:
                location = None
            if location:
                if location == "https://apkpure.com":
                    return None
                response: requests.Response = self.session.head(
                    location, allow_redirects=False
                )
                try:
                    content = response.headers.get("Content-Disposition")
                except AttributeError:
                    content = None
                if content:
                    apk_title = content.split("filename=")[1].strip('"').split("_")[0]
                    return apk_title, location
        except Exception:
            pass

        api_result = self._api_search()
        if api_result:
            title, versions = api_result
            if versions:
                return title, versions[0][1]

        return None

    def 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.

        Parameters:
            apk_link (str): The link to the APK on the APKPure website.

        Returns:
            list[tuple[str, str]]: A list of tuples, where each tuple contains the version number
            and its corresponding download link. If no versions are found, an empty list is returned.
        """
        api_result = self._api_search()
        if api_result:
            return api_result[1]

        versions_info = []
        if apk_link.startswith(self.base_url):
            url = apk_link + "/versions"
            response: requests.Response = self.session.get(url, headers=self.headers)
            soup = BeautifulSoup(response.text, "html.parser")
            versions_list = soup.find("ul", {"class": "version-list"})

            if versions_list:
                versions = versions_list.find_all(
                    "li", {"class": re.compile("^version dt-version-item.*")}
                )
                for ver in versions:
                    version_icon = ver.find("a", {"class": "dt-version-icon"})
                    version_info = ver.find("div", {"class": "version-info"})
                    if version_icon and version_info:
                        version_number = version_info.find(
                            "span", {"class": "name one-line"}
                        ).text
                        download_url = self.base_url + version_icon["href"]
                        versions_info.append((version_number, download_url))
        return versions_info

find_versions(apk_link) #

Finds and returns a list of versions and their download links for the given APK link.

Parameters:

Name Type Description Default
apk_link str

The link to the APK on the APKPure website.

required

Returns:

Type Description
list[tuple[str, str]]

list[tuple[str, str]]: A list of tuples, where each tuple contains the version number

list[tuple[str, str]]

and its corresponding download link. If no versions are found, an empty list is returned.

Source code in apksearch/sites/apkpure.py
def 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.

    Parameters:
        apk_link (str): The link to the APK on the APKPure website.

    Returns:
        list[tuple[str, str]]: A list of tuples, where each tuple contains the version number
        and its corresponding download link. If no versions are found, an empty list is returned.
    """
    api_result = self._api_search()
    if api_result:
        return api_result[1]

    versions_info = []
    if apk_link.startswith(self.base_url):
        url = apk_link + "/versions"
        response: requests.Response = self.session.get(url, headers=self.headers)
        soup = BeautifulSoup(response.text, "html.parser")
        versions_list = soup.find("ul", {"class": "version-list"})

        if versions_list:
            versions = versions_list.find_all(
                "li", {"class": re.compile("^version dt-version-item.*")}
            )
            for ver in versions:
                version_icon = ver.find("a", {"class": "dt-version-icon"})
                version_info = ver.find("div", {"class": "version-info"})
                if version_icon and version_info:
                    version_number = version_info.find(
                        "span", {"class": "name one-line"}
                    ).text
                    download_url = self.base_url + version_icon["href"]
                    versions_info.append((version_number, download_url))
    return versions_info

search_apk() #

Searches for the APK on APKPure and returns the title and link if found.

Returns:

Name Type Description
None None | tuple[str, str]

If no matching APK is found.

None | tuple[str, str]

tuple[str, str]: A tuple containing the title and link of the matching APK if found.

Source code in apksearch/sites/apkpure.py
def search_apk(self) -> None | tuple[str, str]:
    """
    Searches for the APK on APKPure and returns the title and link if found.

    Returns:
        None: If no matching APK is found.
        tuple[str, str]: A tuple containing the title and link of the matching APK if found.
    """
    pkg_name = self.pkg_name
    url = self.search_url + pkg_name
    try:
        response: requests.Response = self.session.get(url, headers=self.headers)
        soup = BeautifulSoup(response.text, "html.parser")
        search_results = soup.find("div", {"class": "apk-list"})
        if search_results:
            apk_items = search_results.find_all("a", {"class": "apk-item"})
            if apk_items:
                for apk_item in apk_items:
                    apk_link = self.base_url + apk_item["href"]
                    apk_title = apk_item["title"]
                    apk_package_name = apk_item["data-dt-pkg"]
                    if apk_package_name == pkg_name:
                        return apk_title, apk_link
    except Exception:
        pass

    # If site search resulted 0 results, try cdn link
    # https://github.com/AbhiTheModder/apksearch/issues/2
    url = self.cdn_url + pkg_name + self.cdn_version + "latest"
    try:
        response: requests.Response = self.session.get(
            url, headers=self.headers, allow_redirects=False
        )
        try:
            location = response.headers.get("Location")
        except AttributeError:
            location = None
        if location:
            if location == "https://apkpure.com":
                return None
            response: requests.Response = self.session.head(
                location, allow_redirects=False
            )
            try:
                content = response.headers.get("Content-Disposition")
            except AttributeError:
                content = None
            if content:
                apk_title = content.split("filename=")[1].strip('"').split("_")[0]
                return apk_title, location
    except Exception:
        pass

    api_result = self._api_search()
    if api_result:
        title, versions = api_result
        if versions:
            return title, versions[0][1]

    return None

APKad #

This class provides methods to search for an APK on APKAD based on package name, and to find available versions and their download links for a given APK link.

Parameters:

Name Type Description Default
pkg_name str

The package name of the APK to search for.

required

Attributes:

Name Type Description
pkg_name str

The package name of the APK to search for.

base_url str

The base URL of the APKAD website.

search_url str

The URL used to search for APKs on APKAD.

headers dict

The headers used for making HTTP requests.

session Session

The session object used for making HTTP requests.

Methods:

Name Description
search_apk

Searches for the APK on APKAD and returns the title and link if found.

Source code in apksearch/sites/apkad.py
class APKad:
    """
    This class provides methods to search for an APK on APKAD based on package name,
    and to find available versions and their download links for a given APK link.

    Parameters:
        pkg_name (str): The package name of the APK to search for.

    Attributes:
        pkg_name (str): The package name of the APK to search for.
        base_url (str): The base URL of the APKAD website.
        search_url (str): The URL used to search for APKs on APKAD.
        headers (dict): The headers used for making HTTP requests.
        session (requests.Session): The session object used for making HTTP requests.

    Methods:
        search_apk() -> None | tuple[str, str]:
            Searches for the APK on APKAD and returns the title and link if found.
    """

    def __init__(self, pkg_name: str):
        self.pkg_name = pkg_name
        self.base_url = "https://apkdownloader.pages.dev"
        self.api_url = "https://api.mi9.com"
        self.token_url = "https://token.mi9.com/"
        self.search_url = self.api_url + "/get"
        self.headers = {
            "accept": "text/event-stream",
            "accept-language": "en-US,en;q=0.9,en-IN;q=0.8",
            "cache-control": "no-cache",
            "dnt": "1",
            "origin": "https://apkdownloader.pages.dev",
            "pragma": "no-cache",
            "priority": "u=1, i",
            "referer": "https://apkdownloader.pages.dev/",
            "sec-ch-ua": '"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": '"Windows"',
            "sec-fetch-dest": "empty",
            "sec-fetch-mode": "cors",
            "sec-fetch-site": "same-site",
            "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",
        }
        self.session = requests.Session()

    def get_token(self) -> tuple[str, int] | None:
        """
        Retrieves a token from the token endpoint.

        Returns:
            tuple[str, int]: A tuple containing the token and timestamp if successful.
            None: If the token retrieval fails.
        """
        data = {
            "package": self.pkg_name,
            "device": "phone",
            "arch": "arm64-v8a",
            "vc": "",
            "device_id": "",
            "sdk": "default",
        }
        response = self.session.post(self.token_url, headers=self.headers, json=data)
        if response.status_code == 200:
            token_data = response.json()
            if token_data.get("success"):
                return token_data.get("token"), token_data.get("timestamp")
        return None

    def search_apk(self) -> None | tuple[str, list[tuple[str, str]]]:
        token_tuple = self.get_token()
        if not token_tuple:
            return None

        token, ts = token_tuple
        data_json = json.dumps(
            {
                "hl": "en",
                "package": self.pkg_name,
                "device": "phone",
                "arch": "arm64-v8a",
                "vc": "",
                "device_id": "",
                "sdk": "default",
                "timestamp": ts,
            },
            separators=(",", ":"),
        )

        data_b64 = base64.b64encode(data_json.encode("utf-8")).decode("utf-8")

        params = {"token": token, "data": data_b64}

        response = self.session.get(
            self.search_url, headers=self.headers, params=params, stream=True
        )

        stream_response = None
        for line in response.iter_lines():
            if not line:
                continue
            line_response = line.decode("utf-8")
            if line_response.startswith("data: "):
                payload = line_response[6:]
                try:
                    j = json.loads(payload)
                    if j.get("progress") == 100 and j.get("html"):
                        stream_response = j
                        break
                except json.JSONDecodeError:
                    continue

        if stream_response:
            html_body = stream_response["html"]
            soup = BeautifulSoup(html_body, "html.parser")
            if not soup:
                return None

            title = soup.find("li", {"class": "_title"})
            title = title.text.strip() if title else self.pkg_name

            apk_files_div = soup.find("div", {"id": "apkslist"})
            if not apk_files_div:
                return None

            apk_links: list[tuple[str, str]] = []
            for a in apk_files_div.find_all("a", href=True):
                link = a["href"].strip()
                filename = a.find("span", {"class": "der_name"})
                filename = filename.text.strip() if filename else link.split("/")[-1]
                apk_links.append((filename, link))

            return title, apk_links

        return None

get_token() #

Retrieves a token from the token endpoint.

Returns:

Name Type Description
tuple[str, int] | None

tuple[str, int]: A tuple containing the token and timestamp if successful.

None tuple[str, int] | None

If the token retrieval fails.

Source code in apksearch/sites/apkad.py
def get_token(self) -> tuple[str, int] | None:
    """
    Retrieves a token from the token endpoint.

    Returns:
        tuple[str, int]: A tuple containing the token and timestamp if successful.
        None: If the token retrieval fails.
    """
    data = {
        "package": self.pkg_name,
        "device": "phone",
        "arch": "arm64-v8a",
        "vc": "",
        "device_id": "",
        "sdk": "default",
    }
    response = self.session.post(self.token_url, headers=self.headers, json=data)
    if response.status_code == 200:
        token_data = response.json()
        if token_data.get("success"):
            return token_data.get("token"), token_data.get("timestamp")
    return None

AppTeka #

This class provides methods to search for an APK on AppTeka based on package name, and to find available versions and their download links for a given APK link.

Parameters:

Name Type Description Default
pkg_name str

The package name of the APK to search for.

required

Attributes:

Name Type Description
pkg_name str

The package name of the APK to search for.

base_url str

The base URL of the AppTeka website.

search_url str

The URL used to search for APKs on AppTeka.

headers dict

The headers used for making HTTP requests.

session Session

The session object used for making HTTP requests.

Methods:

Name Description
search_apk

Searches for an APK on AppTeka based on the package name and version. Returns a tuple containing the APK name and download link if found, otherwise None.

Source code in apksearch/sites/appteka.py
class AppTeka:
    """
    This class provides methods to search for an APK on AppTeka based on package name,
    and to find available versions and their download links for a given APK link.

    Parameters:
        pkg_name (str): The package name of the APK to search for.

    Attributes:
        pkg_name (str): The package name of the APK to search for.
        base_url (str): The base URL of the AppTeka website.
        search_url (str): The URL used to search for APKs on AppTeka.
        headers (dict): The headers used for making HTTP requests.
        session (requests.Session): The session object used for making HTTP requests.

    Methods:
        search_apk(version) -> None | tuple[str, str]:
            Searches for an APK on AppTeka based on the package name and version.
            Returns a tuple containing the APK name and download link if found, otherwise None.
    """

    def __init__(self, pkg_name: str):
        self.pkg_name = pkg_name
        self.base_url = "https://appteka.store"
        self.search_url = self.base_url + "/search?q="
        self.headers = {
            "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",
            "accept-language": "en-US,en;q=0.9,en-IN;q=0.8",
            "cache-control": "no-cache",
            "dnt": "1",
            "connection": "keep-alive",
            "pragma": "no-cache",
            "referer": "https://appteka.store/",
            "sec-ch-ua": '"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": '"Windows"',
            "sec-fetch-dest": "document",
            "sec-fetch-mode": "navigate",
            "sec-fetch-site": "same-origin",
            "sec-fetch-user": "?1",
            "upgrade-insecure-requests": "1",
            "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",
        }
        self.session = requests.Session()

    def search_apk(self, version: str | None = None) -> None | tuple[str, str | None]:
        """
        Searches for the APK on AppTeka and returns the title and link if found.

        Parameters:
           version (str, optional): The version of the APK to search for.

        Returns:
            None: If no matching APK is found.
            tuple[str, str]: A tuple containing the title and link of the matching APK if found.
        """
        pkg_name = self.pkg_name
        url = self.search_url + pkg_name
        response: requests.Response = self.session.get(url, headers=self.headers)
        soup = BeautifulSoup(response.text, "html.parser")

        seen_links = set()
        for a in soup.find_all("a", href=True):
            href = a["href"].split("?")[0]
            if href.startswith("/apps/") and href not in seen_links:
                seen_links.add(href)
                apk_link = urllib.parse.urljoin(self.base_url, href)
                new_response: requests.Response = self.session.get(
                    apk_link, headers=self.headers
                )
                new_soup = BeautifulSoup(new_response.text, "html.parser")

                package_name = None
                for dt in new_soup.find_all("dt"):
                    if dt.text.strip().lower() == "package":
                        dd = dt.find_next_sibling("dd")
                        if dd:
                            package_name = dd.text.strip()
                            break

                if package_name == pkg_name:
                    h1 = new_soup.find("h1")
                    apk_title = h1.text.strip() if h1 else pkg_name

                    if version:
                        # Check current version on page
                        for dt in new_soup.find_all("dt"):
                            if dt.text.strip().lower() == "version":
                                dd = dt.find_next_sibling("dd")
                                if dd and dd.text.strip().split()[0] == version:
                                    return apk_title, apk_link

                        # Check HTML version links in other versions section
                        for va in new_soup.find_all("a", href=True):
                            if va["href"].startswith("/apps/") and "v" in va.text:
                                ver_text = va.text.strip().lstrip("v").strip()
                                if ver_text == version:
                                    return (
                                        apk_title,
                                        urllib.parse.urljoin(
                                            self.base_url, va["href"].split("?")[0]
                                        ),
                                    )

                        # Check versions embedded in page JSON script
                        matches = re.findall(
                            r'app_id\\*":\\*"([^\\"]+)\\*",\\*"ver_name\\*":\\*"([^\\"]+)\\*"',
                            new_response.text,
                        )
                        for app_id, ver_name in matches:
                            if ver_name == version:
                                return apk_title, f"{self.base_url}/apps/{app_id}"

                        return apk_title, None
                    else:
                        return apk_title, apk_link

        return None

search_apk(version=None) #

Searches for the APK on AppTeka and returns the title and link if found.

Parameters:

Name Type Description Default
version str

The version of the APK to search for.

None

Returns:

Name Type Description
None None | tuple[str, str | None]

If no matching APK is found.

None | tuple[str, str | None]

tuple[str, str]: A tuple containing the title and link of the matching APK if found.

Source code in apksearch/sites/appteka.py
def search_apk(self, version: str | None = None) -> None | tuple[str, str | None]:
    """
    Searches for the APK on AppTeka and returns the title and link if found.

    Parameters:
       version (str, optional): The version of the APK to search for.

    Returns:
        None: If no matching APK is found.
        tuple[str, str]: A tuple containing the title and link of the matching APK if found.
    """
    pkg_name = self.pkg_name
    url = self.search_url + pkg_name
    response: requests.Response = self.session.get(url, headers=self.headers)
    soup = BeautifulSoup(response.text, "html.parser")

    seen_links = set()
    for a in soup.find_all("a", href=True):
        href = a["href"].split("?")[0]
        if href.startswith("/apps/") and href not in seen_links:
            seen_links.add(href)
            apk_link = urllib.parse.urljoin(self.base_url, href)
            new_response: requests.Response = self.session.get(
                apk_link, headers=self.headers
            )
            new_soup = BeautifulSoup(new_response.text, "html.parser")

            package_name = None
            for dt in new_soup.find_all("dt"):
                if dt.text.strip().lower() == "package":
                    dd = dt.find_next_sibling("dd")
                    if dd:
                        package_name = dd.text.strip()
                        break

            if package_name == pkg_name:
                h1 = new_soup.find("h1")
                apk_title = h1.text.strip() if h1 else pkg_name

                if version:
                    # Check current version on page
                    for dt in new_soup.find_all("dt"):
                        if dt.text.strip().lower() == "version":
                            dd = dt.find_next_sibling("dd")
                            if dd and dd.text.strip().split()[0] == version:
                                return apk_title, apk_link

                    # Check HTML version links in other versions section
                    for va in new_soup.find_all("a", href=True):
                        if va["href"].startswith("/apps/") and "v" in va.text:
                            ver_text = va.text.strip().lstrip("v").strip()
                            if ver_text == version:
                                return (
                                    apk_title,
                                    urllib.parse.urljoin(
                                        self.base_url, va["href"].split("?")[0]
                                    ),
                                )

                    # Check versions embedded in page JSON script
                    matches = re.findall(
                        r'app_id\\*":\\*"([^\\"]+)\\*",\\*"ver_name\\*":\\*"([^\\"]+)\\*"',
                        new_response.text,
                    )
                    for app_id, ver_name in matches:
                        if ver_name == version:
                            return apk_title, f"{self.base_url}/apps/{app_id}"

                    return apk_title, None
                else:
                    return apk_title, apk_link

    return None

Aptoide #

This class provides methods to search for an APK on Aptoide based on package name, and to find available versions and their download links for a given APK link.

Parameters:

Name Type Description Default
pkg_name str

The package name of the APK to search for.

required

Attributes:

Name Type Description
pkg_name str

The package name of the APK to search for.

api_url str

The base URL for the Aptoide API.

search_url str

The URL used to search for APKs on Aptoide.

headers dict

The headers used for making HTTP requests.

session Session

The session object used for making HTTP requests.

Methods:

Name Description
search_apk

Searches for the APK on Aptoide and returns the title and link if found.

find_versions

str) -> list[str | None]: Finds and returns a list of versions for the given APK link.

Source code in apksearch/sites/aptoide.py
class Aptoide:
    """
    This class provides methods to search for an APK on Aptoide based on package name,
    and to find available versions and their download links for a given APK link.

    Parameters:
        pkg_name (str): The package name of the APK to search for.

    Attributes:
        pkg_name (str): The package name of the APK to search for.
        api_url (str): The base URL for the Aptoide API.
        search_url (str): The URL used to search for APKs on Aptoide.
        headers (dict): The headers used for making HTTP requests.
        session (requests.Session): The session object used for making HTTP requests.

    Methods:
        search_apk() -> None | tuple[str, str]:
            Searches for the APK on Aptoide and returns the title and link if found.

        find_versions(apk_link: str) -> list[str | None]:
            Finds and returns a list of versions for the given APK link.
    """

    def __init__(self, pkg_name: str):
        self.pkg_name = pkg_name
        self.api_url = "https://ws75.aptoide.com/api/7"
        self.search_url = f"{self.api_url}/apps/search"
        self.headers = {
            "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",
            "accept-language": "en-US,en;q=0.9,en-IN;q=0.8",
            "cache-control": "no-cache",
            "dnt": "1",
            "pragma": "no-cache",
            "priority": "u=0, i",
            "referer": "https://en.aptoide.com/",
            "sec-ch-ua": '"Not A(Brand";v="8", "Chromium";v="132", "Microsoft Edge";v="132"',
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": '"Windows"',
            "sec-fetch-dest": "document",
            "sec-fetch-mode": "navigate",
            "sec-fetch-site": "same-origin",
            "sec-fetch-user": "?1",
            "upgrade-insecure-requests": "1",
            "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",
        }
        self.params = {
            "cdn": "web",
            "q": "bXlDUFU9YXJtNjQtdjhhLGFybWVhYmktdjdhLGFybWVhYmkmbGVhbmJhY2s9MA",
            "aab": "1",
            "mature": "false",
            "language": "en_US",
            "country": "US",
            "not_apk_tags": "",
            "query": self.pkg_name,
            "limit": "1",
            "offset": "0",
            "origin": "SITE",
            "store_name": "aptoide-web",
        }
        if curl:
            self.session = requests.Session(impersonate="chrome")
        else:
            self.session = requests.Session()

    def search_apk(self) -> None | tuple[str, str]:
        """
        Searches for the APK on Aptoide and returns the title and link if found.

        Returns:
            None: If no matching APK is found.
            tuple[str, str]: A tuple containing the title and link of the matching APK if found.
        """
        pkg_name = self.pkg_name
        url = self.search_url
        response: requests.Response = self.session.get(
            url, headers=self.headers, params=self.params
        )
        data = response.json()
        if data and data["info"]["status"] == "OK":
            lis = data["datalist"]["list"]
            if lis:
                package = data["datalist"]["list"][0]["package"]
                apk_title = data["datalist"]["list"][0]["name"]
                if package == pkg_name:
                    app_id: int = data["datalist"]["list"][0]["id"]
                    meta_url = self.api_url + f"/app/getMeta?app_id={app_id}"
                    meta_response: requests.Response = self.session.get(
                        meta_url, headers=self.headers
                    )
                    meta_data = meta_response.json()
                    if meta_data and meta_data["info"]["status"] == "OK":
                        url = meta_data["data"]["urls"]["w"].split("?")[0]
                        return apk_title, url
        return None

    def find_versions(self, apk_link: str) -> list[str | None]:
        """
        Finds and returns a list of versions for the given APK link.

        Parameters:
            apk_link (str): The link to the APK on the Aptoide website.

        Returns:
           list[str | None]: A list of version strings for the given APK link.
        """
        versions_info = []

        url = apk_link.rstrip("/") + "/versions"
        response: requests.Response = self.session.get(url, headers=self.headers)
        soup = BeautifulSoup(response.text, "html.parser")
        version_spans = soup.find_all("span", string=re.compile(r"^\d+\.\d+\.\d+$"))
        for span in version_spans:
            version = span.text.strip()
            if version not in versions_info:
                versions_info.append(version)

        if not versions_info:
            import json

            match = re.search(
                r'<script id="__NEXT_DATA__" type="application/json">(.*?)</script>',
                response.text,
            )
            if match:
                try:
                    data = json.loads(match.group(1))
                    versions_list = (
                        data.get("props", {})
                        .get("pageProps", {})
                        .get("versions", [])
                    )
                    for v in versions_list:
                        ver_name = v.get("vername")
                        if ver_name and ver_name not in versions_info:
                            versions_info.append(ver_name)
                except Exception:
                    pass

        return versions_info

find_versions(apk_link) #

Finds and returns a list of versions for the given APK link.

Parameters:

Name Type Description Default
apk_link str

The link to the APK on the Aptoide website.

required

Returns:

Type Description
list[str | None]

list[str | None]: A list of version strings for the given APK link.

Source code in apksearch/sites/aptoide.py
def find_versions(self, apk_link: str) -> list[str | None]:
    """
    Finds and returns a list of versions for the given APK link.

    Parameters:
        apk_link (str): The link to the APK on the Aptoide website.

    Returns:
       list[str | None]: A list of version strings for the given APK link.
    """
    versions_info = []

    url = apk_link.rstrip("/") + "/versions"
    response: requests.Response = self.session.get(url, headers=self.headers)
    soup = BeautifulSoup(response.text, "html.parser")
    version_spans = soup.find_all("span", string=re.compile(r"^\d+\.\d+\.\d+$"))
    for span in version_spans:
        version = span.text.strip()
        if version not in versions_info:
            versions_info.append(version)

    if not versions_info:
        import json

        match = re.search(
            r'<script id="__NEXT_DATA__" type="application/json">(.*?)</script>',
            response.text,
        )
        if match:
            try:
                data = json.loads(match.group(1))
                versions_list = (
                    data.get("props", {})
                    .get("pageProps", {})
                    .get("versions", [])
                )
                for v in versions_list:
                    ver_name = v.get("vername")
                    if ver_name and ver_name not in versions_info:
                        versions_info.append(ver_name)
            except Exception:
                pass

    return versions_info

search_apk() #

Searches for the APK on Aptoide and returns the title and link if found.

Returns:

Name Type Description
None None | tuple[str, str]

If no matching APK is found.

None | tuple[str, str]

tuple[str, str]: A tuple containing the title and link of the matching APK if found.

Source code in apksearch/sites/aptoide.py
def search_apk(self) -> None | tuple[str, str]:
    """
    Searches for the APK on Aptoide and returns the title and link if found.

    Returns:
        None: If no matching APK is found.
        tuple[str, str]: A tuple containing the title and link of the matching APK if found.
    """
    pkg_name = self.pkg_name
    url = self.search_url
    response: requests.Response = self.session.get(
        url, headers=self.headers, params=self.params
    )
    data = response.json()
    if data and data["info"]["status"] == "OK":
        lis = data["datalist"]["list"]
        if lis:
            package = data["datalist"]["list"][0]["package"]
            apk_title = data["datalist"]["list"][0]["name"]
            if package == pkg_name:
                app_id: int = data["datalist"]["list"][0]["id"]
                meta_url = self.api_url + f"/app/getMeta?app_id={app_id}"
                meta_response: requests.Response = self.session.get(
                    meta_url, headers=self.headers
                )
                meta_data = meta_response.json()
                if meta_data and meta_data["info"]["status"] == "OK":
                    url = meta_data["data"]["urls"]["w"].split("?")[0]
                    return apk_title, url
    return None