Готовый парсер на Python для сайта tgstat.ru



Простой парсер для демонстрации возможности парсинга статистики Telegram-каналов с сайта tgstat.ru. Используются библиотеки Selenium и BeautifulSoup. Принцип работы — открывается страница расширенного поиска, вводится ключевое слово, инициируется прокрутка для загрузки всех результатов. Далее собираются все ссылки на расширенную статистику и в цикле собирается информация. Данные сохраняются в список списков, после завершения обхода записываются в файл Excel.

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

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

Есть возможность заказать парсинг с нужными параметрами или готовый парсер. Обращаться:
Telegram: https://t.me/nikylichev_aleksandr
Почта: parser@mob25.com

    options = uc.ChromeOptions()
    profile_path = os.path.join(
        os.environ.get('LOCALAPPDATA', os.path.expanduser('~')),
        'Google', 'Chrome', 'User Data'
    )
    options.add_argument(f"--user-data-dir={profile_path}")
    # Или другое имя профиля
    options.add_argument("--profile-directory=Default")
    options.add_argument("--disable-blink-features=AutomationControlled")
    try:
        driver = uc.Chrome(
            options=options
        )
    except Exception as e:
        print(e)
    driver.set_page_load_timeout(30)

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

    keyword = 'Голубицкая'
    driver.get("https://tgstat.ru/channels/search")
    time.sleep(DELAY)
    search_input = WebDriverWait(driver, 20).until(
        EC.presence_of_element_located((By.ID, "q")))
    search_input.clear()

    for char in keyword:
        search_input.send_keys(char)
        time.sleep(0.1)
    time.sleep(DELAY)
    search_button = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.ID, "search-form-submit-btn")))
    search_button.click()

Открытие страницы и ввод ключевого слов в строку поиска. Ввод по одному символу с паузами, далее поиск кнопки поиска и нажатие на нее.

while True:
        try:
            driver.execute_script(
                "window.scrollTo(0, document.body.scrollHeight);")
            time.sleep(DELAY)
            button_all = WebDriverWait(driver, 10).until(
                EC.element_to_be_clickable(
                    (By.CLASS_NAME, "btn.btn-light.border.lm-button.py-1.min-width-220px"))
            )
            time.sleep(0.5)
            button_all.click()
            print("Нажата кнопка 'Показать больше'")
            time.sleep(DELAY1)

        except (NoSuchElementException, TimeoutException):
            break

Прокрутка с последующим нажатием на кнопку «Показать больше». Цикл до тех пор, пока кнопка не будет найдена (загружены все найденные телеграм-каналы).

find_cards = driver.find_elements(
        By.CSS_SELECTOR, 'div.col.col-12.col-sm-5.col-md-5.col-lg-4')
    all_links = []
    for card in find_cards:
        all_links.append(card.find_element(
            By.CSS_SELECTOR, "a[target='_blank']").get_attribute("href"))
    print(f'Найдено ссылок - {len(all_links)})')

Извлечение всех ссылок на подробную статистку. Данные сохраняются в список all_links.

    count = 0
    parsing_result = []  # список списков для записи в таблицу
    for link in all_links:
        count += 1
        print(f'Обработка {count} ссылки')
        current_line = []  # список с данными текущего канала
        driver.get(link)
        time.sleep(DELAY)
        page_source = driver.page_source
        soup = BeautifulSoup(page_source, 'lxml')
        title = (soup.find('h1').text).strip()
        # сбор описания
        start_hr = soup.find('hr', class_='m-0 mb-3')
        result_texts = []
        if start_hr:
            current = start_hr.next_sibling
            while current and current.name != 'p':
                if isinstance(current, NavigableString) and current.strip():
                    result_texts.append(current.strip())
                    result_texts.append(' ')
                elif current.name:  # Если это тег (например <br>)
                    if current.get_text(strip=True):
                        result_texts.append(' ')
                        result_texts.append(current.get_text(strip=True))
                    elif current.name == 'br':
                        result_texts.append('\n')
                current = current.next_sibling

        description = (''.join(result_texts).strip()).replace('  ', ' ')

        # сбор гео и язык
        geo_block = soup.find('div', class_='mt-4')
        if geo_block:
            texts = []
            for element in geo_block.find('h5').next_siblings:
                if isinstance(element, str) and element.strip():
                    texts.append(element.strip())
        geo_text = ' '.join(texts)
        geo_text = " ".join(geo_text.split())
        # остальные блоки
        all_blocks = soup.find_all(
            'div', class_='card card-body pt-1 pb-2 position-relative border min-height-155px')
        subscribers = all_blocks[0].find(
            'h2', class_='text-dark').get_text(strip=True)
        creation_date = (
            soup.find('b', class_='text-dark mr-2 font-20')).get_text(strip=True)
        url = (soup.find('div', class_='text-center text-sm-left')
               ).find('a')['href']
        category = (((soup.find_all('h5', class_='mb-0'))
                    [1]).find_next('a')).get_text(strip=True)
        current_line = [title, geo_text, subscribers,
                        creation_date, url, category, description]
        parsing_result.append(current_line)
    time.sleep(DELAY)

    df = pd.DataFrame(parsing_result)
    df.columns = ['Название', 'Гео и язык', 'Подписчики',
                  'Дата создания', 'Ссылка', 'Категория', 'Описание']
    writer = pd.ExcelWriter('test2.xlsx', engine='xlsxwriter')
    df.to_excel(writer, sheet_name='welcome', index=False)

Обход всех ссылок, извлечение необходимой информации, запись в файл Excel. Сохраняются: название канала, количество подписчиков, гео и язык группы, дата создания, категория, ссылка на группу и описание.



Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: