Уведомления

Группа в Telegram: @pythonsu

#1 Май 11, 2016 14:54:44

keereel
Зарегистрирован: 2016-05-11
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

API Discogs: год релиза трека - Python

Здравствуйте.
Я новичок в Python (да и в программировании). Решил изучать, что бы можно было применять для своих задач по работе. Уже прогонял свой список через API last.fm и некоторых других сервисов. Вот конкретная задача, с которой мне нужна помощь. Для добычи нужных данных в данном случае служить сервис Discogs и его API. Использую библиотеку discogs_client.
Итак, есть список треков (Artist \t Title), порядка 9000 строк. Задача - добыть данные об этих треках, конкретно в данном случае - самый ранний год выпуска трека. Все данные о треке сохраняются в словарь item. Первым делом выполняю поиск в Discogs по артисту и названию трека:

searchresults = d.search(artist=item['artist'], track=item['title'], type='master')
получаю объект, в котором элементами являются все релизы, содержащие искомый трек. Что бы найти самый ранний год:
        item['year'] = 10000
        for x in range(len(searchresults)):
            if searchresults[x].main_release.year <> 0 and item['year'] > searchresults[x].main_release.year: item['year'] = searchresults[x].main_release.year
        print item['year']
Задача, в принципе, выполняется. Но загвоздка в том, что этот процесс занимает неимоверно много времени. Насколько я понимаю, каждый цикл делает свой запрос к API Discogs (судя по времени выполнения). Можно ли как-то оптимизировать процесс, потому что 9000 треков таким образом обработать нереально.

Офлайн

#2 Май 12, 2016 00:36:15

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

API Discogs: год релиза трека - Python

Надо проверить где делаются запросы (приведите что дает type(searchresult))
Может поможет searchresult=list(searchresult) Чтобы данные загрузились а не вытаскивались запросами.



Офлайн

#3 Май 12, 2016 01:34:37

keereel
Зарегистрирован: 2016-05-11
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

API Discogs: год релиза трека - Python

Вывод type(searchresults):
<class ‘discogs_client.models.MixedPaginatedList’>

Офлайн

#4 Май 12, 2016 01:37:38

keereel
Зарегистрирован: 2016-05-11
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

API Discogs: год релиза трека - Python

Вот почти весь код (убрал всякие нерабочие куски):

import os
import io
import re
import time
import discogs_client
import json
import sys
 
d = discogs_client.Client('client', user_token="token")
 
fileinput = "input.txt"
fileresult = time.strftime('%Y%m%d%H%M%S')+'.txt'
 
if os.path.isfile(fileinput)==False: # if there is no file
    print('Can_t find '+fileinput) # shows message
    sys.exit(1) # and exit
 
i=0
 
print 'Making file for output: '+fileresult
f=io.open(fileresult, 'w', encoding='utf8') # making file for results
f.close() # closing the file
for line in open(fileinput): # for every row in input file
    item={} # making new item
    i=i+1 # number of item
    line = line.split('\t') # splitting input line
    item['artistoriginal'] = line[0] 
    item['titleoriginal'] = line[1]
    item['filename'] = line[2][:-1]
    print(str(i)+'. '+item['artistoriginal']+' - '+item['titleoriginal'].rstrip()) # printing number artist title
    if item['artistoriginal'].lower() == 'AC/DC'.lower(): # for ac/dc
        item['artist'] = 'AC/DC'
    else:
        item['artist'] = item['artistoriginal'].replace('/',' and ') # replacing / with 'and'
    item['artist'] = re.sub(r'(.*), The',r'The \1', item['artist']) # changing 'Beatles, The' format to 'The Beatles'
    item['title'] = item['titleoriginal'].replace('/',' ') # removing '/' from title
    item['title'] = re.sub(r'(.*)\(by .*\)',r'\1', item['title']) # some special conversion
 
    try:
        searchresults = d.search(artist=item['artist'], track=item['title'], type='master') # searching any master release
        item['year'] = 10000 # 
        for x in range(len(searchresults)):
            if searchresults[x].main_release.year <> 0 and item['year'] > searchresults[x].main_release.year: item['year'] = searchresults[x].main_release.year # finding the minimal year
            print item['year']
 
    except IndexError:
        print 'NO INFO'
        item['year'] = 'No info'
 
    except KeyboardInterrupt:
        print '--- interrupted by the user ---'
        sys.exit()
 
    string = ''
 
    for key in sorted(item):
        string = str(item[key]) + '\t' + string
    f=io.open(fileresult, 'a', encoding='utf8')
    f.write(string+u'\n')
    f.close()
А во вложении - пример файла с исходными данными.

Прикреплённый файлы:
attachment input.txt (189 байт)

Офлайн

#5 Май 12, 2016 02:22:23

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

API Discogs: год релиза трека - Python

keereel
Можно ли как-то оптимизировать процесс, потому что 9000 треков таким образом обработать нереально.
Надо проверить, действительно ли запрос для одного трека занимает много времени. Для этого создай отдельный модуль на питоне и там проверь без всяких чтений и записей файлов.



Офлайн

#6 Май 12, 2016 11:36:41

keereel
Зарегистрирован: 2016-05-11
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

API Discogs: год релиза трека - Python

Что такое “модуль”?

Попробовал всё что было, но без чтения/записи файлов:

i=0
item={}
i=i+1
item['artistoriginal'] = 'Nirvana'
item['titleoriginal'] = 'About A Girl'
item['filename'] = '776dbe40-37d4-46db-a809-3d16dee0764f'
print(str(i)+'. '+item['artistoriginal']+' - '+item['titleoriginal'].rstrip())
if item['artistoriginal'].lower() == 'AC/DC'.lower():
    item['artist'] = 'AC/DC'
else:
    item['artist'] = item['artistoriginal'].replace('/',' and ')
item['artist'] = re.sub(r'(.*), The',r'The \1', item['artist'])
item['title'] = item['titleoriginal'].replace('/',' ')
item['title'] = re.sub(r'(.*)\(by .*\)',r'\1', item['title'])
try:
    searchresults = d.search(artist=item['artist'], track=item['title'], type='master')
    searchresults=list(searchresults)
    
    print 'searchresults: '
    print type(searchresults[0])
    item['year'] = 'No Info'
    for x in range(len(searchresults)):
        try:
            relyear = searchresults[x].main_release.year
            if relyear <> 0 and item['year'] > relyear: item['year'] = relyear
        except:
            pass
        print item['year']
except (IndexError, ValueError):
    print 'NO INFO'
    item['year'] = 'No info'
except KeyboardInterrupt:
    print '--- interrupted by the user ---'
    sys.exit()
string = ''
for key in sorted(item):
    string = str(item[key]) + '\t' + string
    #print key + ' => ' + str(item[key])
f=io.open(fileresult, 'a', encoding='utf8')
f.write(string+u'\n')
f.close()
mykey = ''
for key in sorted(item):
    mykey = key  + '\t' + mykey
f=open(fileresult, 'a')
f.write(mykey+'\n')
f.close()
Результат тот же. Судя про времени перебора значений года каждый проход цикла к API отправляется запрос.

Офлайн

#7 Май 12, 2016 12:12:56

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

API Discogs: год релиза трека - Python

keereel
Что такое “модуль”?
Модуль - это файл .py

keereel
Попробовал всё что было
Не надо, просто вручную строки запиши и пошли.

Можешь перед строкой с d.search() и после неё поставить print() и посмотреть по выводу скорость выполнения запроса.



Отредактировано py.user.next (Май 12, 2016 12:13:45)

Офлайн

#8 Май 12, 2016 12:42:58

keereel
Зарегистрирован: 2016-05-11
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

API Discogs: год релиза трека - Python

py.user.next
Не надо, просто вручную строки запиши и пошли.
ну если в файле будет скрипт - ничего?
py.user.next
Можешь перед строкой с d.search() и после неё поставить print() и посмотреть по выводу скорость выполнения запроса.
Так проблема то не с d.search() - без него не обойтись. В идеале это должен был бы быть единственный запрос к базе. Проблема с
    for x in range(len(searchresults)):
        try:
            relyear = searchresults[x].main_release.year
            if relyear <> 0 and item['year'] > relyear: item['year'] = relyear
Этот цикл, судя по времени его выполнения, тоже каждый проход посылает запросы к API. Я поставил в нём везде print - и да, основная задержка как раз на relyear = searchresults.main_release.year. Как выкачать объект сразу и уже тут, на месте из него доставать данные?

Офлайн

#9 Май 12, 2016 20:43:43

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

API Discogs: год релиза трека - Python

keereel
Как выкачать объект сразу и уже тут, на месте из него доставать данные?
Я вам предложил list сделать, который должен по идее итератор превратить в список объектов. Результат конечно далеко не гарантирован. А как выкачивать объект что вы у нас то спрашиваете? Вы тут единственный кто discogs_client использовал. Это в его документации и надо смотреть. Может и напрямую API использовать надо…



Офлайн

#10 Май 13, 2016 00:34:52

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

API Discogs: год релиза трека - Python

doza_and
Это в его документации и надо смотреть. Может и напрямую API использовать надо…
Исходники смотрел вчера, она сделана по типу ORM
https://www.github.com/discogs/discogs_client.git

Так что вполне может быть, что оно докачивает при обращению к полю, чтобы предоставлять самые свежие данные.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version