Авторские статьи Современные методы парсинга Avito

Discussion in 'Статьи' started by FriLL, 16 Apr 2018.

  1. FriLL

    FriLL Member

    Joined:
    14 Sep 2008
    Messages:
    65
    Likes Received:
    20
    Reputations:
    6
    1. INTRO

    Привет читатель. Сегодня я расскажу о том как можно ускорить процесс парсинга
    небезызвестного сайта Avito.ru. На сегодняшний день рынок подобного софта
    наполнен разнообразными продуктами. Взгянем немного на принципы их работы, а потом
    сделаем и свой, ни чем не уступающий, а возможно и превосходящий по характеристикам
    продукт.

    2. Цель

    Цель нашего продукта это собрать с максимальной скоростью базу данных
    подобного вида

    ТЕЛЕФОН;ИМЯ;РЕГИОН;КАТЕГОРИЯ

    Думаю для тебя не будет секретом что базы таких форматов успешно продаются
    на просторов наших интернетов, т.к. являются хорошим подспорьем для
    всевозможных маркетинговых и рекламных акций. Ведь наверняка если ты хоть
    раз размещал объявление на Авито тебе приходил тематический спам? Для
    нашего проекта выберем автомобильную тематику в г.Санкт-Петеребург.


    3. Разведка

    На данный момент я могу выделить 3 вектора для работы потенциального парсера

    a) Собственно сам сайт Avito.ru

    Парсер, забирающий данные отсюда по всей вероятности будет наиболее медленным
    т.к. с сервера придется тащить больше всего данных и что самое неприятное, так
    нужный нам телефон находится в виде PNG картинки.

    [​IMG]

    Опустим момент что картинка статична и то что для расшифровки подобных изображений
    в текст уже есть библиотеки для разных языков, но это все равно не обеспечит
    нам необходимую скоростью



    b) мобильная версия m.avito.ru

    По моим наблюдения большинство парсеров которые встречаются в природе работают именно
    через данный ресурс. Страницы для мобильной версии облегчены да и номер телефона в
    текстовом виде, что конечно радует (хотя чтобы его получить надо тоже немного исхитриться
    с REFERER).

    [​IMG]

    Но опять же мы тащим с сайта "мусор" в виде бесполезного текста, который
    в маштабах парсинга десятков тысяч объявлений существенно снизит нам скорость



    c) Приложение Avito для iOS и Androind

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

    [​IMG]

    И скорее всего это происходит путем JSON запросов. Т.е никаких
    тегов и прочей ненужной нам инфы.



    4. Подготовительные работы

    Загоревшись вопросом, я понял что первым делом необходимо перехватить трафик приложения
    Из девайсов у меня имеется iPhone 7, но снифферов собственного трафика для iOS я не нашел.
    Выйти из положения я решил с помощью программы Fiddler.

    Из описания программы:

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

    Как выснилось трафик можно инспектировать не только между компьютером, но и между iPhone и удаленным хостом (конечно находясь в одной wi-fi сети с компьютером, на котором установлен Fiddler),предварительно разрешив удаленный коннект в настройках Fiddler

    [​IMG]


    Что еще немаловажно после подключения к отладочному прокси необходимо по адресу http://ipv4.fiddler:8888/ скачать сертификат и добавить его к коренным в iPhone

    [​IMG]

    [​IMG]

    Если этого не сделать то мы не сможем инспектировать https траффик


    5. Разбор траффика

    После выполнения всех вышеперечисленных действий можно открывать приложение на смартфоне, ставить нужные настройки поиска и смотреть на траффик.


    [​IMG]

    Отлично! Как мы и предпологали ответ пришел в JSON. Разберем GET запрос и исследуем ответ сервера

    https://avito.ru/api/9/items?
    categoryId =9 # ID=9 соответсвует разделу автомобили
    display =grid # Смена этого значения не влияло на выдачу
    locationId =637640 # Регион - Санкт-Петеребург
    page =1 # без комментариев
    searchRadius =200 #радиус поиска км
    sort =default # сортировка, можно выставить по разным критериям
    key =EzeC8aidairahqu2Eeb1quee9einaeFieboocohX # уникальный ключ, который привязан к приложению. Смена на чтото другое привет к ошибке выдачи


    С запросом вроде разобрались, теперь перейдем к ответу
    JSON ответ это листинг на 30 объявлений. Листинг не содежит номеров телефонов,
    поэтому мы заберем из него только ID объявления

    ['result']['items'][0]['value']['id']

    и перейдем к запросу на более детальное рассмотрение.

    Открыв в приложении конкретное объявление мы обращаемся по следующему адресу:

    https://avito.ru/api/7/items/1296576162?includeRefs=true&key=ЕzC8aidairahqu2Eeb1quee9einaeFieboocohX

    Где 1296576162 это ID нашего объявления, а EzeC8aidairahqu2Eeb1quee9einaeFieboocohX уже известный нам ключ

    [​IMG]

    А вот и телефон!
    Итак, данные необходимы для нашей базы данных


    ['contacts']['list'][0]['value']['uri']
    # Номер телефона
    ['seller']['name'] # Имя разместившего
    ['refs']['locations'] # Регион и подрегион
    ['parameters']['flat'][0]['description'] # категория

    Могу сказать что информации там куда больше, но в формате одной статьи рассказать
    обо всех не представляется возможным. Если будет интересно ты сам можешь все это посмтреть



    6. Пишем парсер

    Пора все наши полученные данные превратить в код парсера. Я буду писать на Python 3.6. Из сторонних библиотек нам пригодится requests, она нужна для удобного обращения к http ресурсам

    Установка вполне проста
    >> pip install requests

    Теперь код:

    PHP:
    import requests
    import json
    import time


    nums 
    # для счетчика объявлений

    def avito_id(page):
        global 
    nums
        idlist 
    = []
        
    url f'https://avito.ru/api/9/items?categoryId=9&display=grid&locationId=653240&page={page}&sort=default&key=ExeC8aidairahqu2Eeb1quee9einaeFieboocohX'
        
    print(f'page: {page}')
        try:
            
    requests.get(url)
            
    rawdata json.loads(r.text)
            
    0
            
    while len(rawdata['result']['items']): #сколько объявлений есть в списке столько и пройдем
                
    if 'id' in rawdata['result']['items'][i]['value']: # не все объявления из списка содержат ID(реклама например), нам такие не нужны
                    
    id rawdata['result']['items'][i]['value']['id']
                    
    idlist.append(id# Добавляем в список те самые ID объявлений
                    
    i=i+1
                
    else:
                    
    i=i+1
                    
    continue
     
        
    except requests.RequestException#на случай провалов соединения
            
    print('Bad connection')

        if (
    len(idlist) > 0): # А вдруг объявлений нет?
            
    0
            citykey 
    = []
            while 
    len(idlist):
                
    url f"https://www.avito.ru/api/7/items/{idlist[i]}?includeRefs=true&key=EzeC8aidairahqu2Eeb1quee9einaeFieboocohX&"
                
    # Из списка собраных ID составляем ссылки и выдергиваем нужные данные
                
    try:
                    
    requests.get(url)
                    
    rawdata json.loads(r.text# модуль для загрузки json
                    
    if 'seller' in rawdata and 'name' in rawdata['seller'] and len(rawdata['contacts']['list']) > 0:
                        
    tel rawdata['contacts']['list'][0]['value']['uri'].replace(
                            
    'ru.avito://1/phone/call?number=%2B7''8'# заменим ссылочный вид телефона на приемлемый нам
                        
    name rawdata['seller']['name']
                        
    cat rawdata['parameters']['flat'][0]['description']
                        for 
    key in rawdata['refs']['locations'].keys():
                            
    citykey.append(key)
                        
    location rawdata['refs']['locations'][citykey[0]]['name']
                        if 
    len(citykey) > 1:
                            
    sublocation rawdata['refs']['locations'][citykey[1]]['name']
                        else:
                            
    sublocation ''
                        
    print(f'{tel} : {name} : {location} : {cat}')
                        
    nums nums 1
                except requests
    .RequestException:
                    print(
    'Bad connection')
                
    1

    speedtime 
    time.time() # считаем время выполенения

    i=1
    while nums<1000#Для теста соберем 1000 записей
        
    avito_id(i#и запускаем цикл на постраничный парсинг
        
    i=i+1
     
    print(f'Собрано {nums} записей за')
    print(
    time.time() - speedtime)

    Хочу обратить внимание на то, что этот код у тебя работать не будет. Единственно что тебе
    нужно будет для этого исправить - это поставить в значение key свой ключ приложения


    [​IMG]


    1000 записей за 174 секунды. Неплохо, не так ли?
    Соответвенно на 10000 записей у нас уйдет около 30мин
    PROFIT!

    Кто зарабатывает на этом? возможно спросишь ты.
    Вот прайс с одного из сайтов торгующих подобной инфой

    [​IMG]


    7. Итог


    Надеюсь моя статья тебе понравилась и была полезной. Я решил ее написать потому что
    сам не нашел подобных описаний. Без сомнения есть те, кто пользуется подобным способом,но спешат об этом рассказывать). При определенной сноровке ты можешь усовершенствовать мой код, например поставив дополнительные фильтры или собирать только объявления частных лиц, игнорируя компании. Я думаю ты уже догадался что сервис Avito далеко не последний где можно применить данную статью, но об этом в другой раз.)

    Мой telegram : @AndreyPython
     
    #1 FriLL, 16 Apr 2018
    Last edited: 18 Apr 2018
    Veil, morozec, Jerri and 1 other person like this.
  2. morozec

    morozec New Member

    Joined:
    2 Mar 2008
    Messages:
    4
    Likes Received:
    0
    Reputations:
    0
    Статья интересная, так и подталкивает к действию.
    Но на данныи момент если перехватывать траффик представленным способом, то приложение авито не запускается, как и авто.ру.
    Может кто подскажет способ как сниффить трафик на андроиде..
     
  3. FriLL

    FriLL Member

    Joined:
    14 Sep 2008
    Messages:
    65
    Likes Received:
    20
    Reputations:
    6
    Выясните как добавить в Android сертификат к корневым. Скорее всего проблема в этом

    Возможно поможет https://support.google.com/nexus/answer/2844832?hl=ru
     
Loading...