Простой парсер для демонстрации возможности парсинга статистики 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. Сохраняются: название канала, количество подписчиков, гео и язык группы, дата создания, категория, ссылка на группу и описание.
