Не добавляются элементы ключ / значение в словарь
Я написал программу, которая собирает лучшие цены на предметы с двух сайтов и записывает их в .csv файл. Я использовал API этих сайтов, вот и они: backpack.tf и mannco.trade. Получение данных с mannco.trade происходит быстро, а с backpack.tf медленно, поэтому я использую библиотеку threading, а именно классы Thread и Lock. Проблема заключается на стадии записи в глобальный словарь этих самых предметов, из-за многопоточности (мой предположение) он записывает не все предметы из array в общий словарь final_list. Вот как выглядит функция для каждого отдельного потока Thread, где происходит сравнение цены и запись (у меня их четыре):
def write_region(array,
client): # Функция, записывающая лучшие варианты предметов, указанных в списке array
nonlocal counter # Это общий счетчик предметов, он находится вне функции
api = Account(api_key=client['api_key'], client_id=client['client_id'],
client_secret=client['client_secret']) # Объект для получения объявлений предметов
for item_title in array: # Array - массив названий предметов, собранных с mannco.trade
# Получаем массив объявлений на предмет item_title
try:
classfields = \
api.search_classifieds(intent='sell', page_size=1, fold=0, item_name=item_title,
tradable=1,
craftable=1)['sell'] # Объявления на предмет item_title
time.sleep(0.6)
except KeyError:
print('Превышен лимит запросов на сайт backpack.tf! Ждём 30 секунд...')
time.sleep(30)
classfields = \
api.search_classifieds(intent='sell', page_size=1, fold=0, item_name=item_title,
tradable=1,
craftable=1)['sell'] # Объявления на предмет item_title
try:
lock.acquire() # Останавливаем другие потоки
if len(classfields['listings']) != 0: # Если объявления вообще нашлись
classfield = classfields['listings'][0] # Информация о объявлении
item_values = mannco[item_title] # Информация о предмете с mannco.trade
currency = list(classfield['currencies'].keys())[0].lower() # Валюта
currency_value = None # Значение валюты
# Даем знаяение currency_value (METAL_CURRENCE и подобные это значения валют в долларах вне функции)
if currency == 'metal' or currency == 'ref':
currency_value = METAL_CURRENCE
elif currency == 'keys' or currency == 'key':
currency_value = KEY_CURRENCE
elif currency == 'hat' or currency == 'hats':
currency_value = HAT_CURRENCE
if fuzz.ratio(item_title,
classfield['item']['name']) > 50: # Если наши слова похожи более чем на 50%
if (classfield['currencies'][currency] * currency_value) < float(
item_values['price']): # Если на backpack.tf лучше...
# ДОБАВЛЕНИЕ ПРЕДМЕТА В ГЛОБАЛЬНЫЙ ОБЩИЙ СЛОВАРЬ
final_list[classfield['item']['name']] = {
'site': 'backpack.tf',
'usd_price': float(classfield['currencies'][currency]) * currency_value,
'rub_price': float(
classfield['currencies'][currency]) * currency_value * DOLLAR_TO_RUB,
'site_price': str(classfield['currencies'][currency]) + f' {currency}'
}
# ИНКРЕМЕНТИРОВАНИЕ ГЛОБАЛЬНОЙ ПЕРЕМЕННОЙ COUNTER
counter += 1
print(f'{counter} предметов записано из {len(mannco)}')
else: # Если на mannco.trade цена лучше...
final_list[item_title] = {
'site': 'mannco.trade',
'usd_price': item_values['price'],
'rub_price': float(item_values['price']) * DOLLAR_TO_RUB,
'site_price': str(item_values['price']) + ' USD'
}
counter += 1
print(f'{counter} предметов записано из {len(mannco)}')
else: # Если слова не похожи, значит это разные объявления, записываем объявление из mannco.trade
final_list[item_title] = {...}
counter += 1
print(f'{counter} предметов записано из {len(mannco)}')
else: # Если не нашлось ни одного объявления, тогда добавляем предмет с mannco.trade
final_list[item_title] = {...}
counter += 1
print(f'{counter} предметов записано из {len(mannco)}')
finally:
lock.release() # Продолжаем работу остальных потоков...
Вот так выглядит создание потоков, количество которых зависит от количества аккаунтов в config.py. Здесь я разделяю общий массив имен на число потоков, чтобы каждый поток обрабатывал определенную часть этого общего массива имен с mannco.trade. (items_names - общий массив имен):
region_length = len(mannco) // len(config.CLIENTS) # Длинна одного региона имен, взятых из главного массива имен
threads = list()
for index in range(1, len(config.CLIENTS) + 1):
if index == 1:
thread = Thread(target=write_region, args=(items_names[:region_length], config.CLIENTS[index - 1]))
threads.append(thread)
elif index == len(config.CLIENTS):
thread = Thread(target=write_region,
args=(
items_names[region_length * (len(config.CLIENTS) - 1):], config.CLIENTS[index - 1]))
threads.append(thread)
else:
thread = Thread(target=write_region,
args=(items_names[region_length * (index - 1):region_length * index],
config.CLIENTS[index - 1]))
threads.append(thread)
for thread in threads:
thread.start()
for thread in threads:
thread.join()
До того как я решил добавить многопоточность в мою программу все отлично работало, но сейчас программа получает 1800 объектов, а из них записывает лишь 1400 по неизвестной причине! У всех объектов названия разные, я это также проверял. Вот вывод программы:
...
1800 предметов записано из 1801
1801 предметов записано из 1801
1801 - Предметы с mannco.trade
1433 - Записанные предметы
Сравнение прошло успешно!
Дайте имя файлу (Без расширения): 123
Начало записи в файл 123.csv...
Запись завершена!
Успех! Нажмите Enter чтобы закрыть программу...