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