@asyncio.coroutine
def get_character(name, tries=5):
    "Returns a dictionary with a player's info\n\n    The dictionary contains the following keys: name, deleted, level, vocation, world, residence,\n    married, gender, guild, last,login, chars*.\n        *chars is list that contains other characters in the same account (if not hidden).\n        Each list element is dictionary with the keys: name, world.\n    May return ERROR_DOESNTEXIST or ERROR_NETWORK accordingly."
    try:
        url = (url_character + urllib.parse.quote(name.encode('iso-8859-1')))
    except UnicodeEncodeError:
        return ERROR_DOESNTEXIST
    char = dict()
    try:
        page = (yield from aiohttp.get(url))
        content = (yield from page.text(encoding='ISO-8859-1'))
    except Exception:
        if (tries == 0):
            log.error("getPlayer: Couldn't fetch {0}, network error.".format(name))
            return ERROR_NETWORK
        else:
            tries -= 1
            (yield from asyncio.sleep(network_retry_delay))
            ret = (yield from get_character(name, tries))
            return ret
    try:
        startIndex = content.index('<div class="BoxContent"')
        endIndex = content.index('<B>Search Character</B>')
        content = content[startIndex:endIndex]
    except ValueError:
        if (tries == 0):
            log.error("getPlayer: Couldn't fetch {0}, network error.".format(name))
            return ERROR_NETWORK
        else:
            tries -= 1
            (yield from asyncio.sleep(network_retry_delay))
            ret = (yield from get_character(name, tries))
            return ret
    if ('Name:</td><td>' not in content):
        return ERROR_DOESNTEXIST
    m = re.search('Name:</td><td>([^<,]+)', content)
    if m:
        char['name'] = m.group(1).strip()
    m = re.search(', will be deleted at ([^<]+)', content)
    if m:
        char['deleted'] = True
    m = re.search('Vocation:</td><td>([^<]+)', content)
    if m:
        char['vocation'] = m.group(1)
    m = re.search('Level:</td><td>(\\d+)', content)
    if m:
        char['level'] = int(m.group(1))
    for onchar in global_online_list:
        if (onchar.split('_', 1)[1] == char['name']):
            c = userDatabase.cursor()
            c.execute('SELECT last_level FROM chars WHERE name LIKE ?', (char['name'],))
            result = c.fetchone()
            if result:
                char['level'] = abs(result['last_level'])
            c.close()
            break
    m = re.search('World:</td><td>([^<]+)', content)
    if m:
        char['world'] = m.group(1)
    m = re.search('Residence:</td><td>([^<]+)', content)
    if m:
        char['residence'] = m.group(1)
    m = re.search('Married To:</td><td>?.+name=([^"]+)', content)
    if m:
        char['married'] = urllib.parse.unquote_plus(m.group(1), encoding='ISO-8859-1')
    m = re.search('Sex:</td><td>([^<]+)', content)
    if m:
        if (m.group(1) == 'male'):
            char['gender'] = 'male'
        else:
            char['gender'] = 'female'
    m = re.search('Membership:</td><td>([^<]+)\\sof the', content)
    if m:
        char['rank'] = m.group(1)
        m = re.search('GuildName=.*?([^&]+).+', content)
        if m:
            char['guild'] = urllib.parse.unquote_plus(m.group(1))
    m = re.search('House:</td><td> <a href=\\"https://secure\\.tibia\\.com/community/\\?subtopic=houses.+houseid=(\\d+)&amp;character=(?:[^&]+)&amp;action=characters\\" >([^<]+)</a> \\(([^(]+)\\) is paid until ([A-z]+).*?;(\\d+).*?;(\\d+)', content)
    if m:
        char['house_id'] = m.group(1)
        char['house'] = m.group(2)
        char['house_town'] = m.group(3)
    m = re.search('Last Login:</td><td>([^<]+)', content)
    if m:
        lastLogin = m.group(1).replace('&#160;', ' ').replace(',', '')
        if ('never' in lastLogin):
            char['last_login'] = None
        else:
            char['last_login'] = lastLogin
    c = userDatabase.cursor()
    c.execute('SELECT user_id FROM chars WHERE name LIKE ?', (char['name'],))
    result = c.fetchone()
    char['owner_id'] = (None if (result is None) else result['user_id'])
    c = userDatabase.cursor()
    c.execute('SELECT vocation, name, id, world FROM chars WHERE name LIKE ?', (name,))
    result = c.fetchone()
    if result:
        if (result['vocation'] != char['vocation']):
            c.execute('UPDATE chars SET vocation = ? WHERE id = ?', (char['vocation'], result['id']))
            log.info("{0}'s vocation was set to {1} from {2} during get_character()".format(char['name'], char['vocation'], result['vocation']))
        if (result['name'] != char['name']):
            c.execute('UPDATE chars SET name = ? WHERE id = ?', (char['name'], result['id']))
            log.info('{0} was renamed to {1} during get_character()'.format(result['name'], char['name']))
        if (result['world'] != char['world']):
            c.execute('UPDATE chars SET world = ? WHERE id = ?', (char['world'], result['id']))
            log.info("{0}'s world was set to {1} from {2} during get_character()".format(char['name'], char['world'], result['world']))
    c = userDatabase.cursor()
    for category in highscores_categories:
        c.execute((((('SELECT ' + category) + ',') + category) + '_rank FROM chars WHERE name LIKE ?'), (name,))
        result = c.fetchone()
        if result:
            if ((result[category] is not None) and (result[(category + '_rank')] is not None)):
                char[category] = result[category]
                char[(category + '_rank')] = result[(category + '_rank')]
    char['deaths'] = []
    regex_deaths = 'valign="top" >([^<]+)</td><td>(.+?)</td></tr>'
    pattern = re.compile(regex_deaths, (re.MULTILINE + re.S))
    matches = re.findall(pattern, content)
    for m in matches:
        death_time = m[0].replace('&#160;', ' ').replace(',', '')
        death_level = ''
        death_killer = ''
        death_by_player = False
        if (m[1].find('Died') != (- 1)):
            regex_deathinfo_monster = 'Level (\\d+) by ([^.]+)'
            pattern = re.compile(regex_deathinfo_monster, (re.MULTILINE + re.S))
            m_deathinfo_monster = re.search(pattern, m[1])
            if m_deathinfo_monster:
                death_level = m_deathinfo_monster.group(1)
                death_killer = m_deathinfo_monster.group(2)
        else:
            regex_deathinfo_player = 'Level (\\d+) by .+?name=([^"]+)'
            pattern = re.compile(regex_deathinfo_player, (re.MULTILINE + re.S))
            m_deathinfo_player = re.search(pattern, m[1])
            if m_deathinfo_player:
                death_level = m_deathinfo_player.group(1)
                death_killer = urllib.parse.unquote_plus(m_deathinfo_player.group(2))
                death_by_player = True
        try:
            char['deaths'].append({'time': death_time, 'level': int(death_level), 'killer': death_killer, 'byPlayer': death_by_player})
        except ValueError:
            continue
    char['chars'] = []
    try:
        startIndex = content.index('<B>Characters</B>')
        content = content[startIndex:]
        regex_chars = '<TD WIDTH=10%><NOBR>([^<]+)[^?]+.+?VALUE=\\"([^\\"]+)'
        pattern = re.compile(regex_chars, (re.MULTILINE + re.S))
        m = re.findall(pattern, content)
        if m:
            for (world, name) in m:
                name = urllib.parse.unquote_plus(name)
                char['chars'].append({'name': name, 'world': world})
    except Exception:
        pass
    return char
Returns a dictionary with a player's info

The dictionary contains the following keys: name, deleted, level, vocation, world, residence,
married, gender, guild, last,login, chars*.
    *chars is list that contains other characters in the same account (if not hidden).
    Each list element is dictionary with the keys: name, world.
May return ERROR_DOESNTEXIST or ERROR_NETWORK accordingly.
@asyncio.coroutine
def get_character(name, tries=5):
    "Returns a dictionary with a player's info\n\n    The dictionary contains the following keys: name, deleted, level, vocation, world, residence,\n    married, gender, guild, last,login, chars*.\n        *chars is list that contains other characters in the same account (if not hidden).\n        Each list element is dictionary with the keys: name, world.\n    May return ERROR_DOESNTEXIST or ERROR_NETWORK accordingly."
    try:
        url = (url_character + urllib.parse.quote(name.encode('iso-8859-1')))
    except UnicodeEncodeError:
        return ERROR_DOESNTEXIST
    char = dict()
    try:
        page = (yield from aiohttp.get(url))
        content = (yield from page.text(encoding='ISO-8859-1'))
    except Exception:
        if (tries == 0):
            log.error("getPlayer: Couldn't fetch {0}, network error.".format(name))
            return ERROR_NETWORK
        else:
            tries -= 1
            (yield from asyncio.sleep(network_retry_delay))
            ret = (yield from get_character(name, tries))
            return ret
    try:
        startIndex = content.index('<div class="BoxContent"')
        endIndex = content.index('<B>Search Character</B>')
        content = content[startIndex:endIndex]
    except ValueError:
        if (tries == 0):
            log.error("getPlayer: Couldn't fetch {0}, network error.".format(name))
            return ERROR_NETWORK
        else:
            tries -= 1
            (yield from asyncio.sleep(network_retry_delay))
            ret = (yield from get_character(name, tries))
            return ret
    if ('Name:</td><td>' not in content):
        return ERROR_DOESNTEXIST
    m = re.search('Name:</td><td>([^<,]+)', content)
    if m:
        char['name'] = m.group(1).strip()
    m = re.search(', will be deleted at ([^<]+)', content)
    if m:
        char['deleted'] = True
    m = re.search('Vocation:</td><td>([^<]+)', content)
    if m:
        char['vocation'] = m.group(1)
    m = re.search('Level:</td><td>(\\d+)', content)
    if m:
        char['level'] = int(m.group(1))
    for onchar in global_online_list:
        if (onchar.split('_', 1)[1] == char['name']):
            c = userDatabase.cursor()
            c.execute('SELECT last_level FROM chars WHERE name LIKE ?', (char['name'],))
            result = c.fetchone()
            if result:
                char['level'] = abs(result['last_level'])
            c.close()
            break
    m = re.search('World:</td><td>([^<]+)', content)
    if m:
        char['world'] = m.group(1)
    m = re.search('Residence:</td><td>([^<]+)', content)
    if m:
        char['residence'] = m.group(1)
    m = re.search('Married To:</td><td>?.+name=([^"]+)', content)
    if m:
        char['married'] = urllib.parse.unquote_plus(m.group(1), encoding='ISO-8859-1')
    m = re.search('Sex:</td><td>([^<]+)', content)
    if m:
        if (m.group(1) == 'male'):
            char['gender'] = 'male'
        else:
            char['gender'] = 'female'
    m = re.search('Membership:</td><td>([^<]+)\\sof the', content)
    if m:
        char['rank'] = m.group(1)
        m = re.search('GuildName=.*?([^&]+).+', content)
        if m:
            char['guild'] = urllib.parse.unquote_plus(m.group(1))
    m = re.search('House:</td><td> <a href=\\"https://secure\\.tibia\\.com/community/\\?subtopic=houses.+houseid=(\\d+)&amp;character=(?:[^&]+)&amp;action=characters\\" >([^<]+)</a> \\(([^(]+)\\) is paid until ([A-z]+).*?;(\\d+).*?;(\\d+)', content)
    if m:
        char['house_id'] = m.group(1)
        char['house'] = m.group(2)
        char['house_town'] = m.group(3)
    m = re.search('Last Login:</td><td>([^<]+)', content)
    if m:
        lastLogin = m.group(1).replace('&#160;', ' ').replace(',', )
        if ('never' in lastLogin):
            char['last_login'] = None
        else:
            char['last_login'] = lastLogin
    c = userDatabase.cursor()
    c.execute('SELECT user_id FROM chars WHERE name LIKE ?', (char['name'],))
    result = c.fetchone()
    char['owner_id'] = (None if (result is None) else result['user_id'])
    c = userDatabase.cursor()
    c.execute('SELECT vocation, name, id, world FROM chars WHERE name LIKE ?', (name,))
    result = c.fetchone()
    if result:
        if (result['vocation'] != char['vocation']):
            c.execute('UPDATE chars SET vocation = ? WHERE id = ?', (char['vocation'], result['id']))
            log.info("{0}'s vocation was set to {1} from {2} during get_character()".format(char['name'], char['vocation'], result['vocation']))
        if (result['name'] != char['name']):
            c.execute('UPDATE chars SET name = ? WHERE id = ?', (char['name'], result['id']))
            log.info('{0} was renamed to {1} during get_character()'.format(result['name'], char['name']))
        if (result['world'] != char['world']):
            c.execute('UPDATE chars SET world = ? WHERE id = ?', (char['world'], result['id']))
            log.info("{0}'s world was set to {1} from {2} during get_character()".format(char['name'], char['world'], result['world']))
    c = userDatabase.cursor()
    for category in highscores_categories:
        c.execute((((('SELECT ' + category) + ',') + category) + '_rank FROM chars WHERE name LIKE ?'), (name,))
        result = c.fetchone()
        if result:
            if ((result[category] is not None) and (result[(category + '_rank')] is not None)):
                char[category] = result[category]
                char[(category + '_rank')] = result[(category + '_rank')]
    char['deaths'] = []
    regex_deaths = 'valign="top" >([^<]+)</td><td>(.+?)</td></tr>'
    pattern = re.compile(regex_deaths, (re.MULTILINE + re.S))
    matches = re.findall(pattern, content)
    for m in matches:
        death_time = m[0].replace('&#160;', ' ').replace(',', )
        death_level = 
        death_killer = 
        death_by_player = False
        if (m[1].find('Died') != (- 1)):
            regex_deathinfo_monster = 'Level (\\d+) by ([^.]+)'
            pattern = re.compile(regex_deathinfo_monster, (re.MULTILINE + re.S))
            m_deathinfo_monster = re.search(pattern, m[1])
            if m_deathinfo_monster:
                death_level = m_deathinfo_monster.group(1)
                death_killer = m_deathinfo_monster.group(2)
        else:
            regex_deathinfo_player = 'Level (\\d+) by .+?name=([^"]+)'
            pattern = re.compile(regex_deathinfo_player, (re.MULTILINE + re.S))
            m_deathinfo_player = re.search(pattern, m[1])
            if m_deathinfo_player:
                death_level = m_deathinfo_player.group(1)
                death_killer = urllib.parse.unquote_plus(m_deathinfo_player.group(2))
                death_by_player = True
        try:
            char['deaths'].append({'time': death_time, 'level': int(death_level), 'killer': death_killer, 'byPlayer': death_by_player})
        except ValueError:
            continue
    char['chars'] = []
    try:
        startIndex = content.index('<B>Characters</B>')
        content = content[startIndex:]
        regex_chars = '<TD WIDTH=10%><NOBR>([^<]+)[^?]+.+?VALUE=\\"([^\\"]+)'
        pattern = re.compile(regex_chars, (re.MULTILINE + re.S))
        m = re.findall(pattern, content)
        if m:
            for (world, name) in m:
                name = urllib.parse.unquote_plus(name)
                char['chars'].append({'name': name, 'world': world})
    except Exception:
        pass
    return char