Как работать с госзакупками: Госзакупки для чайников | Как участвовать в госзакупках
Как работать с госзакупками и «не сесть»
Автор фото: Ермохин Сергей
Public-talk Делового Петербурга и АНО ДПО «Академия Системного образования».
11:0418 октября 2021
709просмотров
11:0418 октября 2021
Крупнейшее деловое издание Санкт-Петербурга «Деловой Петербург» впервые совместно с Автономной некоммерческой организацией дополнительного профессионального образования «Академия системного образования» провели новый формат мероприятий для бизнес сообщества — публичные дискуссии (public talk) на тему госзакупок.
Представители бизнеса и государства обсудили экономическую эффективность участия бизнеса в закупках. Представители контрольных органов рассказали нам, где заканчивается диалог с властью и начинается сговор. Эксперты поделились опытом на примере реальных историй.
В начале дискуссии председатель комитета по государственному заказу Санкт-Петербурга Александр Жемякин отметил, что для процедуры госзакупок важны доверительные отношения между властными структурами и бизнесом. По его словам, система госзакупок проходит эволюционное развитие и те болезни, которые были присущи госзаказу ещё 5 лет назад, сегодня успешно преодолены. На вопрос модератора Игоря Павловского, что организатору госзакупок важнее — качество или цена, Александр Жемякин ответил, что в идеале и то, и другое. Но он понимает, что к этому идеалу ещё надо стремиться.
В продолжении темы разговора адвокат, партнёр Kulik & Partners Law.Economics Кирилл Дозмаров отметил, что как раз у госзакупок есть вопросы коммерческой составляющей, особенно когда ряд компаний демпингует с конечным ухудшением качества продукта. По его словам, в действующем законодательстве о закупках есть несомненный крен в сторону экономии, а не качества продукции.
По мнению Дмитрия Кудрявцева, адвоката, управляющего партнёра адвокатского бюро CTL, уголовную ответственность за нарушение процедуры госзакупок никто не отменял, и предпринимателям, которые первый раз отправляются на процедуру торгов, надо иметь хорошую юридическую подготовку для того, чтобы банально не сесть в тюрьму по причине незнания законодательной и законоприменительной практики в области госзакупок.
Читайте также:
Бизнес
Для малого и среднего: госзакупки оптимизируют в сторону IT
Андрей Тенишев, к.ю.н., заведующий кафедрой конкурентного права РАНХиГС (г. Москва) отметил, что существует проблема картелизации государственных закупок. В своём выступлении он перечислил новые правила квалификации картелей и о том, какое общение с заказчиком может быть признано сговором.
1 / 19
←→
На фото: Public-talk Делового Петербурга и АНО ДПО «Академия Системного образования»
Автор: Ермохин Сергей
Дискуссию государства и бизнеса продолжила Анна Амантаева — и.о. заместителя начальника управления по надзору за исполнением федерального законодательства прокуратуры Ленинградской области. Она рассказала про типичные нарушения, выявляемые в сфере закупок товаров, работ и услуг. Речь шла о формировании закупочной документации под конкретного поставщика, дробление закупок, а также о том, как прокуратура защищает права субъектов предпринимательской деятельности.
Татьяна Леонтьева, независимый эксперт в сфере госзакупок, уполномоченный на проведение антикоррупционной экспертизы Министерства Юстиции РФ, лектор «Консультант плюс» продолжила обсуждение, осветив тему минимизации рисков поставщиков при исполнении контракта. Она также уточнила, как правильно оформить документы, чтобы не попасть в реестр недобросовестных поставщиков.
Директор по правовым вопросам АНО ДПО «Академия системного образования» Сергей Андросов отметил, что существует большая проблема квалификации современных специалистов в сфере закупок, обусловленная низким уровнем профессионализма специалистов. И в завершении дискуссии Кристина Иващенко, старший преподаватель института развития конкуренции и антимонопольного регулирования СПбГУ, директор АНО ДПО «Академия системного образования», вернувшись к началу дискуссии отметила, что в современных реалиях невозможна оценка эффективности на основании исключительно ценовых критериев, поскольку во многих закупках встаёт вопрос соотношения цены и качества товаров, работ или услуг.
туториал со скрепером / Хабр
Недавно пришлось познакомиться тесно с порталами государственных закупок Казахстана и Узбекистана в рамках Школы Данных. Мы (авторка поста, разработчик скрепера и журналисты) исследовали тему «доступной среды» (удобная инфраструктура для людей с инвалидностью) и столкнулись с необходимиостью написать скрепер, которые бы скачивал данные по ключевым словам.
Итоговый текст по нашей задаче тут.
Вот ссылки на источники, с которыми мы работали:
В Узбекистане публикуются тендеры (и другие формы) и корпоративных заказчиков, и бюджетных заказчиков. Эту информацию можно прочитать в левом верхнем угле страниц.
В ходе работы над темой мы узнали, что есть несколько видов государственных закупок — лоты, объявления, тендеры, конкурсы, прямые закупки Поэтому если будете что-то искать среди закупок — будьте бдительны. Проверьте все виды закупок. Если информации нет в одной категории (лоты), то она может быть в другой (в тендерах).
Перед работой стоит наверняка ознакомиться с законодательством и понять, что и где должно быть. В каждом из этих своих видов свои правила, и наши предметы мы находили только в конкретных категориях. Эта проблемы вылезла боком после того, как мы начали искать и скачивать данные для Узбекистана. Пандусов в “тендерах” не оказалось, их можно было найти в “конкурсах”. К счастью, структура страниц оказалась одинаковой и изменения (в уже написанный скрепер) много времени не заняли.
Код на гитхабе подойдет для поиска любых других госзакупок. Просто сделайте замену ключевых слов. Количетсво тем, с которыми можно работать, необъятное и ограничивается только фантазией. Можно скачать все тендеры, где упоминались закупки по COVID, можно анализировать ремонт дорог, строительство и прочее.
Техническая часть мануала. Разбор кода
Код на Github.
Скрепер для госзакупок Узбекистана и Казахстана
В ходе разработки программы возникло несколько проблем:
У сайта госзакупок Казахстана существует публичное API, но для его использования нужно получить токен у распорядителя реестра. Для этого, нужно было отправить письмо с указанием цели получения доступа. Мы этого не делали. К счастью, у сайта существует внутреннее API в формате GET-запроса с параметрами. Подставляя необходимые параметры, можно эмулировать поиск по ключевому слову и дальше скрепить результаты.
У сайта госзакупок Казахстана оказалась достаточно сложная для скрепинга структура. Так, например, оказалось, что структура страниц отличается в случаях когда лот состоит из одной части и из нескольких. Кроме того, полная информация о лоте показывалась с помощью Javascript при нажатии на лот, что делало эту информацию невозможной к получению при использовании классического подхода скрепинга статических страниц.
У сайта госзакупок Узбекистана публичное API отсутствовало. Но был поиск, работающий по такому же принципу, как и у Казахстана. Однако, в отличии от Казахстана, поиск по ключевым словам не работал. Поэтому здесь пришлось искать все тендеры за максимально разрешённый 90-дневный период, а уже затем отдельно искать среди них искомые запросы.
Скреперы написаны в формате утилит командной строки. Для их использования не требуется знания языков программирования. Код и подробная инструкция по запуска есть в репозитории на Github. Всё, что необходимо — интерпретатор Python версии не ниже 3.6 с установленными модулями из файла requirements.txt. Рекомендуется использовать виртуальное окружение Python во избежания конфликта зависимостей. Установка интерпретатора и модулей может отличаться в зависимости от используемой операционной системы. На Linux это:
python3 -m venv venv source venv/bin/activate pip3 install -r requirements.txt
Установив все необходимое, запускаем скрепер. Для Узбекистана это будет выглядеть так:
python3 uzbekistan_scraper.py tender 01.01.2021 31.01.2021
где tender — раздел, по которому ищем. Ещё можем искать по конкурсам – тогда вместо tender пишем competitive. Две даты в формате dd.mm.YYYY – это начало и конец промежутка поиска. Он может быть не больше 90 дней. Если нужно искать в промежутке больше, разделите его на несколько по 90 дней. Кроме того, есть ограничение в 5000 результатов поиска на запрос.
Результатом работы скрепера будет три сущности:
• purchase_type_date.csv — сводная таблица с общей информацией о закупках. Включает в себя поля номера лота, названия, стоимости лота, региона проведения закупки;
• purchase_typedetaileddate.csv — сводная таблица с подробной информацией по каждой закупке;
• отдельные каталоги для каждой закупки с таблицей с детальной информацией и архивом с тендерными документами.
Для Казахстана запуск будет выглядеть так:
python3 kazakhstan_scraper.py "доступная среда"
Если поисковый запрос состоит из нескольких слов, возьмите их в кавычки. Поиск будет происходить по словосочетанию. Количество результатов поиска здесь имеет ограничение в 2000 единиц.
Результатом работы скрепера будут три сущности:
• tenders_query.csv — сводная таблица с основной информацией по искомым тендерам. Включает в себя поля наименований объявления, лота, количество и сумму, способ закупки, её статус;
• tenders_detailed_query. csv — сводная таблица с детальной информацией по искомым тендерам. Кроме основной информации включает в себя дополнительную характеристику лота, заказчика, цену за единицу и другое;
• отдельные каталоги, в каждом из которых находится таблица с информацией по объявлению, аналогичной той, что в сводной таблице.
В файле requirements.txt находится список модулей, необходимых для установки пакетным менеджером pip. Если установка модуля вызывает ошибку, попробуйте удалить версию модуля, скачав таким образом, самую последнюю. Файл log.txt перезаписывается при запуске программы — в него записывается прогресс выполнения. README.md – это документация, аналогичная той, что выше.
Основные переменные находятся в файлах settings.py. Это CSS-селекторы, используемые модулем BeautifulSoup для парсинга HTML-страниц, регулярные выражения для парсинга текста и названия полей в будущих сводных таблицах. Если скрепер перестанет выдавать содержимое той или иной колонки, в первую очередь стоит смотреть именно на используемый селектор. По большому счёту, мелкие изменения редизайна сайта могут быть решены только за счёт исправлений в файле настроек.
Перейдём к непосредственной логике программы, файл kazakhstan_scraper.py. Чтение кода стоит начать с последних двух строк:
if __name__ == '__main__': main()
значит, что при запуске скрипта как программы, будет вызвана функция main.
def main(): # объявляем функцию urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) #отключаем показ ошибки о проверку сертификатов сайта. Просто чтобы не раздражало. logging.basicConfig(level=logging.INFO, format='%(levelname)s:%(message)s', filename='log.txt', filemode='w') #включаем логгирование в сответствующий файл с перезаписью if len(sys.argv) != 2: raise ValueError('Usage: python3 kazakhstan_tenders.py [search_word]. If your search query consists of two and more words, take them into quotes.')
Так как программа задумана как консольная утилита, добавляем базову проверку — если число аргументов включая название программы не равно 2, прерываем выполнение с показом справки по запуску.
search_word = sys.argv[1] #присваем переменной значения введённого посикового запроса start_time = time() #активируем таймер чтобы знать, сколько времени заняло выполнение print('Start downloading') #выводим сообщение о начале работы logging.info('Start downloading') #пишем его в лог url_list = get_general_table(search_word) #запускаем первую функцию для получения общей таблицы, её результат записываем tenders_info = get_detailed_table(url_list)# запускаем вторую функцию для получения подробных таблиц, её результат записываем get_csv_with_tenders_info(tenders_info, search_word)# формируем и сохраняем финальную сводную таблицу end_time = time() #останавливаем таймер print(f'Download for {search_word} completed in {end_time - start_time:.2f} seconds.') #выводим сообщение об успешно завершённой загрузке за время logging.info(f'Download for {search_word} completed in {end_time - start_time:.2f} seconds.') #дублируем эту запись в файл
перейдём теперь к отдельным функциям, но сначала импорты:
import logging #модуль логирования import os #модуль работы с системой import pandas #модуль для работы с данными и таблицами import requests #модуль работы с веб-страницами import sys #модуль для работы с аргументами командной строки import urllib3 #нужен только для отключения записи об ошибке сертификата from bs4 import BeautifulSoup #главный модуль для парсинга веб-страниц from collections import OrderedDict #сортированный словарь, который мы используем для создания двумерного массива.Обычный словарь в Python расставит колонки в случайном порядке, нам это не подходит. from datetime import datetime #модуль работы с датой from time import time #модуль таймера from kazakhstan_settings import * #загружаем все переменные из файла настроек def get_general_table(search_word): #объявляем функцию start_time = time() #таймер kazakhstan_entrypoint = f'{ENTRY_POINT}/ru/search/lots?filter%5Bname5D={search_word}&count_record=2000&search' \ f'=&filter%5Bnumber%5D' \ f'=&filter%5Bnumber_anno%5D=&filter%5Benstru%5D=&filter%5Bcustomer%5D=&filter' \ f'%5Bamount_from%5D=&filter%5Bamount_to%5D=&filter%5Btrade_type%5D=&filter%5Bmonth%5D' \ f'=&filter%5Bplan_number%5D=&filter%5Bend_date_from%5D=&filter%5Bend_date_to%5D=&filter' \ f'%5Bstart_date_to%5D=&filter%5Byear%5D=&filter%5Bitogi_date_from%5D=&filter' \ f'%5Bitogi_date_to%5D=&filter%5Bstart_date_from%5D=&filter%5Bmore%5D=' #формируем адрес поискового запроса, который мы будем совершать, подставляя в словосочетание, которое мы ищем. Ещё может быть интересен параметр count_record — количество получаемых результатов. 2000 должно хватить в большинстве случаев. response = requests.get(kazakhstan_entrypoint, headers=HEADERS, verify=False) #получаем HTML-страницу, подставляя заголовки, чтобы выглядеть как реальный человек и игнорировать проверку сертификата. Казахстанская цензура требует всех устанавливать государственные сертфикаты, блокируемые разработчиками браузеров. soup = BeautifulSoup(response.content, 'html.parser') #парсим полученную страницу urls_list = [f"{ENTRY_POINT}{url['href']}?tab=lots" for url in soup.select(SELECT_GENERAL_URLS)] #получаем список всех ссылок на лоты general_table = list() #создаём список для будущей общей таблицы general_table_dict = OrderedDict() #создаём сортированный словарь для будущей общей таблицы general_table_dict[LOT_ID] = [soup.select(SELECT_LOT_ID)[idx].get_text().strip() for idx, _ in enumerate(soup.select(SELECT_LOT_ID))] #создаём колонку с название из переменной LOT_ID и содержимым в виде списка значений содержимого селектора.
Тут и дальше стоит отметить, что мы получаем список, а для прохода по списку используем функцию enumerate. Она подходит лучше обычного for в ситуациях, когда нам нужно получать и индекс итерируемого объекта и его значение. general_table_dict[ANNOUNCE_NAME] = [soup.select(SELECT_ANNOUNCE_NAME)[idx].get_text().strip() for idx, _ in enumerate(soup.select(SELECT_ANNOUNCE_NAME))] #создаём колонку с название из переменной ANNOUNCE_NAME и содержимым в виде списка значений содержимого селектора general_table_dict[LOT_CUSTOMER] = [idx.next_sibling.strip() for idx in soup.find_all(SELECT_LOT_CUSTOMER, text=SELECT_LOT_CUSTOMER_SIBLING)] #в отличии от других колонок, здесь мы не можем получить необходимый текст только селектором, поэтому мы ищем соседний текст, а уже затем получаем соседний ему и нужный нам general_table_dict[LOT_NAME] = [soup.select(SELECT_LOT_NAME)[idx].get_text().strip() for idx, _ in enumerate(soup.select(SELECT_LOT_NAME))] general_table_dict[LOT_NUMBER] = [soup.select(SELECT_LOT_NUMBER)[idx]. get_text().strip() for idx, _ in enumerate(soup.select(SELECT_LOT_NUMBER))] general_table_dict[LOT_PRICE] = [soup.select(SELECT_LOT_PRICE)[idx].get_text().strip().replace(' ', '') for idx, _ in enumerate(soup.select(SELECT_LOT_PRICE))] #здесь, вдобавок к обычным действиям, производим автозамену запятой на ничего general_table_dict[LOT_PURCHASE_METHOD] = [soup.select(SELECT_LOT_PURCHASE_METHOD)[idx].get_text().strip() for idx, _ in enumerate(soup.select(SELECT_LOT_PURCHASE_METHOD))] general_table_dict[LOT_STATUS] = [soup.select(SELECT_LOT_STATUS)[idx].get_text().strip() for idx, _ in enumerate(soup.select(SELECT_LOT_STATUS))] record_general_table(general_table_dict, search_word) #вызываем функцию для сохранения общей таблицы general_table.append(pandas.DataFrame(general_table_dict)) #превращаем наш словарь в объект DataFrame и добавляем его в список общей таблицы. Тем самым мы дописываем в неё ещё одну строку со всеми колонками. end_time = time() #останавливаем таймер print(f'Urls from general table for {search_word} and the table have been downloaded in {end_time - start_time:.
2f} seconds.') # сообщаем о завершенной работе logging.info(f'Urls from general table for {search_word} and the table have been downloaded in {end_time - start_time:.2f} seconds.') #и записываем это в файл return urls_list# возвращаем список с ссылками на страницы с объявлениями def record_general_table(general_table_dict, search_word): #передаём функции упорядоченный словарь и поисковое словосочетание if not os.path.exists(PATH_TO_LOCATION): os.makedirs(PATH_TO_LOCATION) #проверяем, существует ли каталог kazakgstan/, если нет, создаём его pandas.DataFrame(general_table_dict).to_csv(PATH_TO_LOCATION + f'tenders_{search_word}.csv') #записываем в него общую таблицу def get_detailed_table(urls_list): #передаём функции список с загружёнными ссылками на объявления detailed_table = list() #создаём список, будущую сводную таблицу for url in urls_list: #будем обходить этот список по ссылке за раз try: # здесь мы делаем всё по тому же алгоритму, что и в функции выше start_time = time() старт таймера response = requests. get(url, headers=HEADERS, verify=False) soup = BeautifulSoup(response.content, 'html.parser') detailed_table_dict = OrderedDict() detailed_table_dict[ANNOUNCE_ID] = soup.find_all(SELECT_ANNOUNCE_HEADER)[0]['value'] detailed_table_dict[ANNOUNCE_NAME] = soup.find_all(SELECT_ANNOUNCE_HEADER)[1]['value'] detailed_table_dict[ANNOUNCE_STATUS] = soup.find_all(SELECT_ANNOUNCE_HEADER)[2]['value'] detailed_table_dict[ANNOUNCE_PUBLICATION_DATE] = soup.find_all(SELECT_ANNOUNCE_HEADER)[3]['value'] detailed_table_dict[ANNOUNCE_START_DATE] = soup.find_all(SELECT_ANNOUNCE_HEADER)[4]['value'] detailed_table_dict[ANNOUNCE_END_DATE] = soup.find_all(SELECT_ANNOUNCE_HEADER)[5]['value'] try: #внешний вид страницы может отличаться в зависимости от количества лотов в объявлении. Мы обрабатываем этот случай, делая поиск не по соседнему тексту, а используя селектор. detailed_table_dict[LOT_ID] = soup.find(SELECT_LOT_HEADER, text=SELECT_LOT_ID_DETAILED_SIBLING).
next_sibling.strip() detailed_table_dict[LOT_NAME] = soup.find(SELECT_LOT_HEADER, text=SELECT_LOT_NAME_DETAILED_SIBLING).next_sibling.strip() detailed_table_dict[LOT_DESCRIPTION] = soup.find(SELECT_LOT_HEADER, text=SELECT_LOT_DESCRIPTION_SIBLING).next_sibling.strip() detailed_table_dict[LOT_DESCRIPTION_DETAILED] = soup.find(SELECT_LOT_HEADER, text=SELECT_LOT_DESCRIPTION_DETAILED_SIBLING).next_sibling.strip() except AttributeError: detailed_table_dict[LOT_ID] = [soup.select(SELECT_LOT_ID_DETAILED)[idx].get_text().strip() for idx, _ in enumerate(soup.select(SELECT_LOT_ID_DETAILED))] detailed_table_dict[LOT_NAME] = [soup.select(SELECT_LOT_NAME_DETAILED)[idx].
get_text().strip() for idx, _ in enumerate(soup.select(SELECT_LOT_NAME_DETAILED))] detailed_table_dict[LOT_DESCRIPTION] = '' detailed_table_dict[LOT_DESCRIPTION_DETAILED] = '' detailed_table_dict[LOT_CUSTOMER_NAME] = [soup.select(SELECT_LOT_CUSTOMER_NAME)[idx].get_text().strip() for idx, _ in enumerate(soup.select(SELECT_LOT_CUSTOMER_NAME))] detailed_table_dict[LOT_CHARACTERISTICS_FULL] = [ soup.select(SELECT_LOT_CHARACTERISTICS_FULL)[idx].get_text().strip() for idx, _ in enumerate(soup.select(SELECT_LOT_CHARACTERISTICS_FULL))] detailed_table_dict[LOT_PRICE_PER_ONE] = [ soup.select(SELECT_LOT_PRICE_PER_ONE)[idx].get_text().strip().replace(' ', '') for idx, _ in enumerate(soup.
select(SELECT_LOT_PRICE_PER_ONE))] detailed_table_dict[LOT_NUMBER] = [soup.select(SELECT_LOT_NUMBER_DETAILED)[idx].get_text().strip() for idx, _ in enumerate(soup.select(SELECT_LOT_NUMBER_DETAILED))] detailed_table_dict[LOT_MEASUREMENT] = [soup.select(SELECT_LOT_MEASUREMENT)[idx].get_text().strip() for idx, _ in enumerate(soup.select(SELECT_LOT_MEASUREMENT))] detailed_table_dict[LOT_PLANNED_TOTAL] = [ soup.select(SELECT_LOT_PLANNED_TOTAL)[idx].get_text().strip().replace(' ', '') for idx, _ in enumerate(soup.select(SELECT_LOT_PLANNED_TOTAL))] detailed_table_dict[LOT_TOTAL_1_YEAR] = [soup.select(SELECT_LOT_TOTAL_1_YEAR)[idx].get_text().strip() for idx, _ in enumerate(soup.
select(SELECT_LOT_TOTAL_1_YEAR))] detailed_table_dict[LOT_TOTAL_2_YEAR] = [soup.select(SELECT_LOT_TOTAL_2_YEAR)[idx].get_text().strip() for idx, _ in enumerate(soup.select(SELECT_LOT_TOTAL_2_YEAR))] detailed_table_dict[LOT_TOTAL_3_YEAR] = [soup.select(SELECT_LOT_TOTAL_3_YEAR)[idx].get_text().strip() for idx, _ in enumerate(soup.select(SELECT_LOT_TOTAL_3_YEAR))] detailed_table_dict[LOT_STATUS] = [soup.select(SELECT_LOT_STATUS_DETAILED)[idx].get_text().strip() for idx, _ in enumerate(soup.select(SELECT_LOT_STATUS_DETAILED))] record_detailed_table(detailed_table_dict, detailed_table_dict[ANNOUNCE_ID]) #записываем подробную таблицу для каждого объявления detailed_table.
append(pandas.DataFrame(detailed_table_dict)) #превращаем наш словарь в объект DataFrame и добавляем его в список общей таблицы. Тем самым мы дописываем в неё ещё одну строку со всеми колонками. end_time = time() # конец таймера print(f'Lot {detailed_table_dict[ANNOUNCE_ID]} info has been downloaded in {end_time - start_time:.2f} seconds.')# выводим за сколько секунд была загружена информация об объявлении logging.info( f'Lot {detailed_table_dict[ANNOUNCE_ID]} info has been downloaded in {end_time - start_time:.2f} seconds.') # дублируем её в файл except IndexError: обрабатываем ошибку когда ссылка на объявление есть, а такой страницы нету print('Page is not found. Probably, it wad deleted.') #выводим сообщение об ошибке logging.error('Page is not found. Probably, it was deleted.') #пишем в лог continue #переходим к следующей ссылке return detailed_table
В скрепере для Узбекистана логика работы такая же, за исключением нескольких моментов:
def main(): if len(sys.argv) != 4:# здесь мы проверяем наличие уже четырёх аргументов raise ValueError('Usage: python3 uzbekistan_scraper.py [tender|competitive] [start_date] [end_date]') purchase_type = verify_purchase_type(sys.argv[1]) #для Узбекистана мы можем искать по конкурсам или по тендерам. Здесь мы проверяем, какой вариант был задан. start_date = sys.argv[2] #присваеваем первую временную границу end_date = sys.argv[3]# присваиваем вторую временную границу verify_date(start_date, end_date) #проверяем, что промежуток между первой и второй датами не превышает 90 дней def verify_purchase_type(purchase_type): if purchase_type == 'tender': #если при запуске ввели это значение, то purchase_type = 'tender2' #подставляем в будущий запрос это elif purchase_type == 'competitive':# если такое, то это pass else:# иначе выдаём ошибку logging.error('Purchase type can be only tender or competitive.') raise ValueError('Purchase type can be only tender or competitive.') return purchase_type def verify_date(start_date, end_date): start_date = datetime.
strptime(start_date, '%d.%m.%Y') #превращаем строку с датой в специальный формат end_date = datetime.strptime(end_date, '%d.%m.%Y') if abs((end_date - start_date).days) > 90: #сравниваем их и выдаём ошибку, если промежуток составляет больше 90 дней logging.error("Difference between dates shouldn't be more than 90 days.") raise ValueError("Difference between dates shouldn't be more than 90 days.")
Дальше отличия заключаются только в названиях полей и селекторах, за исключением сохранения архива с тендерной документацией.
def record_detailed_table(detailed_table_dict, lot_id, lot_documents_url): lot_location = f'{PATH_TO_LOCATION}/{lot_id}/' if not os.path.exists(lot_location): os.makedirs(lot_location) pandas.DataFrame(detailed_table_dict).to_csv(lot_location + lot_id + '.csv') response = requests.get(lot_documents_url, headers=HEADERS, verify=False) #кроме того, что мы сохраняем таблицу, мы ещё сохраняем архив с документацией try: with open(f"{lot_location}{lot_id}.{lot_documents_url.split('.')[-1]}", 'wb') as f: #название архива на сайте было сгенерировано автоматически, мы переназываем его соответственно к номеру закупки f.write(response.content) except FileNotFoundError:# если архива на странице нету, выдаём об этом предупреждение и продолжаем logging.error("Archive with purchase documentation hasn't been found on the page.") return uzbekistan_entrypoint = f'{ENTRY_POINT}/ru/ajax/filter?LotID=&PriceMin=&PriceMax=&RegionID=&TypeID=&DistrictID=&INN=&CategoryID=&EndDate={end_date}&PageSize=5000&Src=AllMarkets&PageIndex=1&Type={purchase_type}&Tnved=&StartDate={start_date}' поисковый запрос тоже, конечно, будет другим. Здесь мы подставляем две даты, тип раздела, по которому ищем. Интерес может представлять параметр PageSize. На сайте максимальное количество результатов 2000, в запросе можно подставить любое число. 5000 должно быть достаточно, учитывая временное ограничение в 90 дней.
Чем больше результатов, тем больше времени нужно на обработку запроса, учитываю загрузку тяжёлых документов. Кроме того, архивы с документами могут занимать много места на диске.
Если какой-то функционал не работает или нужно добавить что-то новое, пишите в Issues проекта на Github.
Почему государственные закупки? – Jobs to Move America
Соединенные Штаты балансируют на краю обрыва.
Системный расизм веками не сдерживался. Разрыв в уровне благосостояния увеличивается, а цветные сообщества как никогда хронически испытывают нехватку ресурсов. Кризис климата в первую очередь ударяет по многим из этих же сообществ. Такие кризисы, как Великая рецессия и пандемия коронавируса, показали, что наша экономика просто не приспособлена для работы на рабочих, даже когда корпорации и руководители становятся богаче.
Чтобы решить эти проблемы с блокировкой, нам нужно сначала понять, как мы сюда попали. И эрозия движения промышленных рабочих — одна из важнейших, но часто упускаемая из виду часть истории.
Как мы сюда попали?
За последние полвека фабрики, которые были основой нового среднего класса в послевоенный период, начали закрываться и переезжать в низкооплачиваемые районы, оставляя за собой безработицу и нищету. К 1990-м годам производственные цепочки поставок в США стали настолько глобальными, что эксперты по всему миру провозгласили силу американских промышленных рабочих «умирающей» или «мертвой».
По мере того, как рабочие места на производстве становились все более ненадежными и низкооплачиваемыми, иммигранты и чернокожие рабочие из Миссисипи в Калифорнию начали объединяться, чтобы иметь право голоса на рабочем месте, но столкнулись с репрессиями и угрозами, что фабрики закроются и переедут в другое место. В результате заработная плата и условия труда в производственном секторе США резко упали. Когда-то являвшийся источником стабильной семейной карьеры с низкими образовательными барьерами для входа, производственный сектор США стал крупнейшим пользователем временной рабочей силы в стране: 36% всех временных работников заняты на производстве и в промышленности без какой-либо защиты на рабочем месте. .
Какое отношение восстановление власти промышленных рабочих имеет к построению справедливой экономики и более здоровых сообществ?
Много.
Прямо сейчас примерно 20% всех промышленных товаров в США закупаются нашими правительствами и государственными учреждениями. Каждый год федеральные, государственные и местные органы власти тратят почти 2 триллиона долларов из наших государственных долларов на покупку промышленного оборудования — всего, от школьных автобусов до поездов и мусоровозов. Это государственные закупки, и они подпитывают огромную часть нашей экономики.
Несмотря на то, что наши государственные доллары питают большую часть производственного сектора за счет государственных закупок и субсидий, в государственных контрактах обычно нет ничего, что могло бы привлечь компании — многие из которых являются мировыми производителями — к ответственности за создание хороших рабочих мест или осуществление долгосрочных инвестиций. в наших сообществах. За прошедшие годы строгие новые законы сделали практически невозможным использование местными органами власти своей покупательной способности для повышения трудовых стандартов или создания рабочих мест на дорогах.
Так быть не должно.
Слишком долго люди страдали от низкой заработной платы и несправедливого обращения, работая на производителей и корпорации, которые получают большую прибыль, тратя деньги общества. Пришло время переосмыслить статус-кво в отношении государственных закупок.
Представьте себе, если бы каждый из государственных долларов, которые идут на финансирование этих субсидий и контрактов с производителями, способствовал созданию хороших рабочих мест и восстановлению силы промышленных рабочих. Представьте, если бы наши государственные доллары также боролись с расовой и социально-экономической несправедливостью, противостояли изменению климата и укрепляли сообщества.
Это видение — то, что заставляет нас двигаться вперед в Jobs to Move America. Вот как это выглядело бы, если бы наши общественные блага были наибольшим общественным благом.
Наша политика «общественные блага для наибольшего общественного блага» позволяет городам, штатам и государственным учреждениям использовать наши государственные средства для создания хороших рабочих мест и продвижения расовой, гендерной и климатической справедливости по всей стране. На местах наши общественные и рабочие коалиции организуются для того, чтобы громче выражать свое мнение в цехах.
Исследования показывают, что 2 триллиона долларов, которые мы ежегодно тратим на государственные закупки, могли бы создать до 20 миллионов хороших рабочих мест, если бы города и штаты приняли нашу модель «общественных благ для самого общественного блага».
Мы создали инструменты политики, которые гарантируют, что сообщества и работники получат реальную выгоду от миллиардов государственных долларов, которые мы инвестируем в инфраструктуру. Мы сыграли ключевую роль в том, чтобы заставить железнодорожные и автобусные компании строить заводы и создавать тысячи хороших семейных рабочих мест в Калифорнии, Иллинойсе и Массачусетсе. Мы работаем с группами климатической справедливости, чтобы убедиться, что наш переход на чистую энергию создает хорошие рабочие места для рабочих и маргинализированных сообществ. Мы продвигаем новую парадигму федеральной инфраструктурной политики.
Чтобы решить самые большие проблемы нашего времени, нам необходимо создать справедливую экономику с хорошими рабочими местами и более здоровыми сообществами для всех. Достижение этого означает восстановление власти рабочих и сообщества.
Узнайте больше о работе, которую мы делаем, чтобы это произошло.
Государственные закупки
Государственные закупки — это процесс, посредством которого органы государственной власти, такие как правительственные ведомства или местные органы власти, закупают работы, товары или услуги у компаний.
Чтобы создать равные условия для предприятий по всей Европе, законодательство ЕС устанавливает минимальные гармонизированные правила государственных закупок. Эти правила регулируют порядок закупки товаров, работ и услуг государственными органами и некоторыми операторами коммунальных служб. Они перенесены в национальное законодательство и применяются к тендерам, денежная стоимость которых превышает определенную сумму. Для тендеров меньшей стоимости применяются национальные правила. Тем не менее, эти национальные правила также должны соблюдать общие принципы права ЕС.
На этом веб-сайте представлена информация о европейской политике государственных закупок. Общие сведения о государственных закупках доступны на сайте Your Europe. Если вы ищете возможности для бизнеса в какой-либо стране ЕС, посетите Tenders Electronic Daily. Для получения информации о грантах и закупках, осуществляемых учреждениями ЕС, посетите портал финансирования и тендеров.
Почему государственные закупки важны
Ежегодно более 250 000 органов государственной власти в ЕС тратят около 14% ВВП (около 2 триллионов евро в год) на закупку услуг, работ и материалов. Во многих секторах, таких как энергетика, транспорт, управление отходами, социальная защита и предоставление услуг здравоохранения или образования, государственные органы являются основными покупателями.
Государственный сектор может использовать закупки для увеличения рабочих мест, роста и инвестиций, а также для создания экономики, которая будет более инновационной, ресурсо- и энергоэффективной и социально инклюзивной.