Пример #1
0
    def from_string(cls, string):
        """Parses the coords in Degree Minutes format. Expecting:

        S 36 51.918 E 174 46.725 or
        N 6 52.861  W174   43.327

        Spaces do not matter. Neither does having the degree symbol.

        Returns a geopy.Point instance."""

        # Make it uppercase for consistency
        coords = string.upper().replace("N", " ").replace("S", " ") \
            .replace("E", " ").replace("W", " ").replace("+", " ")

        try:
            m = re.match(r"\s*(-?\s*\d+)\D+(\d+[\.,]\d+)\D?\s*(-?\s*\d+)\D+(\d+[\.,]\d+)", coords)

            latDeg, latMin, lonDeg, lonMin = [float(part.replace(" ", "").replace(",", ".")) for part in m.groups()]

            if "S" in string:
                latDeg *= -1
            if "W" in string:
                lonDeg *= -1

            return Point(Util.to_decimal(latDeg, latMin), Util.to_decimal(lonDeg, lonMin))

        except AttributeError:
            pass

        # fallback
        try:
            return super(Point, cls).from_string(string)
        except ValueError as e:
            # wrap possible error to pycaching.errors.ValueError
            raise errors.ValueError() from e
Пример #2
0
    def _search_parse_cache(self, root):
        """Returns a Cache object parsed from BeautifulSoup Tag."""

        assert isinstance(root, bs4.Tag)

        # parse raw data
        favorites = root.find("span", "favorite-rank")
        typeLink, nameLink = root.find_all("a", "lnk")
        pm_only = root.find("img",
                            title="Premium Member Only Cache") is not None
        direction, info, D_T, placed, last_found = root.find_all(
            "span", "small")
        found = root.find("img", title="Found It!") is not None
        size = root.find("td", "AlignCenter").find("img")
        author, wp, area = [t.strip() for t in info.text.split("|")]

        # create cache object
        c = Cache(wp, self)

        # prettify data
        c.cache_type = typeLink.find("img").get("alt")
        c.name = nameLink.span.text.strip()
        c.found = found
        c.state = "Strike" not in nameLink.get("class")
        c.size = " ".join(size.get("alt").split()[1:])
        c.difficulty, c.terrain = list(map(float, D_T.text.split("/")))
        c.hidden = Util.parse_date(placed.text)
        c.author = author[3:]  # delete "by "
        c.favorites = int(favorites.text)
        c.pm_only = pm_only

        logging.debug("Cache parsed: %s", c)
        return c
Пример #3
0
    def _search_parse_cache(self, root):
        """Returns a Cache object parsed from BeautifulSoup Tag."""

        assert isinstance(root, bs4.Tag)

        # parse raw data
        favorites = root.find("span", "favorite-rank")
        typeLink, nameLink = root.find_all("a", "lnk")
        pm_only = root.find("img", title="Premium Member Only Cache") is not None
        direction, info, D_T, placed, last_found = root.find_all("span", "small")
        found = root.find("img", title="Found It!") is not None
        size = root.find("td", "AlignCenter").find("img")
        author, wp, area = [t.strip() for t in info.text.split("|")]

        # create cache object
        c = Cache(wp, self)

        # prettify data
        c.cache_type = typeLink.find("img").get("alt")
        c.name = nameLink.span.text.strip()
        c.found = found
        c.state = "Strike" not in nameLink.get("class")
        c.size = " ".join(size.get("alt").split()[1:])
        c.difficulty, c.terrain = list(map(float, D_T.text.split("/")))
        c.hidden = Util.parse_date(placed.text)
        c.author = author[3:]  # delete "by "
        c.favorites = int(favorites.text)
        c.pm_only = pm_only

        logging.debug("Cache parsed: %s", c)
        return c
Пример #4
0
 def hidden(self, hidden):
     if type(hidden) is str:
         hidden = Util.parse_date(hidden)
     elif type(hidden) is not datetime.date:
         raise ValueError(
             "Passed object is not datetime.date instance nor string containing a date."
         )
     self._hidden = hidden
Пример #5
0
    def from_string(cls, string):
        """Parses the coords in Degree Minutes format. Expecting:

        S 36 51.918 E 174 46.725 or
        N 6 52.861  W174   43.327

        Spaces do not matter. Neither does having the degree symbol.

        Returns a geopy.Point instance."""

        # Make it uppercase for consistency
        coords = string.upper().replace("N", " ").replace("S", " ") \
            .replace("E", " ").replace("W", " ").replace("+", " ")

        try:
            m = re.match(
                r"\s*(-?\s*\d+)\D+(\d+[\.,]\d+)\D?\s*(-?\s*\d+)\D+(\d+[\.,]\d+)",
                coords)

            latDeg, latMin, lonDeg, lonMin = [
                float(part.replace(" ", "").replace(",", "."))
                for part in m.groups()
            ]

            if "S" in string:
                latDeg *= -1
            if "W" in string:
                lonDeg *= -1

            return Point(Util.to_decimal(latDeg, latMin),
                         Util.to_decimal(lonDeg, lonMin))

        except AttributeError:
            pass

        # fallback
        try:
            return super(Point, cls).from_string(string)
        except ValueError as e:
            # wrap possible error to pycaching.errors.ValueError
            raise errors.ValueError() from e
Пример #6
0
    def search(self, point, limit=0):
        """Returns a generator object of caches around some point."""

        assert isinstance(point, Point)
        assert type(limit) is int

        logging.info("Searching at %s...", point)

        start_index = 0
        while True:
            # get one page
            page = self._search_get_page(point, start_index)

            if not page:
                # result is empty - no more caches
                raise StopIteration()

            # parse caches in result
            for start_index, row in enumerate(BeautifulSoup(page).find_all("tr"), start_index):

                if limit > 0 and start_index == limit:
                    raise StopIteration()

                # parse raw data
                cache_details = row.find("span", "cache-details").text.split("|")
                wp = cache_details[1].strip()

                # create and fill cache object
                c = Cache(wp, self)
                c.cache_type = cache_details[0].strip()
                c.name = row.find("span", "cache-name").text
                c.found = row.find("img", title="Found It!") is not None
                c.favorites = int(row.find(attrs={"data-column": "FavoritePoint"}).text)
                c.state = not (row.get("class") and "disabled" in row.get("class"))
                c.pm_only = row.find("td", "pm-upsell") is not None

                if c.pm_only:
                    # PM only caches doesn't have other attributes filled in
                    yield c
                    continue

                c.size = row.find(attrs={"data-column": "ContainerSize"}).text
                c.difficulty = float(row.find(attrs={"data-column": "Difficulty"}).text)
                c.terrain = float(row.find(attrs={"data-column": "Terrain"}).text)
                c.hidden = Util.parse_date(row.find(attrs={"data-column": "PlaceDate"}).text)
                c.author = row.find("span", "owner").text[3:]  # delete "by "

                logging.debug("Cache parsed: %s", c)
                yield c

            start_index += 1
Пример #7
0
    def load_cache_quick(self, wp, destination=None):
        """Loads details from map server.

        Loads just basic cache details, but very quickly."""

        assert type(wp) is str and wp.startswith("GC")
        logging.info("Loading quick details about %s...", wp)

        # assemble request
        params = urlencode({"i": wp})
        url = self._urls["map"] + "?" + params

        try:
            res = self._browser.get(url).json()
        except requests.exceptions.ConnectionError as e:
            raise Error("Cannot load quick cache details page.") from e

        if res["status"] == "failed" or len(res["data"]) != 1:
            raise LoadError("Waypoint '{}' cannot be loaded: {}".format(
                wp, res["msg"]))

        data = res["data"][0]

        # create cache object
        c = destination or Cache(wp, self)
        assert isinstance(c, Cache)

        # prettify data
        c.name = data["name"]
        c.cache_type = data["type"]["text"]
        c.state = data["available"]
        c.size = data["container"]["text"]
        c.difficulty = data["difficulty"]["text"]
        c.terrain = data["terrain"]["text"]
        c.hidden = Util.parse_date(data["hidden"])
        c.author = data["owner"]["text"]
        c.favorites = int(data["fp"])
        c.pm_only = data["subrOnly"]

        logging.debug("Cache loaded: %r", c)
        return c
Пример #8
0
    def load_cache_quick(self, wp, destination=None):
        """Loads details from map server.

        Loads just basic cache details, but very quickly."""

        assert type(wp) is str and wp.startswith("GC")
        logging.info("Loading quick details about %s...", wp)

        # assemble request
        params = urlencode({"i": wp})
        url = self._urls["map"] + "?" + params

        try:
            res = self._browser.get(url).json()
        except requests.exceptions.ConnectionError as e:
            raise Error("Cannot load quick cache details page.") from e

        if res["status"] == "failed" or len(res["data"]) != 1:
            raise LoadError("Waypoint '{}' cannot be loaded: {}".format(wp, res["msg"]))

        data = res["data"][0]

        # create cache object
        c = destination or Cache(wp, self)
        assert isinstance(c, Cache)

        # prettify data
        c.name = data["name"]
        c.cache_type = data["type"]["text"]
        c.state = data["available"]
        c.size = data["container"]["text"]
        c.difficulty = data["difficulty"]["text"]
        c.terrain = data["terrain"]["text"]
        c.hidden = Util.parse_date(data["hidden"])
        c.author = data["owner"]["text"]
        c.favorites = int(data["fp"])
        c.pm_only = data["subrOnly"]

        logging.debug("Cache loaded: %r", c)
        return c
Пример #9
0
    def load_cache(self, wp, destination=None):
        """Loads details from cache page.

        Loads all cache details and return fully populated cache object."""

        assert type(wp) is str and wp.startswith("GC")
        logging.info("Loading details about %s...", wp)

        # assemble request
        params = urlencode({"wp": wp})
        url = self._urls["cache_details"] + "?" + params

        try:
            root = self._browser.get(url).soup
        except requests.exceptions.ConnectionError as e:
            raise Error("Cannot load cache details page.") from e

        cache_details = root.find(id="cacheDetails")

        # check for PM only caches if using free account
        if cache_details is None:
            if root.select(".PMOWarning") is not None:
                raise PMOnlyException("Premium Members only.")

        # parse raw data
        name = cache_details.find("h2")
        cache_type = cache_details.find("img").get("alt")
        author = cache_details("a")[1]
        hidden = cache_details.find("div",
                                    "minorCacheDetails").find_all("div")[1]
        location = root.find(id="uxLatLon")
        state = root.find("ul", "OldWarning")
        found = root.find("div", "FoundStatus")
        D_T = root.find("div", "CacheStarLabels").find_all("img")
        size = root.find("div", "CacheSize").find("img")
        attributes_raw = root.find_all(
            "div", "CacheDetailNavigationWidget")[0].find_all("img")
        user_content = root.find_all("div", "UserSuppliedContent")
        hint = root.find(id="div_hint")
        favorites = root.find("span", "favorite-value")

        # create cache object
        c = destination or Cache(wp, self)
        assert isinstance(c, Cache)

        # prettify data
        c.name = name.text
        c.cache_type = cache_type
        c.author = author.text
        c.hidden = Util.parse_date(hidden.text.split()[2])
        c.location = Point.from_string(location.text)
        c.state = state is None
        c.found = found and "Found It!" in found.text or False
        c.difficulty, c.terrain = [float(_.get("alt").split()[0]) for _ in D_T]
        c.size = " ".join(size.get("alt").split()[1:])
        attributes_raw = [
            _.get("src").split('/')[-1].rsplit("-", 1) for _ in attributes_raw
        ]
        c.attributes = {
            attribute_name: appendix.startswith("yes")
            for attribute_name, appendix in attributes_raw
            if not appendix.startswith("blank")
        }
        c.summary = user_content[0].text
        c.description = str(user_content[1])
        c.hint = Util.rot13(hint.text.strip())
        c.favorites = int(favorites.text)

        logging.debug("Cache loaded: %r", c)
        return c
Пример #10
0
 def hidden(self, hidden):
     if type(hidden) is str:
         hidden = Util.parse_date(hidden)
     elif type(hidden) is not datetime.date:
         raise ValueError("Passed object is not datetime.date instance nor string containing a date.")
     self._hidden = hidden
Пример #11
0
    def load_cache(self, wp, destination=None):
        """Loads details from cache page.

        Loads all cache details and return fully populated cache object."""

        assert type(wp) is str and wp.startswith("GC")
        logging.info("Loading details about %s...", wp)

        # assemble request
        params = urlencode({"wp": wp})
        url = self._urls["cache_details"] + "?" + params

        try:
            root = self._browser.get(url).soup
        except requests.exceptions.ConnectionError as e:
            raise Error("Cannot load cache details page.") from e

        cache_details = root.find(id="cacheDetails")

        # check for PM only caches if using free account
        if cache_details is None:
            if root.select(".PMOWarning") is not None:
                raise PMOnlyException("Premium Members only.")

        # parse raw data
        name = cache_details.find("h2")
        cache_type = cache_details.find("img").get("alt")
        author = cache_details("a")[1]
        hidden = cache_details.find("div", "minorCacheDetails").find_all("div")[1]
        location = root.find(id="uxLatLon")
        state = root.find("ul", "OldWarning")
        found = root.find("div", "FoundStatus")
        D_T = root.find("div", "CacheStarLabels").find_all("img")
        size = root.find("div", "CacheSize").find("img")
        attributes_raw = root.find_all("div", "CacheDetailNavigationWidget")[0].find_all("img")
        user_content = root.find_all("div", "UserSuppliedContent")
        hint = root.find(id="div_hint")
        favorites = root.find("span", "favorite-value")

        # create cache object
        c = destination or Cache(wp, self)
        assert isinstance(c, Cache)

        # prettify data
        c.name = name.text
        c.cache_type = cache_type
        c.author = author.text
        c.hidden = Util.parse_date(hidden.text.split()[2])
        c.location = Point.from_string(location.text)
        c.state = state is None
        c.found = found and "Found It!" in found.text or False
        c.difficulty, c.terrain = [float(_.get("alt").split()[0]) for _ in D_T]
        c.size = " ".join(size.get("alt").split()[1:])
        attributes_raw = [_.get("src").split('/')[-1].rsplit("-", 1) for _ in attributes_raw]
        c.attributes = {attribute_name: appendix.startswith("yes")
                        for attribute_name, appendix in attributes_raw if not appendix.startswith("blank")}
        c.summary = user_content[0].text
        c.description = str(user_content[1])
        c.hint = Util.rot13(hint.text.strip())
        c.favorites = int(favorites.text)

        logging.debug("Cache loaded: %r", c)
        return c
Пример #12
0
    def load_cache_by_url(self, url, destination=None):
        try:
            root = self._browser.get(url).soup
        except requests.exceptions.ConnectionError as e:
            raise Error("Cannot load cache details page.") from e

        cache_details = root.find(id="cacheDetails")

        # check for PM only caches if using free account
        if cache_details is None:
            if root.select(".PMOWarning") is not None:
                raise PMOnlyException("Premium Members only.")

        # parse raw data
        wp = root.title.string.split(' ')[0]

        name = cache_details.find("h2")
        cache_type = cache_details.find("img").get("src")
        author = cache_details("a")[1]
        hidden = cache_details.find("div",
                                    "minorCacheDetails").find_all("div")[1]
        location = root.find(id="uxLatLon")
        state = root.find("ul", "OldWarning")
        found = root.find("div", "FoundStatus")
        D_T = root.find("div", "CacheStarLabels").find_all("img")
        size = root.find("div", "CacheSize").find("img")
        attributes_raw = root.find_all(
            "div", "CacheDetailNavigationWidget")[0].find_all("img")
        user_content = root.find_all("div", "UserSuppliedContent")
        hint = root.find(id="div_hint")
        favorites = root.find("span", "favorite-value")

        # check for trackables
        inventory_raw = root.find_all("div", "CacheDetailNavigationWidget")
        inventory_links = inventory_raw[1].find_all("a")
        if len(inventory_links) >= 3:
            trackable_page = self._urls['trackable_base'] + inventory_links[
                -3].get("href")
        else:
            trackable_page = None

        # create cache object
        c = destination or Cache(wp, self)
        assert isinstance(c, Cache)

        # prettify data
        c.name = name.text
        c.cache_type = Cache.get_cache_type_by_img(cache_type)
        c.author = author.text
        c.hidden = Util.parse_date(hidden.text.split(":")[-1])
        c.location = Point.from_string(location.text)
        c.state = state is None
        c.found = found and "Found It!" in found.text or False
        c.difficulty, c.terrain = [float(_.get("alt").split()[0]) for _ in D_T]
        c.size = size.get("src").split("/")[-1].rsplit(
            ".", 1)[0]  # filename of img[src]
        attributes_raw = [
            _.get("src").split('/')[-1].rsplit("-", 1) for _ in attributes_raw
        ]
        c.attributes = {
            attribute_name: appendix.startswith("yes")
            for attribute_name, appendix in attributes_raw
            if not appendix.startswith("blank")
        }
        c.summary = user_content[0].text
        c.description = str(user_content[1])
        c.hint = Util.rot13(hint.text.strip())
        if favorites is None:
            c.favorites = 0
        else:
            c.favorites = int(favorites.text)
        if trackable_page is not None:
            c.trackables = self.load_trackable_list(trackable_page)
        else:
            c.trackables = []
        logging.debug("Cache loaded: %r", c)
        return c
Пример #13
0
    def search(self, point, limit=0):
        """Returns a generator object of caches around some point."""

        assert isinstance(point, Point)
        assert type(limit) is int

        logging.info("Searching at %s...", point)

        start_index = 0
        while True:
            # get one page
            page = self._search_get_page(point, start_index)

            if not page:
                # result is empty - no more caches
                raise StopIteration()

            # parse caches in result
            for start_index, row in enumerate(
                    BeautifulSoup(page).find_all("tr"), start_index):

                if limit > 0 and start_index == limit:
                    raise StopIteration()

                # parse raw data
                cache_details = row.find("span",
                                         "cache-details").text.split("|")
                wp = cache_details[1].strip()

                # create and fill cache object
                c = Cache(wp, self)
                c.cache_type = cache_details[0].strip()
                c.name = row.find("span", "cache-name").text
                c.found = row.find("img", title="Found It!") is not None
                c.favorites = int(
                    row.find(attrs={
                        "data-column": "FavoritePoint"
                    }).text)
                c.state = not (row.get("class")
                               and "disabled" in row.get("class"))
                c.pm_only = row.find("td", "pm-upsell") is not None

                if c.pm_only:
                    # PM only caches doesn't have other attributes filled in
                    yield c
                    continue

                c.size = row.find(attrs={"data-column": "ContainerSize"}).text
                c.difficulty = float(
                    row.find(attrs={
                        "data-column": "Difficulty"
                    }).text)
                c.terrain = float(
                    row.find(attrs={
                        "data-column": "Terrain"
                    }).text)
                c.hidden = Util.parse_date(
                    row.find(attrs={
                        "data-column": "PlaceDate"
                    }).text)
                c.author = row.find("span", "owner").text[3:]  # delete "by "

                logging.debug("Cache parsed: %s", c)
                yield c

            start_index += 1
Пример #14
0
    def load_cache_by_url(self, url, destination=None):
        try:
            root = self._browser.get(url).soup
        except requests.exceptions.ConnectionError as e:
            raise Error("Cannot load cache details page.") from e

        cache_details = root.find(id="cacheDetails")

        # check for PM only caches if using free account
        if cache_details is None:
            if root.select(".PMOWarning") is not None:
                raise PMOnlyException("Premium Members only.")

        # parse raw data
        wp = root.title.string.split(' ')[0]

        name = cache_details.find("h2")
        cache_type = cache_details.find("img").get("src")
        author = cache_details("a")[1]
        hidden = cache_details.find("div", "minorCacheDetails").find_all("div")[1]
        location = root.find(id="uxLatLon")
        state = root.find("ul", "OldWarning")
        found = root.find("div", "FoundStatus")
        D_T = root.find("div", "CacheStarLabels").find_all("img")
        size = root.find("div", "CacheSize").find("img")
        attributes_raw = root.find_all("div", "CacheDetailNavigationWidget")[0].find_all("img")
        user_content = root.find_all("div", "UserSuppliedContent")
        hint = root.find(id="div_hint")
        favorites = root.find("span", "favorite-value")

        # check for trackables
        inventory_raw = root.find_all("div", "CacheDetailNavigationWidget")
        inventory_links = inventory_raw[1].find_all("a")
        if len(inventory_links) >= 3:
            trackable_page = self._urls['trackable_base'] + inventory_links[-3].get("href")
        else:
            trackable_page = None

        # create cache object
        c = destination or Cache(wp, self)
        assert isinstance(c, Cache)

        # prettify data
        c.name = name.text
        c.cache_type = Cache.get_cache_type_by_img(cache_type)
        c.author = author.text
        c.hidden = Util.parse_date(hidden.text.split(":")[-1])
        c.location = Point.from_string(location.text)
        c.state = state is None
        c.found = found and "Found It!" in found.text or False
        c.difficulty, c.terrain = [float(_.get("alt").split()[0]) for _ in D_T]
        c.size = size.get("src").split("/")[-1].rsplit(".", 1)[0]  # filename of img[src]
        attributes_raw = [_.get("src").split('/')[-1].rsplit("-", 1) for _ in attributes_raw]
        c.attributes = {attribute_name: appendix.startswith("yes")
                        for attribute_name, appendix in attributes_raw if not appendix.startswith("blank")}
        c.summary = user_content[0].text
        c.description = str(user_content[1])
        c.hint = Util.rot13(hint.text.strip())
        if favorites is None:
            c.favorites = 0
        else:
            c.favorites = int(favorites.text)
        if trackable_page is not None:
            c.trackables = self.load_trackable_list(trackable_page)
        else:
            c.trackables = []
        logging.debug("Cache loaded: %r", c)
        return c