├── .gitignore ├── LICENSE ├── README.md ├── dev ├── attempts.py ├── new.py └── v3.py ├── imgs ├── neofetch.png ├── oldschool_sprite.png └── progress.png ├── imshow.sh ├── pokefetch.py └── pokefetch.sh /.gitignore: -------------------------------------------------------------------------------- 1 | imgs/* 2 | output/* 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ryan McCormick 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pokefetch 2 | This is a script I'm working on to further my webscraping skills 3 | ## Tools 4 | Python 3 5 | * Requests 6 | * BeautifulSoup 7 | 8 | Bash 9 | * catimg 10 | 11 | [Serebii](https://www.serebii.net) 12 | * Currently rewriting my scraper to use [Bulbapedia](http://bulbapedia.bulbagarden.net) 13 | 14 | ## Context 15 | This script currently asks for the pokedex number of the pokemon you'd like 16 | to get information about, then it will get the picture and some related 17 | information such as type, abilities, weaknesses, etc. 18 | 19 | I wanted to model the output to be similar to screenfetch and neofetch, two popular scripts to grab system information. 20 | 21 | ![Alt text](imgs/neofetch.png?raw=true "Neofetch Example") 22 | 23 | 24 | 25 | ## Setup 26 | 27 | ### Starting steps: 28 | 29 | Clone this repository to a directory of your choice in the command-line: 30 | ``` 31 | git clone https://github.com/rmccorm4/pokefetch 32 | ``` 33 | 34 | Make sure you have all of the necessary third-party libraries described below 35 | 36 | #### Python requests module 37 | 38 | ``` 39 | pip install requests 40 | ``` 41 | 42 | #### Python BeautifulSoup module 43 | 44 | ``` 45 | pip install bs4 46 | ``` 47 | 48 | 49 | #### catimg 50 | 51 | On Arch Linux: 52 | ``` 53 | yaourt -S catimg 54 | ``` 55 | 56 | Otherwise, follow the instructions here: 57 | [https://github.com/posva/catimg](https://github.com/posva/catimg) 58 | 59 | ### Disclaimers 60 | 61 | The "Gender" category that gets printed out uses ascii symbols and may 62 | not print properly depending on your terminal configurations. 63 | 64 | Personally, I use `adobe-source-code-pro-fonts` and I make sure that my 65 | terminal's default encoding is `UTF-8` 66 | 67 | ### Running the script: 68 | 69 | ``` 70 | ./pokefetch.sh 71 | ``` 72 | 73 | Example below. 74 | 75 | 76 | ## Current progress 77 | This is what I have so far: 78 | 79 | ![Alt text](imgs/progress.png?raw=true "Pokefetch Example") 80 | 81 | However this requires a full-screen terminal in order to come out nicely. 82 | 83 | ## To-do 84 | 85 | * [ ] Make sure it works for every single pokemon, including difficult names such as "Mr. Mime" and "Ho-oh" 86 | * [ ] Get higher quality images to output if possible, need to research this more 87 | * [ ] Conversely, try to find more pixellated versions of the newer models in hopes of getting a prettier output 88 | * [ ] Add a -shiny flag to output the shiny sprite instead of the regular one 89 | * [ ] Scrape more relevant information about the pokemon 90 | * [ ] Make script work for default size terminal as well as full-screen? 91 | * [ ] Rewrite my scraping method to be much cleaner and more uniform 92 | * [ ] Include Gen VII pokemon 93 | * [ ] Implement old-school sprites because they come out much nicer as seen below 94 | * [ ] Possibly add old school gifs from the special games like yellow and crystal 95 | 96 | ![Alt text](imgs/oldschool_sprite.png?raw=true "Old School Sprite Example") 97 | -------------------------------------------------------------------------------- /dev/attempts.py: -------------------------------------------------------------------------------- 1 | ######## Get Weaknesses ######## 2 | #weakness_list = soup.find_all(class_="footype") 3 | 4 | """ 5 | ######## Get Classification ######## 6 | classification_index = pageInfo.find("Classification\n") 7 | classification = pageInfo[classification_index:] 8 | end_index = classification.find("\n") 9 | classification = classification[:end_index] 10 | print(classification) 11 | """ 12 | -------------------------------------------------------------------------------- /dev/new.py: -------------------------------------------------------------------------------- 1 | """ 2 | Author: Ryan McCormick 3 | File: pokefetch_v2.py 4 | TODO: Use generation (pokedex number range) to get earliest sprite? 5 | """ 6 | 7 | """ Standard Libraries """ 8 | import sys 9 | import re 10 | import argparse 11 | 12 | """ Third Party Libraries """ 13 | from bs4 import BeautifulSoup 14 | import requests 15 | 16 | """ Get Pokemon Name """ 17 | if len(sys.argv) < 2: 18 | pokemon = input("Enter the name of the pokemon to look up: ").title() 19 | 20 | elif len(sys.argv) == 3: 21 | pokemon = (sys.argv[1] + " " + sys.argv[2]).title() 22 | 23 | elif len(sys.argv) == 2: 24 | pokemon = sys.argv[1].title() 25 | 26 | else: 27 | print("You entered too many arguments!") 28 | sys.exit() 29 | 30 | # Fix Special Cases like Mr. Mime and Mime Jr. ### 31 | pokemon = pokemon.replace(' ', '_') 32 | 33 | """ Get optional arguments """ 34 | parser = argparse.ArgumentParser(description='Look-up pokemon in the terminal for their picture and information.') 35 | #parser.add_argument('--shiny', type=str, default='false', help='"true" or "false" to get the shiny model of the pokemon.') 36 | #parser.add_argument('--old', type=str, default='true', help='"true" or "false" to get the oldest available model of the pokemon.') 37 | #args = parser.parse_args() 38 | #shiny, old = args.shiny, args.old 39 | 40 | """ Start Webscraping """ 41 | url = "http://bulbapedia.bulbagarden.net/wiki/" + pokemon + "_(Pok%C3%A9mon)" 42 | request = requests.get(url) 43 | html = request.content 44 | soup = BeautifulSoup(html, "html.parser") 45 | 46 | ### CATEGORY ### 47 | # Get full html string 48 | category = str(soup.find(title="Pokémon category").contents[0]) 49 | begin = category.find(">") 50 | end = category.find("<", 1) 51 | # Cut it down to just the description 52 | category = category[begin+1 : end] 53 | 54 | ### POKEDEX ENTRY ### 55 | pokedex = str(soup.find_all(title="List of Pokémon by National Pokédex number")[1].contents[0]) 56 | begin = pokedex.find(">") 57 | end = pokedex.find("<", 1) 58 | pokedex = pokedex[begin+1 : end] 59 | 60 | ### TYPES ### 61 | types = [] 62 | for t in soup.find_all(title=re.compile("(type)")): 63 | if t.b.text != "Unknown": 64 | types.append(t.b.text) 65 | else: 66 | break 67 | 68 | 69 | ### ABILITIES ### 70 | tags = list(set([str(word) for word in soup.find_all("a", href=re.compile("(Ability)"), title=re.compile("(Ability)")) if "Cacophony" not in str(word) and '"Ability"' not in str(word)])) 71 | 72 | ability_list = [] 73 | for sentence in tags: 74 | begin = sentence.find('wiki/')+5 75 | end = sentence.find('_(Ability)') 76 | ability_list.append(sentence[begin:end]) 77 | 78 | abilities = "" 79 | for ability in ability_list: 80 | abilities += ability + " - " 81 | 82 | 83 | ### GENDER RATIO ### 84 | 85 | 86 | 87 | print(pokemon) 88 | print(pokedex) 89 | print(types) 90 | print(abilities) 91 | -------------------------------------------------------------------------------- /dev/v3.py: -------------------------------------------------------------------------------- 1 | # Use 'unique CSS selector' 2 | -------------------------------------------------------------------------------- /imgs/neofetch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rmccorm4/Pokefetch/06b14789b4be2667643395bbb24cab4259cc1f11/imgs/neofetch.png -------------------------------------------------------------------------------- /imgs/oldschool_sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rmccorm4/Pokefetch/06b14789b4be2667643395bbb24cab4259cc1f11/imgs/oldschool_sprite.png -------------------------------------------------------------------------------- /imgs/progress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rmccorm4/Pokefetch/06b14789b4be2667643395bbb24cab4259cc1f11/imgs/progress.png -------------------------------------------------------------------------------- /imshow.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # z3bra -- 2014-01-21 4 | 5 | test -z "$1" && exit 6 | 7 | W3MIMGDISPLAY="/usr/lib/w3m/w3mimgdisplay" 8 | FILENAME=$1 9 | FONTH=14 # Size of one terminal row 10 | FONTW=8 # Size of one terminal column 11 | COLUMNS=`tput cols` 12 | LINES=`tput lines` 13 | 14 | read width height <<< `echo -e "5;$FILENAME" | $W3MIMGDISPLAY` 15 | 16 | max_width=$(($FONTW * $COLUMNS)) 17 | max_height=$(($FONTH * $(($LINES - 2)))) # substract one line for prompt 18 | 19 | if [[ -z "$width" ]]; then 20 | width=$max_width 21 | fi 22 | 23 | if [[ -z "$height" ]]; then 24 | height=$max_height 25 | fi 26 | 27 | if [[ "$width" -gt "$max_width" ]]; then 28 | height=$(($height * $max_width / $width)) 29 | width=$max_width 30 | fi 31 | if [[ "$height" -gt "$max_height" ]]; then 32 | width=$(($width * $max_height / $height)) 33 | height=$max_height 34 | fi 35 | 36 | w3m_command="0;1;0;0;$width;$height;;;;;$FILENAME\n4;\n3;" 37 | 38 | tput cup $(($height/$FONTH)) 0 39 | echo -e $w3m_command|$W3MIMGDISPLAY 40 | 41 | echo "w3m_command: $w3m_command" 42 | echo "w3mimgdisplay: $W3MIMGDISPLAY" 43 | echo "FILENAME: $FILENAME" 44 | echo "Columns: $COLUMNS" 45 | echo "Rows: $LINES" 46 | echo "Height: $height" 47 | echo "Width: $width" 48 | echo "Max Height: $max_height" 49 | echo "Max Width: $max_width" 50 | -------------------------------------------------------------------------------- /pokefetch.py: -------------------------------------------------------------------------------- 1 | from bs4 import BeautifulSoup 2 | import requests 3 | import sys 4 | import re 5 | 6 | ######## Get Pokemon Name ######## 7 | if len(sys.argv) < 2: 8 | pokemon = input("Enter the name of the pokemon to look up: ").title() 9 | 10 | # Two Word Names Like Mime Jr. 11 | elif len(sys.argv) == 3: 12 | pokemon = (sys.argv[1] + " " + sys.argv[2]).title() 13 | 14 | else: 15 | pokemon = sys.argv[1].title() 16 | 17 | if pokemon == "Mr. Mime": 18 | pokemon = "Mr.Mime" #serebii listed this way 19 | 20 | elif pokemon == "Ho-Oh": 21 | pokemon = "Ho-oh" #serebii listed this way 22 | 23 | ######## Get Pokedex Entry Number ######## 24 | begin_url = "http://serebii.net/pokedex-xy/" 25 | request1 = requests.get(begin_url) 26 | html1 = request1.content 27 | soup1 = BeautifulSoup(html1, "html.parser") 28 | page_info1 = soup1.get_text() 29 | # Pokedex Entries Start At Index 5000 30 | pokemon_index = page_info1.find(pokemon, 5000) 31 | 32 | if pokemon_index == -1: 33 | print("You didn't enter a valid pokemon!") 34 | sys.exit() 35 | 36 | pokedex_number = page_info1[pokemon_index-4 : pokemon_index-1] 37 | 38 | ######## Get Pokemon Info ######## 39 | full_url = begin_url + pokedex_number + ".shtml" 40 | request2 = requests.get(full_url) 41 | html2 = request2.content 42 | soup2 = BeautifulSoup(html2, "html.parser") 43 | page_info2 = soup2.get_text() 44 | 45 | ######## Get Stats ######## 46 | base_total = soup2.find(string=re.compile("Base Stats - Total:")) 47 | # Only want everything after Total 48 | base_total = base_total[base_total.find("Total"):] 49 | base_stats = soup2.find_all(class_="fooinfo") 50 | 51 | hp = str(base_stats[len(base_stats)-21]) 52 | attack = str(base_stats[len(base_stats)-20]) 53 | defence = str(base_stats[len(base_stats)-19]) 54 | spec_attack = str(base_stats[len(base_stats)-18]) 55 | spec_defence = str(base_stats[len(base_stats)-17]) 56 | speed = str(base_stats[len(base_stats)-16]) 57 | 58 | hp = hp[hp.find(">")+1 : hp.find("/")-1] 59 | attack = attack[attack.find(">")+1 : attack.find("/")-1] 60 | defence = defence[defence.find(">")+1 : defence.find("/")-1] 61 | spec_attack = spec_attack[spec_attack.find(">")+1 : spec_attack.find("/")-1] 62 | spec_defence = spec_defence[spec_defence.find(">")+1 : spec_defence.find("/")-1] 63 | speed = speed[speed.find(">")+1:speed.find("/")-1] 64 | 65 | ######## Get Abilities ######## 66 | abilities_index = page_info2.find("Abilities:") 67 | abilities = page_info2[abilities_index:] 68 | end_index = abilities.find("\n") 69 | abilities = abilities[:end_index-1] 70 | 71 | ######## Get Gender ######## 72 | gender_index = page_info2.find("GenderType") 73 | gender = page_info2[gender_index:] 74 | end_index = gender.find("\n") 75 | gender = gender[:end_index] 76 | gender = gender[gender.find(" ")+1:] 77 | if "is Genderless" in gender: 78 | gender = "Genderless" 79 | 80 | ######## Get Image ######## 81 | base_image_url = "http://www.serebii.net/xy/pokemon/" 82 | full_image_url = base_image_url + pokedex_number + ".png" 83 | image_bytes = requests.get(full_image_url) 84 | 85 | # Write bytes of image to file 86 | filename = pokemon.title() + ".png" 87 | myfile = open("imgs/"+filename, "wb") 88 | for byte in image_bytes: 89 | myfile.write(byte) 90 | myfile.close() 91 | 92 | ######## Print everything out ######## 93 | print("Name: ", pokemon) 94 | print("Pokedex Number: ", pokedex_number) 95 | print("Gender Ratio: ", str(gender)) 96 | print(abilities) 97 | print("---Base Stats---") 98 | print(base_total) 99 | print("Hp: ", hp) 100 | print("Attack: ", attack) 101 | print("Defence: ", defence) 102 | print("Special Attack: ", spec_attack) 103 | print("Special Defence: ", spec_defence) 104 | print("Speed: ", speed) 105 | -------------------------------------------------------------------------------- /pokefetch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Make output directory if it doesn't already exist 4 | mkdir -p output 5 | 6 | # Prepend 10 blank lines for nice formatting next to image 7 | echo > output/stats.txt 8 | for ((i=0; i<9; i++)); 9 | do 10 | echo >> output/stats.txt 11 | done 12 | 13 | # Get pokemon stats and output to file 14 | /usr/bin/env python3 pokefetch.py $@ >> output/stats.txt 15 | 16 | # Format input for image 17 | POKEMON=$@ # '$@' refers to command line argument 18 | POKEMON=${POKEMON[@]^} # This converts to Title Case 19 | if [ $POKEMON == "Ho-oh" ] ; then 20 | POKEMON="Ho-Oh" 21 | # This won't work, need to handle space separated args eventualy 22 | # For now just input names like Mr.Mime with no spaces 23 | elif [ $POKEMON == "Mr. Mime" ] ; then 24 | POKEMON="Mr.Mime" 25 | fi 26 | 27 | # Get image and output to file 28 | catimg -w 120 "imgs/$POKEMON.png" > output/image.txt 29 | 30 | # Print image and stats side by side 31 | pr -mts output/image.txt output/stats.txt 32 | --------------------------------------------------------------------------------