-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun_scraping.py
118 lines (93 loc) · 3.65 KB
/
run_scraping.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import asyncio
import json
import os
import sys
import datetime
from django.contrib.auth import get_user_model
proj = os.path.dirname(os.path.abspath('manage.py'))
sys.path.append(proj)
os.environ["DJANGO_SETTINGS_MODULE"] = 'core.settings'
import django
django.setup()
from scraping.utils.parsers import hh_parser, superjob_parser
from scraping.models import Vacancy, City, Language, Error, Url
# автоматическое получение авторизованного пользователя
User = get_user_model()
# список парсеров
parsers = (
(hh_parser, 'hhru'),
(superjob_parser, 'superjob'),
)
# параметры для парсинга из предпочтений пользователей
def get_settings():
# .values() возвращает список словарей
qs = User.objects.filter(send_email=True).values()
# формирование кортежа ('city_id', 'language_id') из данных о пользователе
settings_lst = set((q['city_id'], q['language_id']) for q in qs)
return settings_lst
def get_urls(_settings):
qs = Url.objects.all().values()
# формирование объекта { ('city_id', 'language_id'): {'hhru': 'url', ... }
url_dct = {(q['city_id'], q['language_id']): q['url_data'] for q in qs}
urls = []
for pair in _settings:
if pair in url_dct:
tmp = {}
tmp['city'] = pair[0]
tmp['language'] = pair[1]
tmp['url_data'] = url_dct[pair]
urls.append(tmp)
return urls
async def main(value):
func, url, city, language = value
job, err = await loop.run_in_executor(None, func, url, city, language)
errors.extend(err)
vacancy.extend(job)
settings = get_settings()
url_list = get_urls(settings)
vacancy = []
errors = []
loop = asyncio.get_event_loop()
tmp_tasks = []
for data in url_list:
city = City.objects.get(id=data['city'])
language = Language.objects.get(id=data['language'])
for func, key in parsers:
tmp_tasks.append((func, data['url_data'][key], [data['city'], str(city)], [data['language'], str(language)]))
tasks = asyncio.wait([loop.create_task(main(f)) for f in tmp_tasks])
loop.run_until_complete(tasks)
loop.close()
# синхронный сбор вакансий
# for data in url_list:
# city = City.objects.get(id=data['city'])
# language = Language.objects.get(id=data['language'])
# for func, key in parsers:
# url = data['url_data'][key]
# v, e = func(url, [data['city'], str(city)], [data['language'], str(language)])
# vacancy += v
# errors += e
for job in vacancy:
try:
print(job)
v = Vacancy(**job)
v.save()
except:
print('Ошибка при записи в БД')
if errors:
try:
# проверка наличия данных за сегодня
qs_errors = Error.objects.filter(timestamp=datetime.date.today())
# если сегодня уже записи об ошибках есть
if qs_errors.exists():
# получаем экземпляр класса (в списке он будет всегда один, т.к. фильтруем по дате)
err = qs_errors.first()
# обновляем объект
err.data.update({'errors': errors})
# сохраняем в БД
err.save()
else:
er = Error(data={'errors': errors}).save()
except:
print('Ошибка при записи в БД')
# with open('vacancies.json', 'w', encoding='utf-8') as file:
# json.dump(vacancy, file, indent=4, ensure_ascii=False)