Анализ дружеских связей социальной сети ВКонтакте, TypeError: индексы списка должны быть целыми, а не стр - PullRequest
0 голосов
/ 23 января 2019

У меня есть код для анализа дружеских отношений, для социальной сети «ВКонтакте», когда я запускаю основной файл, появляется ошибка - «Ошибка ввода: индексы списка должны быть целыми числами, а не str».

Код был написан на Python версии 3.4, я запускаю его на Python 3.6. Код должен давать результаты для последующего преобразования в граф.

 def force(f, delay=delay):
    """При неудачном запросе сделать паузу и попробовать снова"""
    def tmp(*args, **kwargs):
        while True:
            try:
                res = f(*args, **kwargs)
                break
            except KeyError:
                time.sleep(delay)
        return res
    return tmp

class VkException(Exception):
    def __init__(self, message):
        self.message = message

    def __str__(self):
        return self.message


class VkFriends():
    """
    Находит друзей, находит общих друзей
    """
    parts = lambda lst, n=25: (lst[i:i + n] for i in iter(range(0, len(lst), n)))
    make_targets = lambda lst: ",".join(str(id) for id in lst)

    def __init__(self, *pargs):
        try:
            self.token, self.my_id, self.api_v, self.max_workers = pargs
            self.my_name, self.my_last_name, self.photo = self.base_info([self.my_id])
            self.all_friends, self.count_friends = self.friends(self.my_id)
        except VkException as error:
            sys.exit(error)

    def request_url(self, method_name, parameters, access_token=False):
        """read https://vk.com/dev/api_requests"""

        req_url = 'https://api.vk.com/method/users.get?user_ids=63585955&fields=photo&access_token=becb5e1dbecb5e1dbecb5e1da3beadc41bbbecbbecb5e1de50c3aeda94cb9fe2b60e49c&v=5.74'.format(
            method_name=method_name, api_v=self.api_v, parameters=parameters)

        if access_token:
            req_url = '{}&access_token={token}'.format(req_url, token=self.token)

        return req_url

    def base_info(self, ids):
        """read https://vk.com/dev/users.get"""
        r = requests.get(self.request_url('users.get', 'user_ids=%s&fields=photo' % (','.join(map(str, ids))))).json()
        if 'error' in r.keys():
            raise VkException('Error message: %s Error code: %s' % (r['error']['error_msg'], r['error']['error_code']))
        r = r['response'][0]
        # Проверяем, если id из settings.py не деактивирован
        if 'deactivated' in r.keys():
            raise VkException("User deactivated")
        return r['first_name'], r['last_name'], r['photo']

    def friends(self, id):
        """
        read https://vk.com/dev/friends.get
        Принимает идентификатор пользователя
        """
        # TODO: слишком много полей для всего сразу, город и страна не нужны для нахождения общих друзей
        r = requests.get(self.request_url('friends.get',
                'user_id=%s&fields=uid,first_name,last_name,photo,country,city,sex,bdate' % id)).json()['response']
        #r = list(filter((lambda x: 'deactivated' not in x.keys()), r['items']))
        return {item['id']: item for item in r['items']}, r['count']

    def common_friends(self):
        """
        read https://vk.com/dev/friends.getMutual and read https://vk.com/dev/execute
        Возвращает в словаре кортежи с инфой о цели и списком общих друзей с инфой
        """
        result = []
        # разбиваем список на части - по 25 в каждой
        for i in VkFriends.parts(list(self.all_friends.keys())):
            r = requests.get(self.request_url('execute.getMutual',
                            'source=%s&targets=%s' % (self.my_id, VkFriends.make_targets(i)), access_token=True)).json()['response']
            for x, id in enumerate(i):
                result.append((self.all_friends[int(id)], [self.all_friends[int(i)] for i in r[x]] if r[x] else None))

        return result

    def deep_friends(self, deep):
        """
        Возвращает словарь с id пользователей, которые являются друзьями, или друзьями-друзей (и т.д. в зависимсти от
        deep - глубины поиска) указаннного пользователя
        """
        result = {}

        @force
        def worker(i):      
            r = requests.get(self.request_url('execute.deepFriends', 'targets=%s' % VkFriends.make_targets(i), access_token=True)).json()['response']
            for x, id in enumerate(i):
                result[id] = tuple(r[x]["items"]) if r[x] else None

        def fill_result(friends):
            with ThreadPoolExecutor(max_workers=self.max_workers) as pool:
                [pool.submit(worker, i) for i in VkFriends.parts(friends)]

        for i in range(deep):
            if result:
                # те айди, которых нет в ключах + не берем id:None
                fill_result(list(set([item for sublist in result.values() if sublist for item in sublist]) - set(result.keys())))
            else:
                fill_result(requests.get(self.request_url('friends.get', 'user_id=%s' % self.my_id, access_token=True)).json()['response']["items"])

        return result

    def from_where_gender(self):
        """
        Возвращает кортеж из 3х частей
        0 -  сколько всего/в% друзей в определнной локации (country, city)
        1 - список, содержащий количество друзей того или иного пола. Где индекс
            0 - пол не указан
            1 - женский;
            2 - мужской;
        2 - сколько друзей родилось в тот или иной день
        """
        locations, all, genders, bdates = [{}, {}], [0, 0], [0, 0, 0], {}

        def calculate(dct, all):
            return {k: (dct[k], round(dct[k]/all * 100, 2)) for k, v in dct.items()}

        def constr(location, dct, ind):
            if location in dct.keys():
                place = dct[location]["title"]
                locations[ind][place] = 1 if place not in locations[ind] else locations[ind][place] + 1
                all[ind] += 1

        for i in self.all_friends.values():
            constr("country", i, 0)
            constr("city", i, 1)
            if "sex" in i.keys():
                genders[i["sex"]] += 1
            if "bdate" in i.keys():
                date = '.'.join(i["bdate"].split(".")[:2])
                bdates[date] = 1 if date not in bdates else bdates[date] + 1

        return (calculate(locations[0], all[0]), calculate(locations[1], all[1])), genders, bdates

    @staticmethod
    def save_load_deep_friends(myfile, sv, smth=None):
        if sv and smth:
            pickle.dump(smth, open(myfile, "wb"))
        else:
            return pickle.load(open(myfile, "rb"))

if __name__ == '__main__':
    a = VkFriends(token, my_id, api_v, max_workers)
    print(a.my_name, a.my_last_name, a.my_id, a.photo)
    #print(a.common_friends())
    df = a.deep_friends(deep)
    print(df)
    VkFriends.save_load_deep_friends('deep_friends_dct', True, df)
    #print(pickle.load( open('deep_friends_dct', "rb" )))
    #print(a.from_where_gender())

Я, к сожалению, не знаю, что должно появиться на выходе. Скорее всего, он должен дать мне файл JSON. Это не мой код, я собираюсь его запустить, автор кода, к сожалению, тоже не знает ответа.

...