-
Notifications
You must be signed in to change notification settings - Fork 0
/
_bnf.py
101 lines (85 loc) · 3.36 KB
/
_bnf.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
# -*- coding: utf-8 -*-
"""Query the BnF Catalogue Général service for metadata."""
import logging
from xml.dom.minidom import parseString
from isbnlib import to_isbn10
from isbnlib.dev import stdmeta
from isbnlib.dev._bouth23 import u
from isbnlib.dev.webquery import query as wquery
LOGGER = logging.getLogger(__name__)
UA = 'isbnlib (gzip)'
SERVICE_URL = 'http://catalogue.bnf.fr/api/SRU?version=1.2'\
'&operation=searchRetrieve&query={isbn}'\
'&maximumRecords=1&recordSchema=dublincore'
def _get_text(topnode):
"""Get the text values in the child nodes."""
text = ""
for node in topnode.childNodes:
if node.nodeType == node.TEXT_NODE: # pragma: no cover
text = text + node.data
return text
def _clean_title(title):
"""Clean the Title field of some unnecessary annotations."""
title = title.replace('<', '').replace('>', '')\
.replace(': roman', '').split('/')[0]
return title.strip(':.,; ')
def _clean_author(author):
"""Clean the Author field of some unnecessary annotations."""
author = author.replace('Auteur du texte', '')\
.split('/')[0].split(';')[0]
if '(' in author:
author = author.split('(')[0]
return author.strip(':.,; ')
def parser_bnf(xml):
"""Parse the response from the BnF Catalogue Général service (France)."""
# handle special case
if 'numberOfRecords>0<' in xml:
return {}
# parse xml and extract canonical fields
dom = parseString(xml)
keys = ('Title', 'Authors', 'Publisher', 'Year', 'Language')
fields = ('dc:title', 'dc:creator', 'dc:publisher', 'dc:date',
'dc:language')
recs = {}
try:
for key, field in zip(keys, fields):
nodes = dom.getElementsByTagName("oai_dc:dc")[0]\
.getElementsByTagName(field)
txt = '|'.join([_get_text(node) for node in nodes])
recs[key] = u(txt)
# cleanning
recs['Publisher'] = recs['Publisher'].split('|')[0]
authors = recs['Authors'].split('|')
recs['Authors'] = [_clean_author(author) for author in authors]
recs['Year'] = u(''.join(c for c in recs['Year'] if c.isdigit())[:4])
recs['Title'] = _clean_title(recs['Title'])
recs['Language'] = recs['Language'].split('|')[0]
except Exception as exc:
LOGGER.debug('Check the parsing for BnF (%r)', exc, exc_info=True)
return recs
def _mapper(isbn, records):
"""Make records canonical.
canonical: ISBN-13, Title, Authors, Publisher, Year, Language
"""
# handle special case
if not records: # pragma: no cover
return {}
# add ISBN-13
records['ISBN-13'] = u(isbn)
# call stdmeta for extra cleanning and validation
return stdmeta(records)
def query(isbn):
"""Query the BnF Catalogue Général service for metadata."""
# Quirk (see issue #1)
isbn10 = to_isbn10(isbn)
if isbn10:
isbn_query = "(bib.isbn%20all%20%22{isbn10}%22%20or%20bib.isbn%20"\
"all%20%22{isbn}%22)".format(isbn10=isbn10, isbn=isbn)
else:
isbn_query = "bib.isbn%20all%20%22{isbn}%22".format(isbn=isbn)
data = wquery(
SERVICE_URL.format(isbn=isbn_query), user_agent=UA, parser=parser_bnf)
if not data: # pragma: no cover
LOGGER.debug('No data from BnF Catalogue Général for isbn %s', isbn)
return {}
return _mapper(isbn, data)