Dragon-Ball-API-Alejo 0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,53 @@
1
+ class ScrapCharacter:
2
+ # these names have to be exactly the same as the asyde region
3
+
4
+ sections = {
5
+ "names": "Nombres",
6
+ "data": "Datos",
7
+ "debut": "Debut"
8
+ }
9
+
10
+ # font for character names section
11
+
12
+ names = {
13
+ "japan_name": "nombre-ja",
14
+ "latin_name": "nombre-ja_latino",
15
+ "pronunciation_name": "pronunciación",
16
+ "other_names": "otros nombres"
17
+ }
18
+
19
+ # font for character data section
20
+
21
+ data = {
22
+ "gender": "sexo",
23
+ "birthday": "fecha de nacimiento",
24
+ "deaths": "fecha de muerte",
25
+ "age": "edad",
26
+ "species": "raza",
27
+ "occupation": "ocupación",
28
+ "origin": "procedencia",
29
+ "residence": "residencia",
30
+ "transformations": "transformaciones",
31
+ "fusion": "fusiones",
32
+ "family": "familia",
33
+ "affiliates": "afiliados"
34
+ }
35
+
36
+ # font for character debut section
37
+
38
+ debut = {
39
+ "sagas": "saga",
40
+ "debut": "Primera aparición",
41
+ "manga": "manga",
42
+ "volume": "tomo",
43
+ "anime": "anime",
44
+ "introduction": "arco"
45
+ }
46
+
47
+ # list of names to use according to sections
48
+
49
+ list_character = {
50
+ "names": list(names.values()),
51
+ "data": list(data.values()),
52
+ "debut": list(debut.values())
53
+ }
@@ -0,0 +1,36 @@
1
+ class ScrapFusion:
2
+ # these names have to be exactly the same as the asyde region
3
+
4
+ sections = {
5
+ "names": "Nombres",
6
+ "data": "Otros datos",
7
+ }
8
+
9
+ # font for character names section
10
+
11
+ names = {
12
+ "japan_name": "nombre-ja",
13
+ "latin_name": "nombre-ja_latino",
14
+ "pronunciation_name": "pronunciación",
15
+ "other_names": "otros nombres"
16
+ }
17
+
18
+ # font for character data section
19
+
20
+ data = {
21
+ "gender": "sexo",
22
+ "date of origin": "fecha de origen",
23
+ "species": "raza",
24
+ "fusion": "fusionados",
25
+ "method_used": "método",
26
+ "transformations": "transformaciones",
27
+ "apparition": "aparición",
28
+ "debut": "Primera aparición"
29
+ }
30
+
31
+ # list of names to use according to sections
32
+
33
+ list_character = {
34
+ "names": list(names.values()),
35
+ "data": list(data.values()),
36
+ }
@@ -0,0 +1,35 @@
1
+ class ScrapGames:
2
+ # these names have to be exactly the same as the asyde region
3
+
4
+ sections = {
5
+ "names": "Nombres",
6
+ "data": "Datos",
7
+ }
8
+
9
+ # font for character names section
10
+
11
+ names = {
12
+ "japan_name": "nombre-ja",
13
+ "latin_name": "nombre-ja_latino",
14
+ }
15
+
16
+ # font for character data section
17
+
18
+ data = {
19
+ "engine_game": "Motor",
20
+ "platforms": "Plataforma",
21
+ "developers": "Desarrolladores",
22
+ "dealers": "Distribuidores",
23
+ "launch": "Lanzamiento",
24
+ "game_mode": "Modos de Juego",
25
+ "gender": "Género",
26
+ "classification": "Clasificaciones",
27
+ "sagas": "Sagas"
28
+ }
29
+
30
+ # list of names to use according to sections
31
+
32
+ list_character = {
33
+ "names": list(names.values()),
34
+ "data": list(data.values())
35
+ }
@@ -0,0 +1,32 @@
1
+ class ScrapPlanet:
2
+ # these names have to be exactly the same as the asyde region
3
+
4
+ sections = {
5
+ "names": "Nombres",
6
+ "data": "Datos",
7
+ }
8
+
9
+ # font for character names section
10
+
11
+ names = {
12
+ "japan_name": "nombre-ja",
13
+ "latin_name": "nombre-ja_latino",
14
+ }
15
+
16
+ # font for character data section
17
+
18
+ data = {
19
+ "localization": "localización",
20
+ "gobernant": "gobernante",
21
+ "residents": "residentes",
22
+ "especies": "especie",
23
+ "sagas": "saga",
24
+ "debut": "aparición",
25
+ }
26
+
27
+ # list of names to use according to sections
28
+
29
+ list_character = {
30
+ "names": list(names.values()),
31
+ "data": list(data.values())
32
+ }
@@ -0,0 +1,36 @@
1
+ class ScrapSagas:
2
+ # these names have to be exactly the same as the asyde region
3
+
4
+ sections = {
5
+ "names": "Títulos",
6
+ "data": "Datos",
7
+ "serialization": "Serialización"
8
+ }
9
+
10
+ # font for character names section
11
+
12
+ names = {
13
+ "japan_name": "nombre-ja",
14
+ "latin_name": "nombre-ja_latino",
15
+ }
16
+
17
+ # font for character data section
18
+
19
+ data = {
20
+ "episodes": "número de episodios (Anime)",
21
+ }
22
+
23
+ # font for serialization data section
24
+
25
+ serialization = {
26
+ "first_emision": "primera emisión",
27
+ "last_emision": "última emisión",
28
+ }
29
+
30
+ # list of names to use according to sections
31
+
32
+ list_character = {
33
+ "names": list(names.values()),
34
+ "data": list(data.values()),
35
+ "serialization": list(serialization.values())
36
+ }
@@ -0,0 +1,15 @@
1
+ class URL:
2
+ URL_BASE = "https://dragonball.fandom.com/"
3
+ URL_WIKI = "https://dragonball.fandom.com/es/wiki/"
4
+
5
+ HEADERS = {
6
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
7
+ "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
8
+ "Accept-Language": "es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3"
9
+ }
10
+
11
+ URL_LIST_CHARACTERS = URL_WIKI + "Lista_de_personajes"
12
+ URL_LIST_FUSIONS = URL_WIKI + "Lista_de_fusiones"
13
+ URL_LIST_PLANETS = URL_WIKI + "Lista_de_planetas"
14
+ URL_LIST_CHRONO = URL_WIKI + "Cronología"
15
+ URL_LIST_GAMES = URL_WIKI + "Lista_de_videojuegos"
@@ -0,0 +1,130 @@
1
+ import requests as requests
2
+ from bs4 import BeautifulSoup
3
+
4
+ from DragonBall.Constants.ScrapCharacter import ScrapCharacter
5
+ from DragonBall.Constants.URLS import URL
6
+ from DragonBall.Data.OutInformation import OutInformation
7
+ from DragonBall.Soup.section import Section
8
+ from DragonBall.Soup.summary import Summary
9
+ from DragonBall.Soup.tags import Tags
10
+
11
+
12
+ class Characters:
13
+ def __init__(self, name: str, all_data=False):
14
+ self.name = name
15
+ self.all_data = all_data
16
+
17
+ @classmethod
18
+ def character_list(cls, character_list: list):
19
+ return [Characters(i).character_information() for i in character_list]
20
+
21
+ @staticmethod
22
+ def list():
23
+ request = requests.get(URL.URL_LIST_CHARACTERS, headers=URL.HEADERS)
24
+ soup = BeautifulSoup(request.content.decode('utf-8'), "html.parser")
25
+ toc = soup.find("div", {"id": "toc"})
26
+ if not toc:
27
+ return {}
28
+ summary_data = toc.text.strip().splitlines()
29
+ return Summary.clean_list_summary(summary_data, [1, -1])
30
+
31
+ def character_information(self):
32
+ url = URL.URL_WIKI + self.name.replace(" ", "_")
33
+ request = requests.get(url, headers=URL.HEADERS)
34
+ soup = BeautifulSoup(request.content.decode('utf-8'), "html.parser")
35
+ list_section = Section.obtain_section_data(soup, 'aside')
36
+ basic_dict = self.__obtain_basic_data(soup, url)
37
+ section_dict = self.__evaluate_scrapper_section(list_section, list(list_section.keys()), ScrapCharacter)
38
+ return self.__show_information(basic_dict, section_dict)
39
+
40
+ def __obtain_basic_data(self, soup: BeautifulSoup, url: str):
41
+ name = self.__get_official_name(soup, "h1", "id", "firstHeading")
42
+ image = self.__get_image(soup, "a", "class", "image image-thumbnail")
43
+ description = self.__get_description_character(soup)
44
+ return {"url": url, "name": name, "image": image, "descripcion": description}
45
+
46
+ @staticmethod
47
+ def __get_official_name(soup: BeautifulSoup, tag: str, identification: str, element: str):
48
+ # Intento 1: Buscar el h1 con el id exacto
49
+ official_name = Tags.custom_catch_error(soup, tag, identification, element)
50
+ if official_name != OutInformation.RESOURCE_NOT_FOUND:
51
+ return official_name.get_text(strip=True)
52
+
53
+ # Intento 2: Buscar CUALQUIER etiqueta <h1> en la página
54
+ h1 = soup.find("h1")
55
+ if h1:
56
+ return h1.get_text(strip=True)
57
+
58
+ # Intento 3: Usar el título de la pestaña del navegador
59
+ if soup.title:
60
+ return soup.title.text.split("|")[0].strip()
61
+
62
+ return OutInformation.RESOURCE_NOT_FOUND
63
+
64
+ @staticmethod
65
+ def __get_image(soup: BeautifulSoup, tag: str, identification: str, name: str):
66
+ found = soup.find(tag, attrs={identification: name})
67
+ if found:
68
+ return found.get("href")
69
+ return OutInformation.RESOURCE_NOT_FOUND
70
+
71
+ @staticmethod
72
+ def __get_description_character(soup: BeautifulSoup):
73
+ [remove_sup.extract() for remove_sup in soup.find_all('sup')]
74
+ try:
75
+ return next(
76
+ p.text.strip() for header in soup.find_all(['h2', 'h3']) if (p := header.find_next_sibling('p')))
77
+ except StopIteration:
78
+ return OutInformation.RESOURCE_NOT_FOUND
79
+
80
+ def __evaluate_scrapper_section(self, list_dict, list_search, tag_found: ScrapCharacter):
81
+ empty = self.__return_empty_section(list_dict)
82
+ if empty:
83
+ return empty
84
+
85
+ section_names = list(tag_found.sections.values())
86
+ names = list_dict.get(section_names[0], OutInformation.RESOURCE_NOT_FOUND)
87
+ data = list_dict.get(section_names[1], OutInformation.RESOURCE_NOT_FOUND)
88
+ debut = list_dict.get(section_names[2], OutInformation.RESOURCE_NOT_FOUND)
89
+
90
+ return {
91
+ "nombres": self.__names_section(names, tag_found.names) if section_names[0] in list_search else names,
92
+ "data": self.__data_section(data, tag_found.data) if section_names[1] in list_search else data,
93
+ "debut": self.__debut_section(debut, tag_found.debut) if section_names[2] in list_search else debut,
94
+ }
95
+
96
+ @staticmethod
97
+ def __return_empty_section(list_dict: dict):
98
+ if not list_dict:
99
+ return {
100
+ "nombres": OutInformation.RESOURCE_NOT_FOUND,
101
+ "data": OutInformation.RESOURCE_NOT_FOUND,
102
+ "debut": OutInformation.RESOURCE_NOT_FOUND,
103
+ }
104
+ return None
105
+
106
+ @staticmethod
107
+ def __names_section(name, lista_tags):
108
+ return {key: Tags.clean_text(Tags.catch_error(name, value)) for key, value in lista_tags.items()}
109
+
110
+ @staticmethod
111
+ def __data_section(data, lista_tags):
112
+ return {key: Tags.clean_text(Tags.catch_error(data, value)) for key, value in lista_tags.items()}
113
+
114
+ @staticmethod
115
+ def __debut_section(debut, lista_tags):
116
+ return {key: Tags.clean_text(Tags.catch_error(debut, value)) for key, value in lista_tags.items()}
117
+
118
+ def __show_information(self, dictionary_basic, dictionary_sections):
119
+ dictionary = {
120
+ "name": dictionary_basic['name'],
121
+ "image": dictionary_basic['image'],
122
+ "description": dictionary_basic['descripcion'],
123
+ "names": dictionary_sections['nombres'],
124
+ "data": dictionary_sections['data'],
125
+ "debut": dictionary_sections['debut'],
126
+ "url_scrap": dictionary_basic['url']
127
+ }
128
+ if self.all_data:
129
+ return dictionary
130
+ return OutInformation.clean_not_found_scrape(dictionary)
@@ -0,0 +1,122 @@
1
+ import requests as requests
2
+ from bs4 import BeautifulSoup
3
+
4
+ from DragonBall.Constants.ScrapFusion import ScrapFusion
5
+ from DragonBall.Constants.URLS import URL
6
+ from DragonBall.Data.OutInformation import OutInformation
7
+ from DragonBall.Soup.section import Section
8
+ from DragonBall.Soup.summary import Summary
9
+ from DragonBall.Soup.tags import Tags
10
+
11
+
12
+ class Fusions:
13
+ def __init__(self, name: str, all_data=False):
14
+ self.name = name
15
+ self.all_data = all_data
16
+
17
+ @classmethod
18
+ def fusion_list(cls, fusion_list: list):
19
+ return [Fusions(i).fusion_information() for i in fusion_list]
20
+
21
+ @staticmethod
22
+ def list():
23
+ request = requests.get(URL.URL_LIST_FUSIONS, headers=URL.HEADERS)
24
+ soup = BeautifulSoup(request.content.decode('utf-8'), "html.parser")
25
+ toc = soup.find("div", {"id": "toc"})
26
+ if not toc:
27
+ return {}
28
+ summary_data = toc.text.strip().splitlines()
29
+ return Summary.clean_list_summary(summary_data, [1, -3])
30
+
31
+ def fusion_information(self):
32
+ url = URL.URL_WIKI + self.name.replace(" ", "_")
33
+ request = requests.get(url, headers=URL.HEADERS)
34
+ soup = BeautifulSoup(request.content.decode('utf-8'), "html.parser")
35
+ list_section = Section.obtain_section_data(soup, 'aside')
36
+ basic_dict = self.__obtain_basic_data(soup, url)
37
+ section_dict = self.__evaluate_scrapper_section(list_section, list(list_section.keys()), ScrapFusion)
38
+ return self.__show_information(basic_dict, section_dict)
39
+
40
+ def __obtain_basic_data(self, soup: BeautifulSoup, url: str):
41
+ name = self.__get_official_name(soup, "h1", "id", "firstHeading")
42
+ image = self.__get_image(soup, "a", "class", "image image-thumbnail")
43
+ description = self.__get_description_fusion(soup)
44
+ return {"url": url, "name": name, "image": image, "descripcion": description}
45
+
46
+ @staticmethod
47
+ def __get_official_name(soup: BeautifulSoup, tag: str, identification: str, element: str):
48
+ # Intento 1: Buscar el h1 con el id exacto
49
+ official_name = Tags.custom_catch_error(soup, tag, identification, element)
50
+ if official_name != OutInformation.RESOURCE_NOT_FOUND:
51
+ return official_name.get_text(strip=True)
52
+
53
+ # Intento 2: Buscar CUALQUIER etiqueta <h1> en la página
54
+ h1 = soup.find("h1")
55
+ if h1:
56
+ return h1.get_text(strip=True)
57
+
58
+ # Intento 3: Usar el título de la pestaña del navegador
59
+ if soup.title:
60
+ return soup.title.text.split("|")[0].strip()
61
+
62
+ return OutInformation.RESOURCE_NOT_FOUND
63
+
64
+ @staticmethod
65
+ def __get_image(soup: BeautifulSoup, tag: str, identification: str, name: str):
66
+ found = soup.find(tag, attrs={identification: name})
67
+ if found:
68
+ return found.get("href")
69
+ return OutInformation.RESOURCE_NOT_FOUND
70
+
71
+ @staticmethod
72
+ def __get_description_fusion(soup: BeautifulSoup):
73
+ [remove_sup.extract() for remove_sup in soup.find_all('sup')]
74
+ try:
75
+ return next(
76
+ p.text.strip() for header in soup.find_all(['h2', 'h3']) if (p := header.find_next_sibling('p')))
77
+ except StopIteration:
78
+ return OutInformation.RESOURCE_NOT_FOUND
79
+
80
+ def __evaluate_scrapper_section(self, list_dict, list_search, tag_found: ScrapFusion):
81
+ empty = self.__return_empty_section(list_dict)
82
+ if empty:
83
+ return empty
84
+
85
+ section_names = list(tag_found.sections.values())
86
+ names = list_dict.get(section_names[0], OutInformation.RESOURCE_NOT_FOUND)
87
+ data = list_dict.get(section_names[1], OutInformation.RESOURCE_NOT_FOUND)
88
+
89
+ return {
90
+ "nombres": self.__names_section(names, tag_found.names) if section_names[0] in list_search else names,
91
+ "data": self.__data_section(data, tag_found.data) if section_names[1] in list_search else data,
92
+ }
93
+
94
+ @staticmethod
95
+ def __return_empty_section(list_dict: dict):
96
+ if not list_dict:
97
+ return {
98
+ "nombres": OutInformation.RESOURCE_NOT_FOUND,
99
+ "data": OutInformation.RESOURCE_NOT_FOUND,
100
+ }
101
+ return None
102
+
103
+ @staticmethod
104
+ def __names_section(name, lista_tags):
105
+ return {key: Tags.clean_text(Tags.catch_error(name, value)) for key, value in lista_tags.items()}
106
+
107
+ @staticmethod
108
+ def __data_section(data, lista_tags):
109
+ return {key: Tags.clean_text(Tags.catch_error(data, value)) for key, value in lista_tags.items()}
110
+
111
+ def __show_information(self, dictionary_basic, dictionary_sections):
112
+ dictionary = {
113
+ "name": dictionary_basic['name'],
114
+ "image": dictionary_basic['image'],
115
+ "description": dictionary_basic['descripcion'],
116
+ "names": dictionary_sections['nombres'],
117
+ "data": dictionary_sections['data'],
118
+ "url_scrap": dictionary_basic['url']
119
+ }
120
+ if self.all_data:
121
+ return dictionary
122
+ return OutInformation.clean_not_found_scrape(dictionary)
@@ -0,0 +1,28 @@
1
+ import json
2
+
3
+
4
+ class OutInformation:
5
+ RESOURCE_NOT_FOUND = 'Not Found In Web'
6
+
7
+ @staticmethod
8
+ def beautiful_print_dict(json_dict: dict):
9
+ beautiful_print = json.dumps(json_dict, indent=4, ensure_ascii=False).encode('utf-8')
10
+ return beautiful_print.decode('utf-8')
11
+
12
+ @classmethod
13
+ def clean_not_found_scrape(cls, character: dict):
14
+ for key, value in character.copy().items():
15
+ if value == cls.RESOURCE_NOT_FOUND:
16
+ character.pop(key)
17
+ elif isinstance(value, dict):
18
+ cls.clean_not_found_scrape(value)
19
+ # si el dict interno quedó vacío tras la limpieza, elimínalo
20
+ if not character.get(key):
21
+ character.pop(key, None)
22
+ elif isinstance(value, list):
23
+ cleaned = [v for v in value if v != cls.RESOURCE_NOT_FOUND]
24
+ if cleaned:
25
+ character[key] = cleaned
26
+ else:
27
+ character.pop(key)
28
+ return character
@@ -0,0 +1,123 @@
1
+ import requests as requests
2
+ from bs4 import BeautifulSoup
3
+
4
+ from DragonBall.Constants.ScrapPlanet import ScrapPlanet
5
+ from DragonBall.Constants.URLS import URL
6
+ from DragonBall.Data.OutInformation import OutInformation
7
+ from DragonBall.Soup.section import Section
8
+ from DragonBall.Soup.tags import Tags
9
+
10
+
11
+ class Planets:
12
+ def __init__(self, name: str, all_data=False):
13
+ self.name = name
14
+ self.all_data = all_data
15
+
16
+ @classmethod
17
+ def planet_list(cls, planet_list: list):
18
+ return [Planets(i).planet_information() for i in planet_list]
19
+
20
+ @staticmethod
21
+ def list():
22
+ request = requests.get(URL.URL_LIST_PLANETS, headers=URL.HEADERS)
23
+ soup = BeautifulSoup(request.content.decode('utf-8'), "html.parser")
24
+ ref = soup.find('div', {"class": "mw-parser-output"})
25
+ if not ref:
26
+ return []
27
+ list_planets = [planet.text for planet in ref.find_all('b')]
28
+ if list_planets:
29
+ list_planets.pop(0)
30
+ return list_planets
31
+
32
+ def planet_information(self):
33
+ url = URL.URL_WIKI + self.name.replace(" ", "_")
34
+ request = requests.get(url, headers=URL.HEADERS)
35
+ soup = BeautifulSoup(request.content.decode('utf-8'), "html.parser")
36
+ list_section = Section.obtain_section_data(soup, 'aside')
37
+ basic_dict = self.__obtain_basic_data(soup, url)
38
+ section_dict = self.__evaluate_scrapper_section(list_section, list(list_section.keys()), ScrapPlanet)
39
+ return self.__show_information(basic_dict, section_dict)
40
+
41
+ def __obtain_basic_data(self, soup: BeautifulSoup, url: str):
42
+ name = self.__get_official_name(soup, "h1", "id", "firstHeading")
43
+ image = self.__get_image(soup, "a", "class", "image image-thumbnail")
44
+ description = self.__get_description_planet(soup)
45
+ return {"url": url, "name": name, "image": image, "descripcion": description}
46
+
47
+ @staticmethod
48
+ def __get_official_name(soup: BeautifulSoup, tag: str, identification: str, element: str):
49
+ # Intento 1: Buscar el h1 con el id exacto
50
+ official_name = Tags.custom_catch_error(soup, tag, identification, element)
51
+ if official_name != OutInformation.RESOURCE_NOT_FOUND:
52
+ return official_name.get_text(strip=True)
53
+
54
+ # Intento 2: Buscar CUALQUIER etiqueta <h1> en la página
55
+ h1 = soup.find("h1")
56
+ if h1:
57
+ return h1.get_text(strip=True)
58
+
59
+ # Intento 3: Usar el título de la pestaña del navegador
60
+ if soup.title:
61
+ return soup.title.text.split("|")[0].strip()
62
+
63
+ return OutInformation.RESOURCE_NOT_FOUND
64
+
65
+ @staticmethod
66
+ def __get_image(soup: BeautifulSoup, tag: str, identification: str, name: str):
67
+ found = soup.find(tag, attrs={identification: name})
68
+ if found:
69
+ return found.get("href")
70
+ return OutInformation.RESOURCE_NOT_FOUND
71
+
72
+ @staticmethod
73
+ def __get_description_planet(soup: BeautifulSoup):
74
+ [remove_sup.extract() for remove_sup in soup.find_all('sup')]
75
+ try:
76
+ return next(
77
+ p.text.strip() for header in soup.find_all(['h2', 'h3']) if (p := header.find_next_sibling('p')))
78
+ except StopIteration:
79
+ return OutInformation.RESOURCE_NOT_FOUND
80
+
81
+ def __evaluate_scrapper_section(self, list_dict, list_search, tag_found: ScrapPlanet):
82
+ empty = self.__return_empty_section(list_dict)
83
+ if empty:
84
+ return empty
85
+
86
+ section_names = list(tag_found.sections.values())
87
+ names = list_dict.get(section_names[0], OutInformation.RESOURCE_NOT_FOUND)
88
+ data = list_dict.get(section_names[1], OutInformation.RESOURCE_NOT_FOUND)
89
+
90
+ return {
91
+ "nombres": self.__names_section(names, tag_found.names) if section_names[0] in list_search else names,
92
+ "data": self.__data_section(data, tag_found.data) if section_names[1] in list_search else data,
93
+ }
94
+
95
+ @staticmethod
96
+ def __return_empty_section(list_dict: dict):
97
+ if not list_dict:
98
+ return {
99
+ "nombres": OutInformation.RESOURCE_NOT_FOUND,
100
+ "data": OutInformation.RESOURCE_NOT_FOUND,
101
+ }
102
+ return None
103
+
104
+ @staticmethod
105
+ def __names_section(name, lista_tags):
106
+ return {key: Tags.clean_text(Tags.catch_error(name, value)) for key, value in lista_tags.items()}
107
+
108
+ @staticmethod
109
+ def __data_section(data, lista_tags):
110
+ return {key: Tags.clean_text(Tags.catch_error(data, value)) for key, value in lista_tags.items()}
111
+
112
+ def __show_information(self, dictionary_basic, dictionary_sections):
113
+ dictionary = {
114
+ "name": dictionary_basic['name'],
115
+ "image": dictionary_basic['image'],
116
+ "description": dictionary_basic['descripcion'],
117
+ "names": dictionary_sections['nombres'],
118
+ "data": dictionary_sections['data'],
119
+ "url_scrap": dictionary_basic['url']
120
+ }
121
+ if self.all_data:
122
+ return dictionary
123
+ return OutInformation.clean_not_found_scrape(dictionary)
@@ -0,0 +1,130 @@
1
+ import requests as requests
2
+ from bs4 import BeautifulSoup
3
+
4
+ from DragonBall.Constants.ScrapSagas import ScrapSagas
5
+ from DragonBall.Constants.URLS import URL
6
+ from DragonBall.Data.OutInformation import OutInformation
7
+ from DragonBall.Soup.section import Section
8
+ from DragonBall.Soup.summary import Summary
9
+ from DragonBall.Soup.tags import Tags
10
+
11
+
12
+ class Sagas:
13
+ def __init__(self, name: str, all_data=False):
14
+ self.name = name
15
+ self.all_data = all_data
16
+
17
+ @classmethod
18
+ def saga_list(cls, saga_list: list):
19
+ return [Sagas(i).saga_information() for i in saga_list]
20
+
21
+ @staticmethod
22
+ def list():
23
+ request = requests.get(URL.URL_LIST_CHRONO, headers=URL.HEADERS)
24
+ soup = BeautifulSoup(request.content.decode('utf-8'), "html.parser")
25
+ toc = soup.find("div", {"id": "toc"})
26
+ if not toc:
27
+ return {}
28
+ summary_data = toc.text.strip().splitlines()
29
+ return Summary.clean_list_summary(summary_data, [1, -2])
30
+
31
+ def saga_information(self):
32
+ url = URL.URL_WIKI + self.name.replace(" ", "_")
33
+ request = requests.get(url, headers=URL.HEADERS)
34
+ soup = BeautifulSoup(request.content.decode('utf-8'), "html.parser")
35
+ list_section = Section.obtain_section_data(soup, 'aside')
36
+ basic_dict = self.__obtain_basic_data(soup, url)
37
+ section_dict = self.__evaluate_scrapper_section(list_section, list(list_section.keys()), ScrapSagas)
38
+ return self.__show_information(basic_dict, section_dict)
39
+
40
+ def __obtain_basic_data(self, soup: BeautifulSoup, url: str):
41
+ name = self.__get_official_name(soup, "h1", "id", "firstHeading")
42
+ image = self.__get_image(soup, "a", "class", "image image-thumbnail")
43
+ description = self.__get_description_saga(soup)
44
+ return {"url": url, "name": name, "image": image, "descripcion": description}
45
+
46
+ @staticmethod
47
+ def __get_official_name(soup: BeautifulSoup, tag: str, identification: str, element: str):
48
+ # Intento 1: Buscar el h1 con el id exacto
49
+ official_name = Tags.custom_catch_error(soup, tag, identification, element)
50
+ if official_name != OutInformation.RESOURCE_NOT_FOUND:
51
+ return official_name.get_text(strip=True)
52
+
53
+ # Intento 2: Buscar CUALQUIER etiqueta <h1> en la página
54
+ h1 = soup.find("h1")
55
+ if h1:
56
+ return h1.get_text(strip=True)
57
+
58
+ # Intento 3: Usar el título de la pestaña del navegador
59
+ if soup.title:
60
+ return soup.title.text.split("|")[0].strip()
61
+
62
+ return OutInformation.RESOURCE_NOT_FOUND
63
+
64
+ @staticmethod
65
+ def __get_image(soup: BeautifulSoup, tag: str, identification: str, name: str):
66
+ found = soup.find(tag, attrs={identification: name})
67
+ if found:
68
+ return found.get("href")
69
+ return OutInformation.RESOURCE_NOT_FOUND
70
+
71
+ @staticmethod
72
+ def __get_description_saga(soup: BeautifulSoup):
73
+ [remove_sup.extract() for remove_sup in soup.find_all('sup')]
74
+ try:
75
+ return next(
76
+ p.text.strip() for header in soup.find_all(['h2', 'h3']) if (p := header.find_next_sibling('p')))
77
+ except StopIteration:
78
+ return OutInformation.RESOURCE_NOT_FOUND
79
+
80
+ def __evaluate_scrapper_section(self, list_dict, list_search, tag_found: ScrapSagas):
81
+ empty = self.__return_empty_section(list_dict)
82
+ if empty:
83
+ return empty
84
+
85
+ section_names = list(tag_found.sections.values())
86
+ names = list_dict.get(section_names[0], OutInformation.RESOURCE_NOT_FOUND)
87
+ data = list_dict.get(section_names[1], OutInformation.RESOURCE_NOT_FOUND)
88
+ serialization = list_dict.get(section_names[2], OutInformation.RESOURCE_NOT_FOUND)
89
+
90
+ return {
91
+ "nombres": self.__names_section(names, tag_found.names) if section_names[0] in list_search else names,
92
+ "data": self.__data_section(data, tag_found.data) if section_names[1] in list_search else data,
93
+ "serializacion": self.__serialization_section(serialization, tag_found.serialization) if section_names[2] in list_search else serialization,
94
+ }
95
+
96
+ @staticmethod
97
+ def __return_empty_section(list_dict: dict):
98
+ if not list_dict:
99
+ return {
100
+ "nombres": OutInformation.RESOURCE_NOT_FOUND,
101
+ "data": OutInformation.RESOURCE_NOT_FOUND,
102
+ "serializacion": OutInformation.RESOURCE_NOT_FOUND,
103
+ }
104
+ return None
105
+
106
+ @staticmethod
107
+ def __names_section(name, lista_tags):
108
+ return {key: Tags.clean_text(Tags.catch_error(name, value)) for key, value in lista_tags.items()}
109
+
110
+ @staticmethod
111
+ def __data_section(data, lista_tags):
112
+ return {key: Tags.clean_text(Tags.catch_error(data, value)) for key, value in lista_tags.items()}
113
+
114
+ @staticmethod
115
+ def __serialization_section(serialization, lista_tags):
116
+ return {key: Tags.clean_text(Tags.catch_error(serialization, value)) for key, value in lista_tags.items()}
117
+
118
+ def __show_information(self, dictionary_basic, dictionary_sections):
119
+ dictionary = {
120
+ "name": dictionary_basic['name'],
121
+ "image": dictionary_basic['image'],
122
+ "description": dictionary_basic['descripcion'],
123
+ "names": dictionary_sections['nombres'],
124
+ "data": dictionary_sections['data'],
125
+ "serialization": dictionary_sections['serializacion'],
126
+ "url_scrap": dictionary_basic['url']
127
+ }
128
+ if self.all_data:
129
+ return dictionary
130
+ return OutInformation.clean_not_found_scrape(dictionary)
@@ -0,0 +1,122 @@
1
+ import requests as requests
2
+ from bs4 import BeautifulSoup
3
+
4
+ from DragonBall.Constants.ScrapGames import ScrapGames
5
+ from DragonBall.Constants.URLS import URL
6
+ from DragonBall.Data.OutInformation import OutInformation
7
+ from DragonBall.Soup.section import Section
8
+ from DragonBall.Soup.summary import Summary
9
+ from DragonBall.Soup.tags import Tags
10
+
11
+
12
+ class VideoGames:
13
+ def __init__(self, name: str, all_data=False):
14
+ self.name = name
15
+ self.all_data = all_data
16
+
17
+ @classmethod
18
+ def game_list(cls, game_list: list):
19
+ return [VideoGames(i).game_information() for i in game_list]
20
+
21
+ @staticmethod
22
+ def list():
23
+ request = requests.get(URL.URL_LIST_GAMES, headers=URL.HEADERS)
24
+ soup = BeautifulSoup(request.content.decode('utf-8'), "html.parser")
25
+ toc = soup.find("div", {"id": "toc"})
26
+ if not toc:
27
+ return {}
28
+ summary_data = toc.text.strip().splitlines()
29
+ return Summary.clean_list_summary(summary_data, [1, -4])
30
+
31
+ def game_information(self):
32
+ url = URL.URL_WIKI + self.name.replace(" ", "_")
33
+ request = requests.get(url, headers=URL.HEADERS)
34
+ soup = BeautifulSoup(request.content.decode('utf-8'), "html.parser")
35
+ list_section = Section.obtain_section_data(soup, 'aside')
36
+ basic_dict = self.__obtain_basic_data(soup, url)
37
+ section_dict = self.__evaluate_scrapper_section(list_section, list(list_section.keys()), ScrapGames)
38
+ return self.__show_information(basic_dict, section_dict)
39
+
40
+ def __obtain_basic_data(self, soup: BeautifulSoup, url: str):
41
+ name = self.__get_official_name(soup, "h1", "id", "firstHeading")
42
+ image = self.__get_image(soup, "a", "class", "image image-thumbnail")
43
+ description = self.__get_description_game(soup)
44
+ return {"url": url, "name": name, "image": image, "descripcion": description}
45
+
46
+ @staticmethod
47
+ def __get_official_name(soup: BeautifulSoup, tag: str, identification: str, element: str):
48
+ # Intento 1: Buscar el h1 con el id exacto
49
+ official_name = Tags.custom_catch_error(soup, tag, identification, element)
50
+ if official_name != OutInformation.RESOURCE_NOT_FOUND:
51
+ return official_name.get_text(strip=True)
52
+
53
+ # Intento 2: Buscar CUALQUIER etiqueta <h1> en la página
54
+ h1 = soup.find("h1")
55
+ if h1:
56
+ return h1.get_text(strip=True)
57
+
58
+ # Intento 3: Usar el título de la pestaña del navegador
59
+ if soup.title:
60
+ return soup.title.text.split("|")[0].strip()
61
+
62
+ return OutInformation.RESOURCE_NOT_FOUND
63
+
64
+ @staticmethod
65
+ def __get_image(soup: BeautifulSoup, tag: str, identification: str, name: str):
66
+ found = soup.find(tag, attrs={identification: name})
67
+ if found:
68
+ return found.get("href")
69
+ return OutInformation.RESOURCE_NOT_FOUND
70
+
71
+ @staticmethod
72
+ def __get_description_game(soup: BeautifulSoup):
73
+ [remove_sup.extract() for remove_sup in soup.find_all('sup')]
74
+ try:
75
+ return next(
76
+ p.text.strip() for header in soup.find_all(['h2', 'h3']) if (p := header.find_next_sibling('p')))
77
+ except StopIteration:
78
+ return OutInformation.RESOURCE_NOT_FOUND
79
+
80
+ def __evaluate_scrapper_section(self, list_dict, list_search, tag_found: ScrapGames):
81
+ empty = self.__return_empty_section(list_dict)
82
+ if empty:
83
+ return empty
84
+
85
+ section_names = list(tag_found.sections.values())
86
+ names = list_dict.get(section_names[0], OutInformation.RESOURCE_NOT_FOUND)
87
+ data = list_dict.get(section_names[1], OutInformation.RESOURCE_NOT_FOUND)
88
+
89
+ return {
90
+ "nombres": self.__names_section(names, tag_found.names) if section_names[0] in list_search else names,
91
+ "data": self.__data_section(data, tag_found.data) if section_names[1] in list_search else data,
92
+ }
93
+
94
+ @staticmethod
95
+ def __return_empty_section(list_dict: dict):
96
+ if not list_dict:
97
+ return {
98
+ "nombres": OutInformation.RESOURCE_NOT_FOUND,
99
+ "data": OutInformation.RESOURCE_NOT_FOUND,
100
+ }
101
+ return None
102
+
103
+ @staticmethod
104
+ def __names_section(name, lista_tags):
105
+ return {key: Tags.clean_text(Tags.catch_error(name, value)) for key, value in lista_tags.items()}
106
+
107
+ @staticmethod
108
+ def __data_section(data, lista_tags):
109
+ return {key: Tags.clean_text(Tags.catch_error(data, value)) for key, value in lista_tags.items()}
110
+
111
+ def __show_information(self, dictionary_basic, dictionary_sections):
112
+ dictionary = {
113
+ "name": dictionary_basic['name'],
114
+ "image": dictionary_basic['image'],
115
+ "description": dictionary_basic['descripcion'],
116
+ "names": dictionary_sections['nombres'],
117
+ "data": dictionary_sections['data'],
118
+ "url_scrap": dictionary_basic['url']
119
+ }
120
+ if self.all_data:
121
+ return dictionary
122
+ return OutInformation.clean_not_found_scrape(dictionary)
@@ -0,0 +1,17 @@
1
+ from bs4 import BeautifulSoup
2
+
3
+
4
+ class Section:
5
+
6
+ @classmethod
7
+ def obtain_section_data(cls, soup: BeautifulSoup, tag: str):
8
+ data_General = soup.find(tag)
9
+ if data_General:
10
+ sections = [i for i in data_General.find_all("section", {'class': 'pi-item pi-group pi-border-color'})]
11
+ return cls.__find_name_section(sections)
12
+ else:
13
+ return dict()
14
+
15
+ @staticmethod
16
+ def __find_name_section(sections: BeautifulSoup):
17
+ return {i.find('h2').text: i for i in sections if i.find('h2')}
@@ -0,0 +1,18 @@
1
+ class Summary:
2
+
3
+ @classmethod
4
+ def clean_list_summary(cls, list_sumary, remove):
5
+ summary = [x for x in list_sumary if x != '']
6
+ return cls.__convert_list_summary_to_dict(summary[remove[0]:remove[1]])
7
+
8
+ @staticmethod
9
+ def __convert_list_summary_to_dict(summary):
10
+ dictionary = {}
11
+ current_key = None
12
+ for item in summary:
13
+ if "." not in item:
14
+ current_key = item.lstrip('1234567890.').strip()
15
+ dictionary[current_key] = []
16
+ else:
17
+ dictionary[current_key].append(item.lstrip('1234567890.').strip())
18
+ return dictionary
@@ -0,0 +1,53 @@
1
+ from bs4 import BeautifulSoup
2
+
3
+ from DragonBall.Constants.URLS import URL
4
+ from DragonBall.Data.OutInformation import OutInformation
5
+
6
+
7
+ class Tags:
8
+
9
+ @classmethod
10
+ def clean_text(cls, elem):
11
+ if elem is None:
12
+ return OutInformation.RESOURCE_NOT_FOUND
13
+ if elem == OutInformation.RESOURCE_NOT_FOUND:
14
+ return elem
15
+ return cls.evaluate_clean_text(elem)
16
+
17
+ @classmethod
18
+ def evaluate_clean_text(cls, elem):
19
+ text = ''
20
+ [remove_sup.extract() for remove_sup in elem.find_all('sup')]
21
+ for e in elem.descendants:
22
+ if isinstance(e, str):
23
+ text += e
24
+ elif e.name in ['br', 'p', 'li']:
25
+ text += '\n'
26
+
27
+ list_data = [x for x in text.strip().splitlines() if x != '']
28
+
29
+ if not list_data:
30
+ list_data = cls.__text_and_link(elem)
31
+
32
+ return list_data[0] if len(list_data) == 1 else list_data
33
+
34
+ @staticmethod
35
+ def catch_error(section, data_source):
36
+ # Guarda: si section no es un Tag/BeautifulSoup, no intentes .find()
37
+ if not hasattr(section, "find"):
38
+ return OutInformation.RESOURCE_NOT_FOUND
39
+ div = section.find("div", {"data-source": data_source})
40
+ if not div:
41
+ return OutInformation.RESOURCE_NOT_FOUND
42
+ value = div.find("div", {"class": "pi-data-value pi-font"})
43
+ return value if value else OutInformation.RESOURCE_NOT_FOUND
44
+
45
+ @staticmethod
46
+ def custom_catch_error(soup: BeautifulSoup, tag: str, identification: str, name: str):
47
+ div = soup.find(tag, {identification: name})
48
+ return div if div else OutInformation.RESOURCE_NOT_FOUND
49
+
50
+ @staticmethod
51
+ def __text_and_link(soup: BeautifulSoup):
52
+ tupla = soup.find_all('a')
53
+ return [{"title": data.get('title'), "url": URL.URL_BASE[:-1] + data.get('href')} for data in tupla]
DragonBall/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+ from DragonBall.Data.Characters import Characters
2
+ from DragonBall.Data.Sagas import Sagas
3
+ from DragonBall.Data.Planets import Planets
4
+ from DragonBall.Data.Fusions import Fusions
5
+ from DragonBall.Data.VideoGames import VideoGames
6
+ from DragonBall.Data.OutInformation import OutInformation
@@ -0,0 +1,111 @@
1
+ Metadata-Version: 2.4
2
+ Name: Dragon-Ball-API-Alejo
3
+ Version: 0.1
4
+ Summary: Api unoficial de dragon ball inspirado de la fandom de dragon ball
5
+ Home-page: https://github.com/xtream-club/Dragon-Ball-API
6
+ Download-URL: https://github.com/xtream-club/Dragon-Ball-API/tarball/0.1
7
+ Author: Eduardo Lopez
8
+ Author-email: nanguelulpz@gmail.com
9
+ License: MIT
10
+ Keywords: Dragon-Ball-Api,Dragon Ball,Api Dragon Ball
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: requests<3,>=2.32
14
+ Requires-Dist: beautifulsoup4<4.15,>=4.12
15
+ Dynamic: author
16
+ Dynamic: author-email
17
+ Dynamic: description
18
+ Dynamic: description-content-type
19
+ Dynamic: download-url
20
+ Dynamic: home-page
21
+ Dynamic: keywords
22
+ Dynamic: license
23
+ Dynamic: requires-dist
24
+ Dynamic: requires-python
25
+ Dynamic: summary
26
+
27
+ Scrapper-DragonBall
28
+ ===============
29
+ Scrapper unofficial de Dragon Ball inspirado en su fandom. <https://dragonball.fandom.com/es/wiki/Dragon_Ball_Wiki_Hispano>. Esta api nos permite obtener datos de personajes, sagas, fusiones, lugares y videojuegos de manera sencilla. Para poder utilizarlo en nuestras aplicaciones.
30
+ ===============
31
+ Requiere version python 3.9
32
+ ===============
33
+ Requerimientos
34
+ ============
35
+ Para instalar los requerimientos instale los requerimientos del archivo requirements.txt con el siguiente comando
36
+
37
+ pip install -r requirements.txt
38
+
39
+ Importaciones
40
+ ============
41
+
42
+ from DragonBall.Data.Characters import Characters
43
+ from DragonBall.Data.Sagas import Sagas
44
+ from DragonBall.Data.Planets import Planets
45
+ from DragonBall.Data.Fusions import Fusions
46
+ from DragonBall.Data.VideoGames import VideoGames
47
+ from DragonBall.Data.OutInformation import OutInformation
48
+
49
+ Instalación
50
+ ============
51
+
52
+ pip install Dragon-Ball-API
53
+
54
+ Usage
55
+ =====
56
+
57
+ >>> from DragonBall.Data.Characters import Characters
58
+
59
+ >>> search_goku = Characters('Goku')
60
+ >>> search_goku.character_information()
61
+
62
+ {
63
+ 'name': 'Son Goku', 'image': 'https://example.com', 'description': 'descripcion',
64
+ 'names': {'japan_name': '...', 'latin_name': '...', 'pronunciation_name': '...', 'other_names': '...'},
65
+ 'data': {'gender': '...', 'birthday': '...', 'origin': '...', 'family': ['...','...'], 'transformations': ['...', '...'], etc.. },
66
+ 'debut': {'sagas': [{'title': '...', 'url': '...'}], 'debut': '...'}
67
+ }
68
+
69
+
70
+ Algunos personajes tendran más datos que otros. Eso dependera de la información que se encuentre en la wiki de dragon ball en ese momento. Si deseamos podemos pasar una lista de personajes a buscar y usar el método list para devolvernos la información de todos los personajes.
71
+
72
+ >>> from DragonBall.Data.Characters import Characters
73
+
74
+ goku_family = ['Son Gohan (abuelo)', 'Bardock', 'Gine', 'Raditz', 'Rey Gyuma', 'Milk', 'Gohan', 'Goten', 'Mr. Satán', 'Videl', 'Pan', 'Son Goku Jr.']
75
+
76
+ >>> character_list = Characters.character_list(goku_family)
77
+
78
+ [{'...'},{'...'}]
79
+
80
+
81
+
82
+
83
+ Podemos ver una lista de los personajes usando el método list de la clase. De la siguiente manera.
84
+
85
+
86
+
87
+ >>> Characters.list()
88
+
89
+ {
90
+ 'Personajes por raza': ['Androides', 'Animales', 'Arlianos', 'Ángeles', '...', '...'],
91
+ 'Personajes por asociación': ['...', '...', '...']
92
+ }
93
+
94
+
95
+
96
+ Si queremos imprimir los datos de manera más legible podemos utilizar el método beautiful_print_dict de la clase OutInformation
97
+
98
+
99
+ >>> OutInformation.beautiful_print_dict(Characters.list())
100
+
101
+ "Personajes por raza": [
102
+ "Androides",
103
+ "Animales",
104
+ "Arlianos",
105
+ "Ángeles",
106
+ "..."
107
+ ]
108
+
109
+
110
+
111
+ Todos estos metodos los podemos aplicar en todas sus clases (sagas, juegos, etc).
@@ -0,0 +1,20 @@
1
+ DragonBall/__init__.py,sha256=hhWzNuDPVxtNobvyjKNHv1cUuoyMlep9qGscWkVVUT0,292
2
+ DragonBall/Constants/ScrapCharacter.py,sha256=2vAWDZkf4cCb0DeAULXH_9vHmDCepJIQMu6qlilGQqk,1355
3
+ DragonBall/Constants/ScrapFusion.py,sha256=qWmLG-SUCD_1UJqjeO536hZFVpTgzq7gkM3de7bclE0,929
4
+ DragonBall/Constants/ScrapGames.py,sha256=5aDDG7jip4UI_GVDqSK7L3GqyO0ogQfAJdJHJsTjj5Y,864
5
+ DragonBall/Constants/ScrapPlanet.py,sha256=BC_aE9PDVznQEvJu5_MT2XKDtyP9G4DfPG6rfwtHfjU,742
6
+ DragonBall/Constants/ScrapSagas.py,sha256=nOVRHKnZRw98oIVJVD3SPoy2EFta8Asxko9aYPT2r9Y,858
7
+ DragonBall/Constants/URLS.py,sha256=YsHU38-Q8aZMwnrH7c1QXrvFbwQpjFyL-3pnCRiXMC8,730
8
+ DragonBall/Data/Characters.py,sha256=BJ_jYWmknBO2-bG1oX87EnVPCpzarDp8WEEzQEpxD-c,5726
9
+ DragonBall/Data/Fusions.py,sha256=O9dBaunz9IqxWwDgbxqEF4lM89RGuNBwEl4QD9_qvpA,5199
10
+ DragonBall/Data/OutInformation.py,sha256=pWO5Mu9bGh5k_1l07k9YziUzknfuZppWV7xXaRfzC94,1057
11
+ DragonBall/Data/Planets.py,sha256=89mxwzVJ5RK6-2urWGK4DXKSb2CT8mVfZrfsv9f0u3w,5208
12
+ DragonBall/Data/Sagas.py,sha256=6fuyWwD0CCJ5HbKKj5FaAqmrx6_wPDy733SkVDnKngk,5757
13
+ DragonBall/Data/VideoGames.py,sha256=f341kt5oW_ju6C6QQvgLsU0s1zRf4OeRTz4klepvBxk,5185
14
+ DragonBall/Soup/section.py,sha256=sY3BvJkRPOjg_8odEm-h7ckNl5eMfhrtPXPi8hg8_jE,562
15
+ DragonBall/Soup/summary.py,sha256=ktYxQxvEIUWD2isu_WJQafNoOYQMZmlaEzzDtxEJvpk,654
16
+ DragonBall/Soup/tags.py,sha256=2Ns8DrGPLadbh-dkKIQqjq-dzrMSuS3MucQW31STNgs,1922
17
+ dragon_ball_api_alejo-0.1.dist-info/METADATA,sha256=nejeZwsx2-aVFBNeCL60GbFh_tI4Wk7qPoGPEdox1TY,3746
18
+ dragon_ball_api_alejo-0.1.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
19
+ dragon_ball_api_alejo-0.1.dist-info/top_level.txt,sha256=BCa2x7xRYl8q8z_qGMKdG9QweNR81bZwa5-Yj0FVXrc,11
20
+ dragon_ball_api_alejo-0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ DragonBall