# installing some packages
!pip3 install dicttoxml
!pip3 install xmltodict
!pip3 install jikanpy
from google.colab import files
import pandas as pd
from dicttoxml import dicttoxml
import xmltodict, json
import xml.etree.ElementTree as ET
from xml.dom import minidom
from jikanpy import Jikan
import time
uploaded = files.upload()
# Here you need to upload the 9anime export.txt file.
# It should contain MAL urls of the anime in your history.
for fn in uploaded.keys():
print('User uploaded file "{name}" with length {length} bytes'.format(
name=fn, length=len(uploaded[fn])))
Saving export.txt to export.txt User uploaded file "export.txt" with length 189 bytes
# Next, we access the MAL id(s) from the urls
NineAnimeList = pd.read_csv('./export.txt', names=['url'])
metaData = (NineAnimeList['url'].str.split('/')).apply(pd.Series)
anime = pd.DataFrame()
# The anime list dataset
anime['id'] = metaData[4] # this is all that we'll need.
anime['name'] = metaData[5]
anime['url'] = NineAnimeList['url']
# Here's how it should look
anime.head(2)
id | name | url | |
---|---|---|---|
0 | 28171 | Shokugeki_no_Souma | http://myanimelist.net/anime/28171/Shokugeki_n... |
1 | 38691 | Dr_Stone | http://myanimelist.net/anime/38691/Dr_Stone |
# Required fields for the XML file. All of methods go into the MAL class.
# If you know what you are doing feel free to edit the animeMeta dictionary.
# For example you can change the my_start_date and my_finish_date to today() or
# import a separate series and feed it to the for loop inside the createDictList
# function with a date argument added in animeDetails.
class MAL():
def __init__(self, user_id, user_name):
self.user_id = user_id
self.user_name = user_name
self.jikan = Jikan()
self.MALdict = None
self.MALxml = None
def animeDetails(self, id):
# We will use the Jikan API with the anime id(s) to acquire additional information on the shows.
# The jikan request rate limit is 1 request/2s (30 requests/minute).
# I'll use 2.1s delay between requests just to be safe.
# For 400 anime it should take exactly 14m
time.sleep(2.1)
series = self.jikan.anime(id)
animeMeta = {
'series_animedb_id': series['mal_id'],
'series_title': series['title'],
'series_type': series['type'],
'series_episodes': series['episodes'],
'my_id': 0,
'my_watched_episodes': series['episodes'],
'my_start_date': '0000-00-00',
'my_finish_date': '0000-00-00',
'my_rated': None,
'my_score': None,
'my_storage': None,
'my_storage_value': 0.00,
'my_status': 'Completed',
'my_comments': None,
'my_times_watched': 0,
'my_rewatch_value': None,
'my_priority': 'LOW',
'my_tags': None,
'my_rewatching': 0,
'my_rewatching_ep': 0,
'my_discuss': 1,
'my_sns': 'default',
'update_on_import': 1}
return animeMeta
def createDictList(self, animeIDs):
myinfo = {'user_id': self.user_id,
'user_name': self.user_name,
'user_export_type': '1',
'user_total_anime': len(animeIDs),
'user_total_watching': '0',
'user_total_completed': len(animeIDs),
'user_total_onhold': '0',
'user_total_dropped': '0',
'user_total_plantowatch': '0'}
# Collecting all of the details json files into a single list
anime = []
for seriesID in animeIDs:
anime.append(self.animeDetails(seriesID))
# Constructing the main object
MALdict = {
'myanimelist': {
'myinfo': myinfo,
'anime': anime}}
self.MALdict = MALdict
return MALdict
def dictToMALxml(self, animeDict):
# Converts a dict into an MAL xml file
def itemName(arg):
return 'anime'
# A small bug caused by the inherent differences between json and xml datatypes.
# In json you can't reuse a key twice, while the same is not true for xml file.
animeDict['myanimelist']['CustomRemoval'] = animeDict['myanimelist'].pop(
'anime')
xml = dicttoxml(animeDict['myanimelist'], root=True, custom_root='myanimelist', ids=False,
attr_type=False, item_func=itemName)
# Removing a key due the json->xml bug
xml = xml.replace(b'<CustomRemoval>', b'')
xml = xml.replace(b'</CustomRemoval>', b'')
MALxml = minidom.parseString(xml).toprettyxml(indent=" ")
self.MALxml = MALxml
return MALxml
def createMALxml(self, animeIDs):
self.createDictList(animeIDs)
self.dictToMALxml(self.MALdict)
return self.MALxml
# Usage
# You don't actually need to specify an id or a username.
# As of now the site fixes the issue for you. So you can leave this as is.
mal = MAL(user_id='1234', user_name='John Joe')
MALxml = mal.createMALxml(anime['id'])
# Writting the MALxml into a file
with open("./MAL.xml", "w") as f:
f.write(MALxml)
# Print to view the final output (or check the file directly)
# If you are in google colab click the folder icon on the right.
# You should see a file named MAL.xml on the left. Right click and download.
# Now go to https://myanimelist.net/import.php and upload the file.
# You are done!
print(MALxml)
<?xml version="1.0" ?> <myanimelist> <myinfo> <user_id>1234</user_id> <user_name>John Joe</user_name> <user_export_type>1</user_export_type> <user_total_anime>4</user_total_anime> <user_total_watching>0</user_total_watching> <user_total_completed>4</user_total_completed> <user_total_onhold>0</user_total_onhold> <user_total_dropped>0</user_total_dropped> <user_total_plantowatch>0</user_total_plantowatch> </myinfo> <anime> <series_animedb_id>28171</series_animedb_id> <series_title>Shokugeki no Souma</series_title> <series_type>TV</series_type> <series_episodes>24</series_episodes> <my_id>0</my_id> <my_watched_episodes>24</my_watched_episodes> <my_start_date>0000-00-00</my_start_date> <my_finish_date>0000-00-00</my_finish_date> <my_rated/> <my_score/> <my_storage/> <my_storage_value>0.0</my_storage_value> <my_status>Completed</my_status> <my_comments/> <my_times_watched>0</my_times_watched> <my_rewatch_value/> <my_priority>LOW</my_priority> <my_tags/> <my_rewatching>0</my_rewatching> <my_rewatching_ep>0</my_rewatching_ep> <my_discuss>1</my_discuss> <my_sns>default</my_sns> <update_on_import>1</update_on_import> </anime> <anime> <series_animedb_id>38691</series_animedb_id> <series_title>Dr. Stone</series_title> <series_type>TV</series_type> <series_episodes>24</series_episodes> <my_id>0</my_id> <my_watched_episodes>24</my_watched_episodes> <my_start_date>0000-00-00</my_start_date> <my_finish_date>0000-00-00</my_finish_date> <my_rated/> <my_score/> <my_storage/> <my_storage_value>0.0</my_storage_value> <my_status>Completed</my_status> <my_comments/> <my_times_watched>0</my_times_watched> <my_rewatch_value/> <my_priority>LOW</my_priority> <my_tags/> <my_rewatching>0</my_rewatching> <my_rewatching_ep>0</my_rewatching_ep> <my_discuss>1</my_discuss> <my_sns>default</my_sns> <update_on_import>1</update_on_import> </anime> <anime> <series_animedb_id>32182</series_animedb_id> <series_title>Mob Psycho 100</series_title> <series_type>TV</series_type> <series_episodes>12</series_episodes> <my_id>0</my_id> <my_watched_episodes>12</my_watched_episodes> <my_start_date>0000-00-00</my_start_date> <my_finish_date>0000-00-00</my_finish_date> <my_rated/> <my_score/> <my_storage/> <my_storage_value>0.0</my_storage_value> <my_status>Completed</my_status> <my_comments/> <my_times_watched>0</my_times_watched> <my_rewatch_value/> <my_priority>LOW</my_priority> <my_tags/> <my_rewatching>0</my_rewatching> <my_rewatching_ep>0</my_rewatching_ep> <my_discuss>1</my_discuss> <my_sns>default</my_sns> <update_on_import>1</update_on_import> </anime> <anime> <series_animedb_id>2167</series_animedb_id> <series_title>Clannad</series_title> <series_type>TV</series_type> <series_episodes>23</series_episodes> <my_id>0</my_id> <my_watched_episodes>23</my_watched_episodes> <my_start_date>0000-00-00</my_start_date> <my_finish_date>0000-00-00</my_finish_date> <my_rated/> <my_score/> <my_storage/> <my_storage_value>0.0</my_storage_value> <my_status>Completed</my_status> <my_comments/> <my_times_watched>0</my_times_watched> <my_rewatch_value/> <my_priority>LOW</my_priority> <my_tags/> <my_rewatching>0</my_rewatching> <my_rewatching_ep>0</my_rewatching_ep> <my_discuss>1</my_discuss> <my_sns>default</my_sns> <update_on_import>1</update_on_import> </anime> </myanimelist>
PS: It took me three hours to finish writing and implementing the code, but even so, mistakes aren't something we can intentionally prevent, so watch out for bugs.