Дом, отдых, хобби

здравствуйте,нужна переписка задним числом,сможете помочь? - вопрос №2654793

ноябрь 12, 2017 г.

  • Всего ответов: 1

  • Иван - аватарка

    Иван

    33-й в Доме и отдыхе

    Здравствуйте. Сегодня мы научимся изменять дату отправки личных сообщений в социальной сети ВКонтакте. Хочу сказать сразу, что я не рассказываю что-то новое. В интернете полно аналогичных методов и я сам какие-то куски кода брал оттуда. Поэтому, не судите строго.

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

    Начнем.

    Первый способ. Метод вложенной переписки.

    Алгоритм: создаем переписку, редактируем, меняем дату, отсылаем назад в виде пересылки.
    Самым обычным способом, создаем переписку между двумя аккаунтами ВКонтакте. Подключаем каждый аккаунт к API. Для этого достаточно перейти по данной ссылке и разрешить сбор информации с аккаунта:

    oauth.vk.com/authorize?client_id=3245775&redirect_uri=http://api.vk.com/blank.html&scope=messages&display=page&response_type=token

    В следствии, приложению будут доступны все данные пользователя. Не забудьте запомнить свой токен.

    Далее, вытащим личные сообщения. Я буду использовать Python. Чтобы получить историю сообщений используем messages.getHistory [https://vk.com/dev/messages.getHistory]:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    # -*- coding: utf-8 -*-
     
    import
    codecs
    import
    ConfigParser
    import
    datetime
    import
    json
    import
    sys
    import
    urllib2
    from
    urllib 
    import
    urlencode
     
    import
    vk_auth
     
    def
    _api(method, params, token):
        
    params.append((
    "access_token"
    , token))
        
    url 
    =
    "<a href="https://api.vk.com/method/%s?%s">https://api.vk.com/method/%s?%s</a>"
    %
    (method, urlencode(params))
     
        
    return
    json.loads(urllib2.urlopen(url).read())[
    "response"
    ]
     
    # read config values
     
    Config 
    =
    ConfigParser.ConfigParser()
    Config.read(
    "config.ini"
    )
     
    login 
    =
    Config.get(
    "auth"
    , 
    "username"
    )
    password 
    =
    Config.get(
    "auth"
    , 
    "password"
    )
    messages_id 
    =
    Config.get(
    "messages"
    , 
    "chat_id"
    )
    messages_type 
    =
    Config.get(
    "messages"
    , 
    "chat_type"
    )
    app_id 
    =
    Config.get(
    "application"
    , 
    "app_id"
    )
     
    # some chat preparation
     
    if
    messages_type 
    =
    =
    "interlocutor"
    :
        
    is_chat 
    =
    False
    elif
    messages_type 
    =
    =
    "chat"
    :
        
    is_chat 
    =
    True
    else
    :
        
    sys.exit(
    "Messages type must be either interlocutor or chat."
    )
     
    # auth to get token
     
    try
    :
        
    token, user_id 
    =
    vk_auth.auth(login, password, app_id, 
    'messages'
    )
    except
    RuntimeError:
        
    sys.exit(
    "Incorrect login/password. Please check it."
    )
     
    sys.stdout.write(
    'Authorized vk\n'
    )
     
    # get some information about chat
     
    selector 
    =
    "chat_id"
    if
    is_chat 
    else
    "uid"
    messages 
    =
    _api(
    "messages.getHistory"
    , [(selector, messages_id)], token)
     
    out 
    =
    codecs.
    open
    (
        
    'vk_exported_dialogue_%s%s.txt'
    %
    (
    'ui'
    if
    not
    is_chat 
    else
    'c'
    , messages_id),
        
    "w+"
    , 
    "utf-8"
    )
     
    human_uids 
    =
    [messages[
    1
    ][
    "uid"
    ]]
     
    # Export uids from dialogue.
    # Due to vk.api, start from 1.
    for
    i 
    in
    range
    (
    1
    , 
    100
    ):
        
    try
    :
            
    if
    messages[i][
    "uid"
    ] !
    =
    human_uids[
    0
    ]:
                
    human_uids.append(messages[i][
    "uid"
    ])
        
    except
    IndexError:
            
    pass
     
    # Export details from uids
    human_details 
    =
    _api(
        
    "users.get"
    ,
        
    [(
    "uids"
    , 
    ','
    .join(
    str
    (v) 
    for
    v 
    in
    human_uids))],
        
    token
    )
     
    human_details_index 
    =
    {}
    for
    human_detail 
    in
    human_details:
        
    human_details_index[human_detail[
    "uid"
    ]] 
    =
    human_detail
     
    def
    write_message(who, to_write):
        
    out.write(u
    '[{date}] {full_name}:\n {message} \n\n\n'
    .
    format
    (
    *
    *
    {
            
    'date'
    : datetime.datetime.fromtimestamp(
                
    int
    (to_write[
    "date"
    ])).strftime(
    '%Y-%m-%d %H:%M:%S'
    ),
                
    'full_name'
    : 
    '%s %s'
    %
    (
                    
    human_details_index[who][
    "first_name"
    ], human_details_index[who][
    "last_name"
    ]),
                    
    'message'
    : to_write[
    "body"
    ].replace('
    ', '
    \n')
        
    }))
     
    mess 
    =
    0
    max_part 
    =
    200
    # Due to vk.api
     
    cnt 
    =
    messages[
    0
    ]
    sys.stdout.write(
    "Count of messages: %s\n"
    %
    cnt)
     
    while
    mess !
    =
    cnt:
        
    # Try to retrieve info anyway
     
    while
    True
    :
        
    try
    :
            
    message_part 
    =
    _api(
                
    "messages.getHistory"
    ,
                
    [(selector, messages_id), (
    "offset"
    , mess), (
    "count"
    , max_part), (
    "rev"
    , 
    1
    )],
                
    token
            
    )
        
    except
    Exception as e:
            
    sys.stderr.write(
    'Got error %s, continue...\n'
    %
    e)
            
    continue
        
    break
     
    try
    :
        
    for
    i 
    in
    range
    (
    1
    , 
    201
    ):
            
    write_message(message_part[i][
    "uid"
    ], message_part[i])
    except
    IndexError:
        
    break
     
    result 
    =
    mess 
    +
    max_part
    if
    result > cnt:
        
    result 
    =
    (mess 
    -
    cnt) 
    +
    mess
        
    mess 
    =
    result
        
    sys.stdout.write(
    "Exported %s messages of %s\n"
    %
    (mess, cnt))
     
    out.close()
    sys.stdout.write(‘done!\n')

    Далее, для простоты, поставим одну и ту же дату на все сообщения. Я не претендую на оптимизированный код и очевидно, что его можно ужать, но я хочу продемонстрировать как можно подробную работу парсера с подобными XML:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    while
    (
    true
    ) {
        
    doc = XDocument . Load(
    "<a href="https://api.vk.com/method/messages.getHistory.xml?uid=12345&offset=">https://api.vk.com/method/messages.getHistory.xml?uid=12345&offset=</a>"
    + m + 
    "&count=200&access_token="
    + token);
        
    foreach (XElement el in doc . Root . Elements()) {
            
    if
    (el . Name . ToString() == 
    "message"
    ) {
                
    foreach (XElement el_msg in el . Elements()) {
                    
    if
    (el_msg . Name == 
    "date"
    ) {
                        
    foreach (XElement el_date in el_msg . Elements()) {
                            
    if
    (el_date . Name == 
    " 1403320931"
    ) {
                                
    el_date . Name = 
    '1403429673'
    ;
                                
    // то есть меняем дату на любую другую
                                
    k++;
                            
    }
                        
    }
                    
    }
                
    }
            
    }
        
    }
        
    m += 
    200
    ;
    }

    Я думаю, что основная идея здесь понятна. Осталось вернуть сообщения на сервер. Для этого нам понадобиться функция message.send(). Объект message должен обратиться к полю date, но сервер ВКонтакте устанавливает время у себя на сервере сам. Однако, если мы отправим сообщения как вложенную переписку — все получиться.

    Наши письма должны имеют вложенную структуру, значит надо вызывать метод парсинга рекурсивно. Но в Java можно поступить проще. Всё, что находиться внутри цикла forEach, мы будем помещать в отдельный класс. В следствии, в методе accept будет происходить всё то, что было бы в теле цикла. В VkApiMessage есть поле fwd_messages. В нем будет хранится список из объектов пересланных сообщений VkApiMessage:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    private
    static
    class
    MessageConsumer 
    implements
    Consumer<VKApiMessage> {
        
    @Override
    public
    void
    accept(VKApiMessage message) {}
    }
     
    messages.stream().forEach(
    new
    MessageConsumer());
    if
    (!message.fwd_messages.isEmpty()) {
        
    System.out.println(
    "<div class='wall'>"
    );
        
    message.fwd_messages.forEach(
    new
    MessageConsumer());
        
    System.out.println(
    "</div>"
    );
    }

    Далее, просто отправляем сообщения назад на сервер. Здесь, думаю, все очевидно. Аналогично, можно легко использовать поле “attachment” объекта message. [https://vk.com/dev/messages.send]

    В общем, результат выглядит ничем не хуже оригинала в ВК:

    Второй способ. Метод изменения GMT на сервере.

    Алгоритм: меняем время на сервере, отправляем сообщения.

    Второй метод несколько легче первого, так как нам не нужно старые(но измененные) сообщения возвращать назад на сервер (кстати, иногда, это не получается сделать из-за “глупого” сервера). Второй же способ работает более надежно.

    Здесь нам не нужны готовые сообщения. Мы их создадим сами и перешлем на сервер, предварительно изменив GMT (часовой пояс). Для таких целей нам понадобиться абузоустойчивый VPS. Желательно на базе CentOS.

    Сначала, меняем время и дату на сервере. Опять же, это можно сделать любым другим способом. Можно так:

    1
    2
    3
    4
    5
    # mv /etc/localtime /etc/localtime.bak
    ln
    -s 
    /usr/share/zoneinfo/Europe/USA
    /etc/localtime
    # date MMDDhhmm
    # date 03182015
    # man date

    Настраиваем наш сервер под данные сервера ВК:
    IP:87.240.182.185
    Browser: Mozilla/5.0 (compatible; vkShare; +http://vk.com/dev/Share)
    Port: 36035
    Host: srv185-182-240-87.vk.com

    Не забываем про регистрация на API (см. Первый способ). Отправляем сообщения через уже знакомую функцию message.send().

    Объект message, описывающий личное сообщение, возвращает поле “date” — дата отправки сообщения в формате unixtime. Обратите внимание на фразу “дата отправки”. Ничего не говорится про дату получения сообщения сервером ВКонтакте. [https://vk.com/dev/message]

    Вот и все. Результат аналогичный первому. Все очень просто.

    Третий способ. Сниффер трафика.

    Алгоритм: качаем/покупаем сниффер, радуемся.
    Самый простой метод. Но, к сожалению, методика зависит от качества программы, которую мы качаем из интернета.
    Итак, можно просто попробовать скачать/купить что-то типо Charles, словить запрос, редактировать его (дату) и дублировать. Программа перехватывает пакет, меняет время отправки внутри пакета и отправляет контакту. Сервис ВК получает уже заданное unixtime сообщение. Таких снифферов в интернете куча. Но качественных и бесплатных найти сложно. Однако, они стоят не так дорого.

    Как Вы уже поняли, отправить личное сообщение задним числом не составляет труда. Я не написал выше полностью все коды, а только самые необходимые и сложные. Дописать остальные, думаю, не составит труда. Большое спасибо.

    декабрь 6, 2017 г.