249 lines
11 KiB
Python
249 lines
11 KiB
Python
#!/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() |