Files
map_yandex/search_2gis.py
2025-09-23 20:13:51 +05:00

249 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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()