Skip to content

wright-way-scraper

wright_way_scraper.WrightWayScraper #

WrightWayScraper()

A client for the Petango API, specifically for the Wright-Way Rescue shelter.

Initialize the WrightWayScraper client with the base URL and authentication key.

Source code in wright_way_scraper/client.py
def __init__(self) -> None:
    """Initialize the WrightWayScraper client with the base URL and authentication key."""  # noqa: E501, W505
    self.base_url = "https://ws.petango.com"
    self.auth_key = "io53xfw8b0k2ocet3yb83666507n2168taf513lkxrqe681kf8"

get_animal #

get_animal(id_: int | str) -> Animal

Parse the HTML for a single animal and return an Animal Pydantic model.

Parameters:

Name Type Description Default
id_ int | str

The unique Petango identifier for the animal.

required

Raises:

Type Description
TypeError

If any of the required fields are missing from the HTML.

Returns:

Name Type Description
Animal Animal

A Pydantic model representing an animal available for adoption.

Source code in wright_way_scraper/client.py
def get_animal(self, id_: int | str) -> Animal:
    """Parse the HTML for a single animal and return an Animal Pydantic model.

    Args:
        id_ (int | str): The unique Petango identifier for the animal.

    Raises:
        TypeError: If any of the required fields are missing from the HTML.

    Returns:
        Animal: A Pydantic model representing an animal available for adoption.
    """
    tree = self._get_animal_xml(id_)
    labels = {
        "Name": "AnimalName",
        "Species": "Species",
        "Breed": "PrimaryBreed",
        "Birthdate": "DateOfBirth",
        "Gender": "Sex",
        "Size": "Size",
        "Color": "PrimaryColor",
        "Declawed": "Declawed",
        "Housetrained": "Housetrained",
        "Location": "Location",
        "Intake_Date": "LastIntakeDate",
        "Stage": "Stage",
        "Profile_URL": "Photo1",
    }
    mapping = {"id": id_, "URL": self.get_animal_html_url(id_)}
    for k, v in labels.items():
        elem = tree.find(v)
        if elem is None:
            msg = f"Could not find {v} for animal {id_}"
            raise TypeError(msg)
        mapping[k] = elem.text
    try:
        return Animal(**mapping)
    except ValidationError as e:
        msg = f"Could not validate Animal model for animal {id_}"
        raise ValueError(msg) from e

get_animal_html_url #

get_animal_html_url(id_: int | str, auth_key: str | None = None) -> str

Get the URL for the Petango HTML page for a single animal.

This page is embedded in a frame on the Wright-Way Rescue website. The URL is constructed using the Petango ID of the animal.

Parameters:

Name Type Description Default
id_ int | str

The Petango ID of the animal.

required
auth_key str | None

The authentication key for the Petango API. If None, the client's default key is used. Defaults to None.

None

Returns:

Name Type Description
str str

The URL for the Petango HTML page for the animal.

Source code in wright_way_scraper/client.py
def get_animal_html_url(self, id_: int | str, auth_key: str | None = None) -> str:
    """Get the URL for the Petango HTML page for a single animal.

    This page is embedded in a frame on the Wright-Way Rescue website. The URL is
    constructed using the Petango ID of the animal.

    Args:
        id_ (int | str): The Petango ID of the animal.
        auth_key (str | None, optional): The authentication key for the Petango API.
            If None, the client's default key is used. Defaults to None.

    Returns:
        str: The URL for the Petango HTML page for the animal.
    """
    if auth_key is None:
        auth_key = self.auth_key

    _url = "/webservices/adoptablesearch/wsAdoptableAnimalDetails.aspx?css=http://ws.petango.com/WebServices/adoptablesearch/css/styles.css"
    return f"{self.base_url}{_url}&id={id_}&authkey={auth_key}"

get_animal_ids #

get_animal_ids() -> list[int]

Parse the HTML table of all animals and return a list of their Petango ids.

Returns:

Type Description
list[int]

list[int]: A list of Petango ids for all animals available for adoption.

Source code in wright_way_scraper/client.py
def get_animal_ids(self) -> list[int]:
    """Parse the HTML table of all animals and return a list of their Petango ids.

    Returns:
        list[int]: A list of Petango ids for all animals available for adoption.
    """
    tree = self._get_animals_xml()
    ids = []
    for elem in tree:
        if elem.tag != "{http://www.petango.com/}XmlNode":
            msg = f"Expected '{{http://www.petango.com/}}XmlNode', got '{elem.tag}'"
            raise TypeError(msg)
        if (search_elem := elem.find("adoptableSearch")) is None:
            if elem.keys() == ["{http://www.w3.org/2001/XMLSchema-instance}nil"]:
                continue
            msg = "Could not find 'adoptableSearch' in the XmlNode"
            raise ValueError(msg)

        if (id_elem := search_elem.find("ID")) is None:
            msg = "Could not find 'ID' in the adoptableSearch XmlNode"
            raise ValueError(msg)

        if id_elem.text is None:
            msg = "Could not find text in the ID XmlNode"
            raise ValueError(msg)

        try:
            id_ = int(id_elem.text)
            ids.append(id_)
        except ValueError as e:
            msg = f"Could not cast '{id_elem.text}' to an integer"
            raise ValueError(msg) from e

    return ids

get_animal_xml_url #

get_animal_xml_url(id_: int | str, auth_key: str | None = None) -> str

Get the URL for the Petango API to get the details of a single animal.

This URL is used to get the XML data for a single animal from the Petango API. It is not the URL for the HTML page for the animal.

Parameters:

Name Type Description Default
id_ int | str

The Petango ID of the animal.

required
auth_key str | None

The authentication key for the Petango API. If None, the client's default key is used. Defaults to None.

None

Returns:

Name Type Description
str str

The URL for the Petango API to get the details of a single animal.

Source code in wright_way_scraper/client.py
def get_animal_xml_url(
    self,
    id_: int | str,
    auth_key: str | None = None,
) -> str:
    """Get the URL for the Petango API to get the details of a single animal.

    This URL is used to get the XML data for a single animal from the Petango API.
    It is not the URL for the HTML page for the animal.

    Args:
        id_ (int | str): The Petango ID of the animal.
        auth_key (str | None, optional): The authentication key for the Petango API.
            If None, the client's default key is used. Defaults to None.

    Returns:
        str: The URL for the Petango API to get the details of a single animal.
    """
    if auth_key is None:
        auth_key = self.auth_key

    # HTTP GET request to the Petango API
    # https://ws.petango.com/webservices/wsAdoption.asmx?op=AdoptableDetails
    _url = "/webservices/wsAdoption.asmx/AdoptableDetails"
    return f"{self.base_url}{_url}?animalID={id_}&authkey={auth_key}"

get_animals #

get_animals(ids: list[int] | None = None) -> list[Animal]

Get all animals available for adoption.

Parameters:

Name Type Description Default
ids list[int] | None

A list of Petango ids for animals available for adoption. If None, the list will be generated by calling self.get_animal_ids().

None

Returns:

Type Description
list[Animal]

list[Animal]: A list of Pydantic models representing animals available for adoption.

Source code in wright_way_scraper/client.py
def get_animals(self, ids: list[int] | None = None) -> list[Animal]:
    """Get all animals available for adoption.

    Args:
        ids (list[int] | None): A list of Petango ids for animals available for
            adoption. If None, the list will be generated by calling
            self.get_animal_ids().

    Returns:
        list[Animal]: A list of Pydantic models representing animals available for
            adoption.
    """
    if ids is None:
        ids = self.get_animal_ids()

    return [self.get_animal(id_) for id_ in ids]

get_animals_xml_url #

get_animals_xml_url(auth_key: str | None = None) -> str

Get the URL for the Petango API to get all animals available for adoption.

This URL is used to get the XML data for all animals available for adoption from the Petango API. It is not the URL for the HTML page for the animals, as seen on the Wright-Way Rescue website.

Parameters:

Name Type Description Default
auth_key str | None

The authentication key for the Petango API. If None, the client's default key is used. Defaults to None.

None

Returns:

Name Type Description
str str

The URL for the Petango API to get all animals available for adoption.

Source code in wright_way_scraper/client.py
def get_animals_xml_url(self, auth_key: str | None = None) -> str:
    """Get the URL for the Petango API to get all animals available for adoption.

    This URL is used to get the XML data for all animals available for adoption from
    the Petango API. It is not the URL for the HTML page for the animals, as seen on
    the Wright-Way Rescue website.

    Args:
        auth_key (str | None, optional): The authentication key for the Petango API.
            If None, the client's default key is used. Defaults to None.

    Returns:
        str: The URL for the Petango API to get all animals available for adoption.
    """
    if auth_key is None:
        auth_key = self.auth_key

    # HTTP GET request to the Petango API
    # https://ws.petango.com/webservices/wsAdoption.asmx?op=AdoptableSearch
    _url = "/webservices/wsAdoption.asmx/AdoptableSearch"
    _keys = [
        "speciesID",
        "sex",
        "ageGroup",
        "location",
        "site",
        "onHold",
        "orderBy",
        "primaryBreed",
        "secondaryBreed",
        "specialNeeds",
        "noDogs",
        "noCats",
        "noKids",
        "stageID",
    ]
    url = f"{self.base_url}{_url}?authkey={auth_key}"
    for key in _keys:
        url += f"&{key}="
    return url

wright_way_scraper.Animal #

Bases: BaseModel

A model representing an animal available for adoption from the Wright-Way Rescue.

Attributes:

Name Type Description
id int

The unique Petango identifier for the animal.

Name str

The name of the animal.

Species Literal['Cat', 'Dog']

The species of the animal.

Breed str

The breed of the animal.

Birthdate datetime | str | None

The birthdate of the animal.

Gender Literal['Male', 'Female', 'Unknown']

The gender of the animal.

Size str

The size of the animal.

Color str

The color of the animal.

Declawed Literal['Yes', 'No', 'Unknown']

Whether the animal is declawed.

Housetrained Literal['Yes', 'No', 'Unknown']

Whether the animal is house-trained.

Location str

The location of the animal.

Intake_Date datetime | str

The date the animal was taken in by the shelter.

Stage Literal['Reserved', 'Available']

The stage of the animal.

Raises:

Type Description
TypeError

If the Intake_Date is not a datetime object or a string in the format 'mm/dd/yyyy'.

TypeError

If the Birthdate is not a datetime object or a string in the Petango API format.