This commit is contained in:
2025-09-23 20:13:51 +05:00
commit 234525435d
21 changed files with 25832 additions and 0 deletions

249
search_2gis.py Normal file
View File

@@ -0,0 +1,249 @@
#!/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()