xaxaxax
This commit is contained in:
249
search_2gis.py
Normal file
249
search_2gis.py
Normal 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()
|
||||
Reference in New Issue
Block a user