Interrogating a web API using query-url's, for each query I can get either zero hits, one hit, or multiple hits. Each of those categories needs to go into a separate CSV file for manual review or processing later. (More on this project here and here).
The input data (from a 14K line csv, one line per artist) is full of holes. Only a name is always given, but may be misspelled or in a form that the API does not recognise. Birth dates, death dates may or may not be known, with a precision like for example 'not before may 1533, not after january 1534'. It may also have exact dates in ISO format.
Using those three different output csv's, the user may go back to their source, try to refine their data, and run the script again to get a better match. Exactly one hit is what we go for: a persistent identifier for this specific artist.
In the code below, df
is a Pandas dataframe that has all the information in a form that is easiest to interrogate the API with.
First, I try to get an exact match best_q
(exact match of name string + any of the available input fields elsewhere in the record), if that yields zero, I try a slightly more loose match bracket_q
(any of the words in the literal name string + any of the available input fields elsewhere in the record).
I output the dataframe as a separate csv, and each list of zero hits, single hits, or multiple hits also in a separate csv.
I'm seeking advice on two specific things.
Is there a more Pythonic way of handling the lists? Right now, I think the code is readable enough, but I have one line to generate the lists, another to put them in a list of lists, and another to put them in a list of listnames.
The second thing is the nested
if..elif
on zero hits for the first query. I know it ain't pretty, but it's still quite readable (to me), and I don't see how I could do that any other way. That is: I have to trybest q
first, and only if it yields zero, try again withbracket_q
.
I have omitted what goes before. It works, it's been reviewed, I'm happy with it.
A final note: I'm not very concerned about performance, because the API is the bottleneck. I am concerned about readability. Users may want to tweak the script, somewhere down the line.
singles, multiples, zeroes = ([] for i in range(3))
for row in df.itertuples():
query = best_q(row)
hits, uri = ask_rkd(query)
if hits == 1:
singles.append([row.priref, row.name, hits, uri])
elif hits > 1:
multiples.append([row.priref, row.name, hits])
elif hits == 0:
query = bracket_q(row)
hits, uri = ask_rkd(query)
if hits == 1:
singles.append([row.priref, row.name, hits, uri])
elif hits > 1:
multiples.append([row.priref, row.name, hits])
elif hits == 0:
zeroes.append([row.priref, str(row.name)]) # PM: str!!
lists = singles, multiples, zeroes
listnames = ['singles','multiples','zeroes']
for s, l in zip(listnames, lists):
listfile = '{}_{}.csv'.format(input_fname, s)
writelist(list=l, fname=listfile)
outfile = fname + '_out' + ext
df.to_csv(outfile, sep='|', encoding='utf-8-sig')