#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Скрипт для поиска учебных заведений в Челябинске через 2GIS Places API """ import requests import json import time from typing import List, Dict, Optional class TwoGISSearcher: """Клиент для работы с 2GIS Places API""" def __init__(self, api_key: Optional[str] = None): self.base_url = "https://catalog.api.2gis.com/3.0/items" self.api_key = api_key or "f61cfc4b-55b7-4937-8625-c00932bee844" self.session = requests.Session() # Челябинск (region_id получен из документации 2GIS) self.chelyabinsk_location = "55.1644,61.4368" # координаты центра Челябинска self.chelyabinsk_region_id = 1 # region_id для России # Поисковые запросы для среднего специального и высшего образования self.search_queries = [ "техникум", "колледж", "университет", "институт", "академия", "профессиональное училище", "высшее учебное заведение", "вуз", "факультет", "филиал университета", "медицинский колледж", "педагогический колледж", "технический колледж", "экономический колледж" ] def search_educational_institutions(self, query: str, limit: int = 50) -> List[Dict]: """Поиск учебных заведений по запросу""" params = { 'q': query, 'location': self.chelyabinsk_location, 'radius': 50000, # радиус поиска 50км от центра города 'region_id': self.chelyabinsk_region_id, 'fields': 'items.name,items.full_name,items.address,items.point,items.contact_groups,items.rubrics,items.context', 'page_size': limit } if self.api_key: params['key'] = self.api_key try: print(f"Поиск: {query}") response = self.session.get(self.base_url, params=params) response.raise_for_status() data = response.json() if 'result' in data and 'items' in data['result']: items = data['result']['items'] print(f"Найдено {len(items)} заведений для запроса '{query}'") return items else: print(f"Нет результатов для запроса '{query}'") return [] except requests.exceptions.RequestException as e: print(f"Ошибка при запросе '{query}': {e}") return [] def filter_educational_institutions(self, items: List[Dict]) -> List[Dict]: """Фильтрация результатов - оставляем только учебные заведения""" educational_rubrics = [ 'university', 'college', 'technical_school', 'higher_education', 'vocational_school' ] filtered_items = [] for item in items: # Проверяем рубрики if 'rubrics' in item: for rubric in item['rubrics']: if any(edu_key in rubric.get('alias', '').lower() for edu_key in educational_rubrics): filtered_items.append(item) break # Дополнительная проверка по названию (только среднее специальное и высшее) name = item.get('name', '').lower() educational_keywords = [ 'техникум', 'колледж', 'университет', 'институт', 'академия', 'вуз', 'факультет', 'филиал', 'профессиональное училище', 'медицинский', 'педагогический', 'технический', 'экономический' ] # Исключаем школы, лицеи, гимназии, детские сады excluded_keywords = [ 'школа', 'лицей', 'гимназия', 'детский сад', 'дошкольн' ] # Проверяем наличие ключевых слов и отсутствие исключаемых has_educational_keyword = any(keyword in name for keyword in educational_keywords) has_excluded_keyword = any(keyword in name for keyword in excluded_keywords) if has_educational_keyword and not has_excluded_keyword: if item not in filtered_items: filtered_items.append(item) return filtered_items def extract_institution_data(self, item: Dict) -> Dict: """Извлечение данных об учебном заведении""" # Получаем координаты point = item.get('point', {}) lat = point.get('lat', 0) lon = point.get('lon', 0) # Получаем адрес address_info = item.get('address', {}) address = address_info.get('name', '') if address_info else '' # Получаем контактную информацию contacts = [] if 'contact_groups' in item: for group in item['contact_groups']: if 'contacts' in group: for contact in group['contacts']: if contact.get('type') == 'phone': contacts.append(contact.get('value', '')) # Получаем рубрики (категории) rubrics = [] if 'rubrics' in item: rubrics = [rubric.get('name', '') for rubric in item['rubrics']] return { 'id': item.get('id', ''), 'name': item.get('name', ''), 'full_name': item.get('full_name', ''), 'address': address, 'latitude': lat, 'longitude': lon, 'phones': contacts, 'categories': rubrics, 'source': '2GIS Places API' } def search_all_educational_institutions(self) -> List[Dict]: """Поиск всех учебных заведений в Челябинске""" all_institutions = [] seen_ids = set() for query in self.search_queries: # Задержка между запросами чтобы не превысить лимиты API time.sleep(0.5) items = self.search_educational_institutions(query) filtered_items = self.filter_educational_institutions(items) for item in filtered_items: institution_data = self.extract_institution_data(item) # Избегаем дубликатов по ID if institution_data['id'] and institution_data['id'] not in seen_ids: seen_ids.add(institution_data['id']) all_institutions.append(institution_data) # Если нет ID, проверяем по названию и адресу elif not institution_data['id']: unique_key = f"{institution_data['name']}_{institution_data['address']}" if unique_key not in seen_ids: seen_ids.add(unique_key) all_institutions.append(institution_data) print(f"\nВсего найдено уникальных учебных заведений: {len(all_institutions)}") return all_institutions def save_to_json(self, institutions: List[Dict], filename: str = "educational_institutions_2gis.json"): """Сохранение данных в JSON файл""" try: with open(filename, 'w', encoding='utf-8') as f: json.dump({ 'city': 'Челябинск', 'source': '2GIS Places API', 'count': len(institutions), 'institutions': institutions }, f, ensure_ascii=False, indent=2) print(f"Данные сохранены в файл: {filename}") except Exception as e: print(f"Ошибка при сохранении файла: {e}") def main(): """Основная функция""" print("Поиск заведений среднего специального и высшего образования в Челябинске") print("Используется 2GIS Places API") print("="*70) # Создаем экземпляр поисковика # API ключ можно получить на https://platform.2gis.com/ # Для тестирования можно попробовать без ключа (есть лимиты) searcher = TwoGISSearcher() # Выполняем поиск institutions = searcher.search_all_educational_institutions() if institutions: # Сохраняем результаты searcher.save_to_json(institutions) # Выводим краткую статистику print("\n" + "="*60) print("СТАТИСТИКА:") print(f"Всего найдено заведений среднего специального и высшего образования: {len(institutions)}") # Группируем по типам categories_count = {} for inst in institutions: for category in inst.get('categories', []): categories_count[category] = categories_count.get(category, 0) + 1 print("\nРаспределение по категориям:") for category, count in sorted(categories_count.items(), key=lambda x: x[1], reverse=True): print(f" {category}: {count}") # Показываем первые 5 найденных заведений print("\nПримеры найденных заведений:") for i, inst in enumerate(institutions[:5], 1): print(f"{i}. {inst['name']}") print(f" Адрес: {inst['address']}") print(f" Координаты: {inst['latitude']}, {inst['longitude']}") if inst['phones']: print(f" Телефон: {', '.join(inst['phones'])}") print() else: print("Учебные заведения не найдены. Возможно, нужен API ключ для полноценного поиска.") print("Получите API ключ на https://platform.2gis.com/") if __name__ == "__main__": main()