gruplac-json 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gruplac_json-0.1.0/.gitignore +17 -0
- gruplac_json-0.1.0/CHANGELOG.md +25 -0
- gruplac_json-0.1.0/LICENSE +21 -0
- gruplac_json-0.1.0/PKG-INFO +110 -0
- gruplac_json-0.1.0/README.md +79 -0
- gruplac_json-0.1.0/docs/gruplac_json_esquema.md +206 -0
- gruplac_json-0.1.0/pyproject.toml +72 -0
- gruplac_json-0.1.0/src/gruplac_json/__init__.py +17 -0
- gruplac_json-0.1.0/src/gruplac_json/__main__.py +3 -0
- gruplac_json-0.1.0/src/gruplac_json/cli.py +68 -0
- gruplac_json-0.1.0/src/gruplac_json/data/col_nro.json +6938 -0
- gruplac_json-0.1.0/src/gruplac_json/members.py +193 -0
- gruplac_json-0.1.0/src/gruplac_json/parser.py +807 -0
- gruplac_json-0.1.0/src/gruplac_json/py.typed +0 -0
- gruplac_json-0.1.0/src/gruplac_json/scienti.py +209 -0
- gruplac_json-0.1.0/tests/conftest.py +22 -0
- gruplac_json-0.1.0/tests/fixtures/gruplac_sintetico.html +327 -0
- gruplac_json-0.1.0/tests/test_cli.py +27 -0
- gruplac_json-0.1.0/tests/test_parser.py +212 -0
- gruplac_json-0.1.0/tests/test_scienti.py +66 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
.venv/
|
|
7
|
+
venv/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
.coverage
|
|
11
|
+
coverage.xml
|
|
12
|
+
htmlcov/
|
|
13
|
+
# Add here any generated outputs or data files that hold personal data (e.g. downloaded pages)
|
|
14
|
+
# Never commit credentials
|
|
15
|
+
.env
|
|
16
|
+
.pypirc
|
|
17
|
+
*apikey*
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and versions follow [Semantic Versioning](https://semver.org/).
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-11-02
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- Parser of the public GrupLAC page: basic data, institutions, strategic plan, research lines, members
|
|
11
|
+
("Integrantes del grupo") with COD_RH and linkage period, bibliographic production as ImpactU works, projects,
|
|
12
|
+
scientific events and every other section in `other_products`, with the structured fields of each item.
|
|
13
|
+
- Same record schema as cvlac-json for the same products (depends on cvlac-json for its helpers); the four social
|
|
14
|
+
appropriation sections merged into "Apropiación social del conocimiento".
|
|
15
|
+
- Member affiliations: authors matched to members by name get their COD_RH and, when the product's year is in their
|
|
16
|
+
linkage period, the group as affiliation with `gruplac.provenance: "gruplac members"`.
|
|
17
|
+
- Scienti ids from the group's records in apis.colav.co (`group_id`), with the other members' records of the same
|
|
18
|
+
product in `scienti.also`; items without authors on the page get the members who registered them in Scienti.
|
|
19
|
+
- ROR ids of the group's institutions and of thesis institutions.
|
|
20
|
+
- COL code <-> GrupLAC number table (6,936 groups, 2026-10-31) shipped with the package.
|
|
21
|
+
- Items of Guías de práctica clínica and Proyectos de ley, which come after a blank header row.
|
|
22
|
+
- Command line `gruplac-json COL|NRO` with `--html`, `--save-html`, `--scienti`, `--ror`, `--apikey`.
|
|
23
|
+
|
|
24
|
+
[Unreleased]: https://github.com/restrepo/gruplac-json/compare/v0.1.0...HEAD
|
|
25
|
+
[0.1.0]: https://github.com/restrepo/gruplac-json/releases/tag/v0.1.0
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Diego Restrepo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: gruplac-json
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Turn a research group's public GrupLAC page (Minciencias, Colombia) into one JSON document, in the cvlac-json schema, with member affiliations and Scienti ids.
|
|
5
|
+
Project-URL: Homepage, https://github.com/restrepo/gruplac-json
|
|
6
|
+
Project-URL: Repository, https://github.com/restrepo/gruplac-json
|
|
7
|
+
Project-URL: Issues, https://github.com/restrepo/gruplac-json/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/restrepo/gruplac-json/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: Diego Restrepo <restrepo@udea.edu.co>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: bibliometrics,colombia,cris,cvlac,gruplac,impactu,minciencias,research groups,scienti
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: Natural Language :: Spanish
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: cvlac-json>=0.7
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest-cov>=5; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
28
|
+
Requires-Dist: ruff==0.17.3; extra == 'dev'
|
|
29
|
+
Requires-Dist: twine>=5; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# gruplac-json
|
|
33
|
+
|
|
34
|
+
Convierte la página pública del **GrupLAC** de un grupo de investigación (Minciencias, Colombia) en un único documento JSON: datos básicos, instituciones (con su ROR), plan estratégico, líneas de investigación, integrantes con su COD_RH y su periodo de vinculación, producción bibliográfica en el esquema de obras de [ImpactU](https://impactu.colav.co), proyectos, eventos y todos los demás productos (`other_products`), con autores, título, lugar, fechas, identificadores, enlaces y los demás datos rotulados de cada ítem.
|
|
35
|
+
|
|
36
|
+
Es la pareja de [cvlac-json](https://github.com/restrepo/cvlac-json): los productos que existen en ambos tienen la misma forma, y usa sus herramientas de ROR y de Scienti.
|
|
37
|
+
|
|
38
|
+
- **Afiliaciones de los integrantes:** cada autor de un producto que aparece en "Integrantes del grupo" recibe su COD_RH y, si el año del producto está en su periodo "Inicio - Fin Vinculación", el grupo como afiliación, con la procedencia (`gruplac.provenance: "gruplac members"`), como hace cvlac-json con la experiencia.
|
|
39
|
+
- Con una clave de [apis.colav.co](https://apis.colav.co), agrega los **identificadores Scienti** (`COD_RH-COD_PRODUCTO`, `-COD_PROYECTO`, `-COD_EVENTO`, `-COD_RED`) de los registros del grupo que coinciden. Los productos sin autores en la página (consultorías, conceptos técnicos, procesos de apropiación social…) reciben como autores a los integrantes que registraron ese producto en Scienti.
|
|
40
|
+
|
|
41
|
+
## Instalación
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install gruplac-json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Uso en la terminal
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
gruplac-json COL0008423 # escribe gruplac_COL0008423.json
|
|
51
|
+
gruplac-json 1676 # el número de GrupLAC, con o sin ceros a la izquierda
|
|
52
|
+
gruplac-json COL0008423 --save-html g.html # guarda también la página descargada
|
|
53
|
+
gruplac-json COL0008423 --html g.html.gz # analiza una página guardada (.html o .html.gz), sin descargar
|
|
54
|
+
gruplac-json COL0008423 -o - # JSON por la salida estándar
|
|
55
|
+
gruplac-json COL0008423 --scienti off --ror off
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
| Opción | Efecto |
|
|
59
|
+
| --- | --- |
|
|
60
|
+
| `--scienti auto` (por defecto) | Si hay clave de apis.colav.co, agrega los ids Scienti de los registros del grupo que coinciden. |
|
|
61
|
+
| `--scienti off` | No consulta Scienti. |
|
|
62
|
+
| `--institution`, `--model-year` | Volcado de Scienti (`udea`, `univalle`, `uec`, `unaula`) y año del modelo. Por defecto se prueban en ese orden. |
|
|
63
|
+
| `--apikey CLAVE` | Clave de apis.colav.co para esta ejecución. |
|
|
64
|
+
| `--ror auto` / `off` | Consulta o no el registro ROR (instituciones del grupo y de las tesis). |
|
|
65
|
+
|
|
66
|
+
El código COL se traduce al número de GrupLAC con la tabla de los 6.936 grupos de la búsqueda de grupos de Minciencias (31 de octubre de 2026), incluida en el paquete. Un grupo que no esté en la tabla se puede pedir por su número de GrupLAC; sin código COL no se consulta Scienti.
|
|
67
|
+
|
|
68
|
+
La clave de apis.colav.co se toma, en este orden, de `--apikey`, de la variable de entorno `COLAV_APIKEY` o del archivo `~/.config/colav/apikey`. Nunca se imprime.
|
|
69
|
+
|
|
70
|
+
## Uso como biblioteca
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from gruplac_json import extract
|
|
74
|
+
|
|
75
|
+
data = extract("COL0008423", scienti="off") # descarga y analiza la página
|
|
76
|
+
print(data["name"], len(data["members"]), len(data["works"]))
|
|
77
|
+
|
|
78
|
+
from gruplac_json.parser import decode
|
|
79
|
+
|
|
80
|
+
html = decode(open("g.html", "rb").read())
|
|
81
|
+
data = extract("COL0008423", html=html, ror=False)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Esquema del JSON
|
|
85
|
+
|
|
86
|
+
El esquema completo, campo por campo, está en [docs/gruplac_json_esquema.md](docs/gruplac_json_esquema.md).
|
|
87
|
+
|
|
88
|
+
## Desarrollo
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
git clone https://github.com/restrepo/gruplac-json.git
|
|
92
|
+
cd gruplac-json
|
|
93
|
+
python -m pip install -e ".[dev]"
|
|
94
|
+
python -m pytest
|
|
95
|
+
ruff check . && ruff format --check .
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Las pruebas no usan la red: corren sobre una página sintética (`tests/fixtures/gruplac_sintetico.html`) con personas y productos ficticios y la misma estructura HTML del GrupLAC.
|
|
99
|
+
|
|
100
|
+
Cómo publicar una versión nueva en PyPI: [PUBLISHING.md](PUBLISHING.md) y [CHANGELOG.md](CHANGELOG.md).
|
|
101
|
+
|
|
102
|
+
## Avisos
|
|
103
|
+
|
|
104
|
+
- La página del GrupLAC es pública, pero contiene datos personales (nombres de los integrantes, correo del grupo). Úselos de acuerdo con la normativa de protección de datos que aplique.
|
|
105
|
+
- Sea moderado con el servidor de Minciencias: haga una pausa de uno o dos segundos entre grupos cuando procese muchos.
|
|
106
|
+
- Las afiliaciones de los productos son **inferidas** del periodo de vinculación (el autor era integrante del grupo ese año); el GrupLAC no las declara. Los coautores que no son integrantes no tienen afiliación.
|
|
107
|
+
|
|
108
|
+
## Licencia
|
|
109
|
+
|
|
110
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# gruplac-json
|
|
2
|
+
|
|
3
|
+
Convierte la página pública del **GrupLAC** de un grupo de investigación (Minciencias, Colombia) en un único documento JSON: datos básicos, instituciones (con su ROR), plan estratégico, líneas de investigación, integrantes con su COD_RH y su periodo de vinculación, producción bibliográfica en el esquema de obras de [ImpactU](https://impactu.colav.co), proyectos, eventos y todos los demás productos (`other_products`), con autores, título, lugar, fechas, identificadores, enlaces y los demás datos rotulados de cada ítem.
|
|
4
|
+
|
|
5
|
+
Es la pareja de [cvlac-json](https://github.com/restrepo/cvlac-json): los productos que existen en ambos tienen la misma forma, y usa sus herramientas de ROR y de Scienti.
|
|
6
|
+
|
|
7
|
+
- **Afiliaciones de los integrantes:** cada autor de un producto que aparece en "Integrantes del grupo" recibe su COD_RH y, si el año del producto está en su periodo "Inicio - Fin Vinculación", el grupo como afiliación, con la procedencia (`gruplac.provenance: "gruplac members"`), como hace cvlac-json con la experiencia.
|
|
8
|
+
- Con una clave de [apis.colav.co](https://apis.colav.co), agrega los **identificadores Scienti** (`COD_RH-COD_PRODUCTO`, `-COD_PROYECTO`, `-COD_EVENTO`, `-COD_RED`) de los registros del grupo que coinciden. Los productos sin autores en la página (consultorías, conceptos técnicos, procesos de apropiación social…) reciben como autores a los integrantes que registraron ese producto en Scienti.
|
|
9
|
+
|
|
10
|
+
## Instalación
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pip install gruplac-json
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Uso en la terminal
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
gruplac-json COL0008423 # escribe gruplac_COL0008423.json
|
|
20
|
+
gruplac-json 1676 # el número de GrupLAC, con o sin ceros a la izquierda
|
|
21
|
+
gruplac-json COL0008423 --save-html g.html # guarda también la página descargada
|
|
22
|
+
gruplac-json COL0008423 --html g.html.gz # analiza una página guardada (.html o .html.gz), sin descargar
|
|
23
|
+
gruplac-json COL0008423 -o - # JSON por la salida estándar
|
|
24
|
+
gruplac-json COL0008423 --scienti off --ror off
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
| Opción | Efecto |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| `--scienti auto` (por defecto) | Si hay clave de apis.colav.co, agrega los ids Scienti de los registros del grupo que coinciden. |
|
|
30
|
+
| `--scienti off` | No consulta Scienti. |
|
|
31
|
+
| `--institution`, `--model-year` | Volcado de Scienti (`udea`, `univalle`, `uec`, `unaula`) y año del modelo. Por defecto se prueban en ese orden. |
|
|
32
|
+
| `--apikey CLAVE` | Clave de apis.colav.co para esta ejecución. |
|
|
33
|
+
| `--ror auto` / `off` | Consulta o no el registro ROR (instituciones del grupo y de las tesis). |
|
|
34
|
+
|
|
35
|
+
El código COL se traduce al número de GrupLAC con la tabla de los 6.936 grupos de la búsqueda de grupos de Minciencias (31 de octubre de 2026), incluida en el paquete. Un grupo que no esté en la tabla se puede pedir por su número de GrupLAC; sin código COL no se consulta Scienti.
|
|
36
|
+
|
|
37
|
+
La clave de apis.colav.co se toma, en este orden, de `--apikey`, de la variable de entorno `COLAV_APIKEY` o del archivo `~/.config/colav/apikey`. Nunca se imprime.
|
|
38
|
+
|
|
39
|
+
## Uso como biblioteca
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from gruplac_json import extract
|
|
43
|
+
|
|
44
|
+
data = extract("COL0008423", scienti="off") # descarga y analiza la página
|
|
45
|
+
print(data["name"], len(data["members"]), len(data["works"]))
|
|
46
|
+
|
|
47
|
+
from gruplac_json.parser import decode
|
|
48
|
+
|
|
49
|
+
html = decode(open("g.html", "rb").read())
|
|
50
|
+
data = extract("COL0008423", html=html, ror=False)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Esquema del JSON
|
|
54
|
+
|
|
55
|
+
El esquema completo, campo por campo, está en [docs/gruplac_json_esquema.md](docs/gruplac_json_esquema.md).
|
|
56
|
+
|
|
57
|
+
## Desarrollo
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
git clone https://github.com/restrepo/gruplac-json.git
|
|
61
|
+
cd gruplac-json
|
|
62
|
+
python -m pip install -e ".[dev]"
|
|
63
|
+
python -m pytest
|
|
64
|
+
ruff check . && ruff format --check .
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Las pruebas no usan la red: corren sobre una página sintética (`tests/fixtures/gruplac_sintetico.html`) con personas y productos ficticios y la misma estructura HTML del GrupLAC.
|
|
68
|
+
|
|
69
|
+
Cómo publicar una versión nueva en PyPI: [PUBLISHING.md](PUBLISHING.md) y [CHANGELOG.md](CHANGELOG.md).
|
|
70
|
+
|
|
71
|
+
## Avisos
|
|
72
|
+
|
|
73
|
+
- La página del GrupLAC es pública, pero contiene datos personales (nombres de los integrantes, correo del grupo). Úselos de acuerdo con la normativa de protección de datos que aplique.
|
|
74
|
+
- Sea moderado con el servidor de Minciencias: haga una pausa de uno o dos segundos entre grupos cuando procese muchos.
|
|
75
|
+
- Las afiliaciones de los productos son **inferidas** del periodo de vinculación (el autor era integrante del grupo ese año); el GrupLAC no las declara. Los coautores que no son integrantes no tienen afiliación.
|
|
76
|
+
|
|
77
|
+
## Licencia
|
|
78
|
+
|
|
79
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# Esquema del JSON extraído del GrupLAC
|
|
2
|
+
|
|
3
|
+
Este documento describe el JSON que produce el paquete **gruplac-json** (comando `gruplac-json` o función `gruplac_json.extract()`) a partir de la página pública del GrupLAC de un grupo de investigación:
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
https://scienti.minciencias.gov.co/gruplac/jsp/visualiza/visualizagr.jsp?nro=NRO
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Los registros siguen el esquema de [cvlac-json](https://github.com/restrepo/cvlac-json/blob/main/docs/cvlac_json_esquema.md) siempre que el producto es el mismo: `works` tiene la forma de las obras de ImpactU, y `projects`, `events` y `other_products` las de cvlac-json. Este documento explica sobre todo lo que cambia. El esquema se construyó con las 6.936 páginas de la búsqueda de grupos de Minciencias (descargadas del 31 de octubre al 1 de noviembre de 2026), con nueve grupos que juntos tienen ítems en todas las secciones.
|
|
10
|
+
|
|
11
|
+
## 1. Cómo se genera
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
gruplac-json COL|NRO [-o salida.json] [--html pagina.html[.gz]] [--save-html pagina.html]
|
|
15
|
+
[--scienti auto|off] [--institution udea] [--model-year 2024] [--apikey CLAVE] [--ror auto|off]
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
| Fuente | Qué aporta | Opción |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| Página pública del GrupLAC | **Todos los registros** | Siempre |
|
|
21
|
+
| Tabla de grupos de Minciencias (en el paquete) | Código COL ↔ número de GrupLAC | Siempre |
|
|
22
|
+
| Scienti (apis.colav.co, con clave), consultado por el código COL del grupo | Ids Scienti de los ítems que coinciden, y autores de los ítems que no los listan | `--scienti auto` (por defecto) |
|
|
23
|
+
| ROR (api.ror.org) | ROR de las instituciones del grupo y de las tesis | `--ror auto` (por defecto) |
|
|
24
|
+
|
|
25
|
+
## 2. Convenciones generales
|
|
26
|
+
|
|
27
|
+
Las de cvlac-json (§2 de su esquema): los mismos campos en todos los registros de una colección (`[]` o `null` donde no hay dato), los campos vacíos en toda la colección se eliminan, los textos se conservan como en la página, y `provenance` / `source` siguen la convención de ImpactU, aquí con `gruplac` en lugar de `cvlac`. Excepción: los ítems de `other_products` siempre tienen `authors`, aunque sea `[]`.
|
|
28
|
+
|
|
29
|
+
Las secciones vacías (el GrupLAC muestra siempre las 87, la mayoría sin ítems) no aparecen.
|
|
30
|
+
|
|
31
|
+
## 3. Nivel superior
|
|
32
|
+
|
|
33
|
+
| Campo | Tipo | Descripción |
|
|
34
|
+
| --- | --- | --- |
|
|
35
|
+
| `nro` | string | Número de GrupLAC (14 dígitos). |
|
|
36
|
+
| `col` | string o null | Código del grupo en Minciencias (`COL0008423`); `null` si la tabla no conoce el número. |
|
|
37
|
+
| `url`, `retrieved` | string | Página leída y fecha de la extracción (UTC). |
|
|
38
|
+
| `name` | string | Nombre del grupo. |
|
|
39
|
+
| `profile` | object | "Datos básicos" (§4). |
|
|
40
|
+
| `institutions` | array | `{name, status, ror}`: instituciones del grupo; `status` es "Avalado" u otro; `ror` es `{id, name, match}` o `null`. |
|
|
41
|
+
| `strategic_plan` | object | "Plan Estratégico": `Plan de trabajo`, `Estado del arte`, `Objetivos`, `Retos`, `Visión`…, como en la página. |
|
|
42
|
+
| `research_lines` | array | `{name}`: líneas de investigación declaradas. |
|
|
43
|
+
| `members` | array | "Integrantes del grupo" (§5). |
|
|
44
|
+
| `works` | array | Producción bibliográfica, en el esquema de obras de ImpactU (§6). |
|
|
45
|
+
| `projects` | array | Proyectos (§7). |
|
|
46
|
+
| `events` | array | Eventos científicos (§7). |
|
|
47
|
+
| `other_products` | object | Las demás secciones, por título (§8). |
|
|
48
|
+
| `section_categories` | object | Sección → categoría de la página: "PRODUCCIÓN BIBLIOGRÁFICA", "PRODUCCIÓN TÉCNICA Y TECNOLÓGICA", "APROPIACIÓN SOCIAL Y DIVULGACIÓN PÚBLICA DE LA CIENCIA", "Producción en arte, arquitectura y diseño", "ACTIVIDADES DE FORMACIÓN", "ACTIVIDADES COMO EVALUADOR", "PRODUCCIÓN DE FORMACIÓN Y EXTENSIÓN"… |
|
|
49
|
+
| `counts` | object | Conteos (§10). |
|
|
50
|
+
| `affiliations_from_members` | object | Resumen de la asignación de integrantes y afiliaciones (§9). |
|
|
51
|
+
| `scienti` | object | Resumen del cruce con Scienti; solo con clave (§11). |
|
|
52
|
+
|
|
53
|
+
## 4. `profile`
|
|
54
|
+
|
|
55
|
+
| Campo | Tipo | Ejemplo |
|
|
56
|
+
| --- | --- | --- |
|
|
57
|
+
| `raw` | object | Las filas de "Datos básicos", con las etiquetas como en la página. |
|
|
58
|
+
| `formed` | object | `{"year": 1979, "month": 12}` ("Año y mes de formación"). |
|
|
59
|
+
| `department`, `city` | string | "ANTIOQUIA", "MEDELLÍN". |
|
|
60
|
+
| `leader` | string | Nombre del líder. |
|
|
61
|
+
| `certified` | object o null | `{"value": "Si", "date": "2016-01-21"}`. |
|
|
62
|
+
| `website`, `email` | string o null | Como en la página. |
|
|
63
|
+
| `classification` | object o null | `{"category": "A1", "text": "con vigencia hasta …"}`. |
|
|
64
|
+
| `knowledge_area` | array de string | `["Ciencias Naturales", "Ciencias Físicas", "Física de Partículas y Campos"]`. |
|
|
65
|
+
| `national_program`, `national_program_secondary` | string o null | Programas nacionales de CTI. |
|
|
66
|
+
|
|
67
|
+
## 5. `members[]`
|
|
68
|
+
|
|
69
|
+
| Campo | Tipo | Descripción |
|
|
70
|
+
| --- | --- | --- |
|
|
71
|
+
| `full_name` | string | Nombre como en la tabla. |
|
|
72
|
+
| `cod_rh` | string | COD_RH (del enlace a su CvLAC). |
|
|
73
|
+
| `url` | string | Enlace al CvLAC. |
|
|
74
|
+
| `linkage` | string | "Vinculación": Integrante, Estudiante… |
|
|
75
|
+
| `hours` | integer | Horas de dedicación. |
|
|
76
|
+
| `period` | string | Texto original, "2012/1 - Actual". |
|
|
77
|
+
| `start`, `end` | object | `{year, month}`; `end` es `null` si el periodo sigue abierto. |
|
|
78
|
+
| `open_end` | boolean | `true` si termina en "Actual". |
|
|
79
|
+
|
|
80
|
+
## 6. `works[]`
|
|
81
|
+
|
|
82
|
+
Las secciones Artículos publicados, Otros artículos publicados, Libros publicados, Libros de formación, Libros de divulgación y/o Compilación de divulgación, Manuales y Guías Especializadas, Otros Libros publicados, Capítulos de libro publicados, Documentos de trabajo, Otra publicación divulgativa, Traducciones, Traducciones Filológicas y Edición de Fuentes, Notas científicas y Publicaciones editoriales no especializadas (esta última, como en cvlac-json).
|
|
83
|
+
|
|
84
|
+
Mismos campos que en cvlac-json (§10 de su esquema), con estas diferencias:
|
|
85
|
+
|
|
86
|
+
- `id` es `gruplac:NRO:n` (n = orden en la página).
|
|
87
|
+
- `types[]`: nivel 0 "Producción bibliográfica", nivel 1 la clase de la sección (Artículo, Libro, Capítulo de libro…), nivel 2 el tipo en negrilla del ítem ("Publicado en revista especializada", "Libro resultado de investigación"…), con `source: "gruplac"`.
|
|
88
|
+
- `authors[]` son los de "Autores:" (el GrupLAC lista solo a los integrantes que registraron el producto y a sus coautores en el CvLAC). Los integrantes llevan su COD_RH en `id` y en `external_ids` y, si el año está en su periodo, la afiliación al grupo (§9).
|
|
89
|
+
- `source.publisher.country` es el país de la revista o editorial, como en cvlac-json.
|
|
90
|
+
- `gruplac` reemplaza a `cvlac`: `section`, `endorsed` (marca de verificación), `country`, `fields` (pares etiqueta → valor rotulados), `text` (texto completo) y `scienti` (§11).
|
|
91
|
+
|
|
92
|
+
## 7. `projects[]` y `events[]`
|
|
93
|
+
|
|
94
|
+
| `projects[]` | Descripción |
|
|
95
|
+
| --- | --- |
|
|
96
|
+
| `type`, `title` | "Investigación y desarrollo", "Extensión y responsabilidad social CTI"…, y el título. |
|
|
97
|
+
| `endorsed` | Marca de verificación. |
|
|
98
|
+
| `start`, `end` | `{year, month}`; `end` es `null` si el proyecto sigue ("Actual"). |
|
|
99
|
+
| `ongoing` | `true` si termina en "Actual". |
|
|
100
|
+
| `text` | Texto completo. |
|
|
101
|
+
| `scienti`, `external_ids` | Coincidencia con Scienti (§11). |
|
|
102
|
+
|
|
103
|
+
| `events[]` | Descripción |
|
|
104
|
+
| --- | --- |
|
|
105
|
+
| `name`, `type` | Nombre y tipo (Congreso, Encuentro, Seminario, Simposio, Taller, Otro). |
|
|
106
|
+
| `scope` | "Ámbito". |
|
|
107
|
+
| `start`, `end` | `AAAA-MM-DD`. |
|
|
108
|
+
| `place` | Ciudad. |
|
|
109
|
+
| `participation` | "Tipos de participación", p. ej. `["Ponente"]`. |
|
|
110
|
+
| `institutions[]` | `{name, link}` de "Instituciones asociadas" (`link`: Patrocinadora, Organizadora…). |
|
|
111
|
+
| `text`, `endorsed`, `scienti` | |
|
|
112
|
+
|
|
113
|
+
## 8. `other_products`
|
|
114
|
+
|
|
115
|
+
Un objeto cuyas claves son los títulos de las demás secciones del GrupLAC, con los ítems en el orden de la página. Las cuatro secciones de apropiación social del conocimiento (fortalecimiento o solución de asuntos de interés social; trabajo conjunto entre un Centro de Ciencia y un grupo; generación de insumos de política pública y normatividad; fortalecimiento de cadenas productivas) van juntas en "Apropiación social del conocimiento", como en cvlac-json, con `type` "Apropiación social del conocimiento - <título de la sección>". Las secciones de arte, arquitectura y diseño (Obras o productos, Industrias creativas y culturales, Eventos Artísticos, Talleres de Creación) son filas de encabezado dentro de una sola tabla de la página; aquí son secciones normales.
|
|
116
|
+
|
|
117
|
+
Cada ítem tiene los campos de cvlac-json (§13 de su esquema) que se puedan leer de su texto, y algunos propios del GrupLAC:
|
|
118
|
+
|
|
119
|
+
| Campo | Tipo | De dónde sale |
|
|
120
|
+
| --- | --- | --- |
|
|
121
|
+
| `type` | string | El tipo en negrilla ("Consultoría científica", "Computacional", "Marcas", "Spin-off"…). En Redes de Conocimiento Especializado es la clase de red ("Real", "Virtual"). |
|
|
122
|
+
| `endorsed` | boolean | Marca de verificación. |
|
|
123
|
+
| `title` | string | El texto tras el tipo, o el valor de "Nombre del producto", "Nombre del proceso", "Nombre del curso", "Programa académico", "Nombre del evento", "Nombre del taller", "Nombre de la empresa creativa o cultural". |
|
|
124
|
+
| `authors[]` | array | **Siempre presente.** Las personas de "Autores:", como en las obras (§6), con `{full_name, id, external_ids, affiliations}`. En tesis, `type` `advisor`/`co-advisor` (Tutor(es)/Cotutor(es), según "Tipo de orientación") y `student` (Nombre del estudiante); en jurados, `jury` y `student` (Nombre del orientado). Muchas secciones no listan autores (consultorías, conceptos e informes técnicos, contenido digital, apropiación social, redes, estrategias…): ahí la lista queda vacía, salvo que Scienti diga qué integrantes registraron el producto (§11). |
|
|
125
|
+
| `authors_inferred` | boolean | `true` si los autores vienen de los registros Scienti. |
|
|
126
|
+
| `country`, `city`, `place` | string | "Colombia, 2020" al inicio de la línea, "Ciudad", "en MEDELLÍN", "Lugar", "Lugar de realización". |
|
|
127
|
+
| `institution` | string | "Institución", "Institución solicitante", "Institución que emite el registro", "Institución en la cual prestó el servicio". En tesis es `{name, id, ror_name, ror_match}`, como en cvlac-json. |
|
|
128
|
+
| `funder` | string | "Institución financiadora". |
|
|
129
|
+
| `certifier` | string | "Institución certificadora". |
|
|
130
|
+
| `participating_institutions` | string | "Instituciones participantes", "Entidades vinculadas". |
|
|
131
|
+
| `date` | string | `AAAA-MM-DD`, `AAAA-MM` o `AAAA`: fecha de creación, presentación (también "Año: …, Mes: …"), envío, obtención, publicación, registro ante cámara, del acto administrativo, de solicitud, o el año de la línea. |
|
|
132
|
+
| `start`, `end` | string | Fechas de inicio y fin ("Fecha de inicio", "Año de inicio"/"Mes de inicio", "desde … hasta …"). |
|
|
133
|
+
| `year` | integer o null | Año de `date`, `start` o `end`, o del texto. Es el año que se compara con el periodo del integrante. |
|
|
134
|
+
| `duration` | object | `{value, unit}` cuando la etiqueta trae la unidad ("Duración (semanas): 3"). |
|
|
135
|
+
| `pages` | integer | Tesis: "Número de páginas". |
|
|
136
|
+
| `project` | string | "Nombre del proyecto", "Proyecto de investigación". |
|
|
137
|
+
| `program`, `role`, `assessment` | string | "Programa académico", "Tipo de orientación", "Valoración". |
|
|
138
|
+
| `audience`, `differential_focus` | array de string | "público objetivo" y "Enfoque diferencial", separados por ";". |
|
|
139
|
+
| `scope`, `availability`, `language`, `medium`, `genre`, `circulation`, `format`, `license`, `topic`, `purpose`, `holder`, `database`, `description`, `commercial_name`, `participants_count`, `discipline`, `distinction`, `selection`, `cycle`, `edition`, `series`, `broadcaster`, `fairs`, `original_authors`, `original_language`, `translation_language` | string | Ámbito, Disponibilidad, Idioma, Medio de divulgación o de circulación, Género literario, Tipo de circulación, Tipo de formato, Licencia, Tema, Finalidad u Objeto, Titular, Base de datos, Descripción, Nombre comercial, Nro de participantes, Disciplina o ámbito de origen, Distinción obtenida, Mecanismo de selección, Tipo de ciclo, Edición, Serie, Emisora, Nombre de las ferias, y los datos de las traducciones. |
|
|
140
|
+
| `identifiers[]` | array | `{source, id}`: `contract` (Número del contrato), `registration` (Número de registro), `nit`, `concept number`, `administrative act`, `snies`, `doi`, `isbn`. |
|
|
141
|
+
| `links[]` | array | `{url, label}`: enlaces `<a>` y URL escritas en el texto ("medio de verificación", "Sitio web"…). |
|
|
142
|
+
| `text` | string | Texto completo del ítem. |
|
|
143
|
+
| `fields` | object | Todos los pares etiqueta → valor, como en la página (los vacíos se quitan). |
|
|
144
|
+
| `scienti` | object | Coincidencia con Scienti (§11). |
|
|
145
|
+
|
|
146
|
+
## 9. Afiliaciones y `affiliations_from_members`
|
|
147
|
+
|
|
148
|
+
Un autor es **integrante** cuando su nombre en "Autores:" coincide con el de un solo integrante de la tabla:
|
|
149
|
+
|
|
150
|
+
- `exact`: las mismas palabras, sin tildes ni mayúsculas ("OSCAR ALBERTO ZAPATA NORENA" = "Oscar Alberto Zapata Norena").
|
|
151
|
+
- `words`: las mismas palabras en otro orden, o un nombre contenido en el otro con al menos tres palabras ("ROBERTO TORRES CORREDOR" ⊂ "Roberto Armando Torres Corredor").
|
|
152
|
+
- `spelling`: las mismas palabras salvo una, que difiere en una letra o en dos letras vecinas intercambiadas ("GIRLADO" / "GIRALDO").
|
|
153
|
+
- `scienti`: el autor se agregó desde un registro Scienti de ese integrante (§11).
|
|
154
|
+
|
|
155
|
+
El integrante recibe su COD_RH en `id` y en `external_ids` (`{provenance: "gruplac", source: "scienti", id}`) y, **si el año del producto está en su periodo** "Inicio - Fin Vinculación" (hasta el año actual si dice "Actual"), el grupo como afiliación:
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"id": "COL0008423",
|
|
160
|
+
"name": "Grupo de Fenomenologia de Interacciones Fundamentales",
|
|
161
|
+
"types": [{"source": "minciencias", "type": "group"}],
|
|
162
|
+
"external_ids": [{"provenance": "gruplac", "source": "minciencias", "id": "COL0008423"},
|
|
163
|
+
{"provenance": "gruplac", "source": "gruplac", "id": "00000000001676"}],
|
|
164
|
+
"years": [2012, 2013, "…", 2026],
|
|
165
|
+
"gruplac": {"provenance": "gruplac members", "member": "Oscar Alberto Zapata Norena", "linkage": "Integrante",
|
|
166
|
+
"hours": 20, "period": "2012/1 - Actual", "name_match": "exact"}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Es la misma idea que las afiliaciones de cvlac-json ("cvlac experience"): significa "era integrante del grupo ese año", no que la página declare dónde se hizo el producto. Los autores que no son integrantes tienen `id: null` y `affiliations: []`. En las tesis, el tutor y los estudiantes también reciben la institución de la tesis con su ROR (`gruplac.provenance: "gruplac thesis"`).
|
|
171
|
+
|
|
172
|
+
`affiliations_from_members`: `members`, `members_with_cod_rh`, `authors`, `authors_matched`, `name_match` (por regla), `works_with_affiliation`, `products_with_affiliation`, `rule` y `ror_lookup_errors`.
|
|
173
|
+
|
|
174
|
+
## 10. `counts`
|
|
175
|
+
|
|
176
|
+
`members`, `works`, `projects`, `events`, `works:<sección>`, `<título de sección>` (ítems de cada lista de `other_products`), `endorsed_works`, `works_with_affiliation` y `products_with_affiliation` (con al menos un autor con la afiliación al grupo).
|
|
177
|
+
|
|
178
|
+
## 11. Coincidencias con Scienti
|
|
179
|
+
|
|
180
|
+
Se piden a apis.colav.co los registros del grupo (`/scienti/product`, `/project`, `/event` y `/network` con `group_id=COL…`), en el primer volcado (udea, univalle, uec, unaula) que los tenga. Cada registro es la entrada del CvLAC de un integrante, así que un producto del grupo puede coincidir con varios: uno por cada integrante que lo registró.
|
|
181
|
+
|
|
182
|
+
- Las reglas son las de cvlac-json: mismo DOI; mismo título (≥ 25 caracteres y 4 palabras) con año, ISSN, ISBN o revista; un título truncado con el mismo año; y, en proyectos, eventos y redes, mismo nombre y año.
|
|
183
|
+
- El mejor registro va a `scienti` (`id`, `by`, `evidence`, `shared`, `scienti_title`, `scienti_year`); los demás registros del mismo producto (mismo DOI, o mismo título y año) van a `scienti.also`. En las obras, todos se agregan a `external_ids` con `source: "scienti"`, y en los proyectos a `external_ids`.
|
|
184
|
+
- Los ítems sin autores en la página reciben como autores a los integrantes cuyos COD_RH tienen esos registros (`authors_inferred: true`).
|
|
185
|
+
|
|
186
|
+
Objeto `scienti` del nivel superior: `institution`, `model_year`, `source`, `group_id`, `products` (registros de productos del grupo), `products_matched`, `matched` (`works`, `other_products`, `projects`, `events`, `networks`), `records`, `items_with_authors_from_scienti`, `rules`, `not_on_page` (registros de productos sin ítem en la página) y `not_on_page_note`.
|
|
187
|
+
|
|
188
|
+
## 12. Valores observados (7.170 páginas guardadas, 2026-11-02)
|
|
189
|
+
|
|
190
|
+
Las 7.170 páginas descargadas el 31 de octubre y el 1 de noviembre de 2026 (los 6.936 grupos de la búsqueda de Minciencias y 234 más que conoce ImpactU) se analizaron sin errores. Algunas cifras, sumadas sobre todos los grupos:
|
|
191
|
+
|
|
192
|
+
| Sección | Ítems | Con título | Con año | Autores que son integrantes | Ítems con afiliación al grupo |
|
|
193
|
+
| --- | --- | --- | --- | --- | --- |
|
|
194
|
+
| Artículos publicados | 588.181 | 100 % | 100 % | 59 % | 91 % |
|
|
195
|
+
| Capítulos de libro publicados | 169.019 | 100 % | 100 % | 72 % | 93 % |
|
|
196
|
+
| Libros publicados | 61.299 | 100 % | 100 % | 65 % | 93 % |
|
|
197
|
+
| Trabajos dirigidos/turorías | 869.980 | 100 % | 100 % | 48 % | 91 % |
|
|
198
|
+
| Jurado/Comisiones evaluadoras de trabajo de grado | 390.944 | 100 % | 100 % | 49 % | 94 % |
|
|
199
|
+
| Eventos Científicos | 650.438 | 100 % | 100 % | — | — |
|
|
200
|
+
| Proyectos | 334.728 | 100 % | 99 % | — | — |
|
|
201
|
+
| Consultorías científico-tecnológicas | 58.218 | 100 % | 100 % | sin autores en la página | |
|
|
202
|
+
| Apropiación social del conocimiento (4 secciones) | 32.186 | 100 % | 100 % | sin autores en la página | |
|
|
203
|
+
| Obras o productos | 23.026 | 94 % | 100 % | sin autores en la página | |
|
|
204
|
+
| Integrantes del grupo | 301.377 | | | | |
|
|
205
|
+
|
|
206
|
+
"Autores que son integrantes" cuenta personas de "Autores:" (en tesis y jurados también estudiantes, que pocas veces son integrantes). "Con afiliación al grupo" cuenta ítems con al menos un integrante cuyo periodo contiene el año del ítem. Las secciones Guías de práctica clínica y Proyectos de ley ponen una fila de encabezado vacía antes de sus ítems (868 ítems en total); se leen como parte de su sección.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.24", "hatch-vcs>=0.4"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "gruplac-json"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Turn a research group's public GrupLAC page (Minciencias, Colombia) into one JSON document, in the cvlac-json schema, with member affiliations and Scienti ids."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
authors = [{ name = "Diego Restrepo", email = "restrepo@udea.edu.co" }]
|
|
14
|
+
keywords = ["gruplac", "cvlac", "scienti", "minciencias", "colombia", "bibliometrics", "cris", "impactu", "research groups"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Intended Audience :: Science/Research",
|
|
19
|
+
"Natural Language :: Spanish",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
23
|
+
"Topic :: Scientific/Engineering :: Information Analysis",
|
|
24
|
+
"Typing :: Typed",
|
|
25
|
+
]
|
|
26
|
+
dependencies = ["cvlac-json>=0.7"] # shares the record schema, ROR and Scienti helpers
|
|
27
|
+
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
dev = ["pytest>=8", "pytest-cov>=5", "ruff==0.17.3", "build>=1.2", "twine>=5"]
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
gruplac-json = "gruplac_json.cli:main"
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://github.com/restrepo/gruplac-json"
|
|
36
|
+
Repository = "https://github.com/restrepo/gruplac-json"
|
|
37
|
+
Issues = "https://github.com/restrepo/gruplac-json/issues"
|
|
38
|
+
Changelog = "https://github.com/restrepo/gruplac-json/blob/main/CHANGELOG.md"
|
|
39
|
+
|
|
40
|
+
# Version from the git tag (v0.1.0 -> 0.1.0); commits after a tag get 0.1.1.devN
|
|
41
|
+
[tool.hatch.version]
|
|
42
|
+
source = "vcs"
|
|
43
|
+
|
|
44
|
+
[tool.hatch.version.raw-options]
|
|
45
|
+
local_scheme = "no-local-version" # PyPI and TestPyPI reject local versions (+g1234abc)
|
|
46
|
+
|
|
47
|
+
[tool.hatch.build.targets.sdist]
|
|
48
|
+
include = ["src/", "tests/", "docs/", "README.md", "CHANGELOG.md", "LICENSE"]
|
|
49
|
+
|
|
50
|
+
[tool.hatch.build.targets.wheel]
|
|
51
|
+
packages = ["src/gruplac_json"]
|
|
52
|
+
|
|
53
|
+
[tool.pytest.ini_options]
|
|
54
|
+
testpaths = ["tests"]
|
|
55
|
+
addopts = "-ra --strict-markers"
|
|
56
|
+
|
|
57
|
+
[tool.coverage.run]
|
|
58
|
+
source = ["gruplac_json"]
|
|
59
|
+
branch = true
|
|
60
|
+
|
|
61
|
+
[tool.ruff]
|
|
62
|
+
line-length = 130
|
|
63
|
+
target-version = "py310"
|
|
64
|
+
src = ["src", "tests"]
|
|
65
|
+
|
|
66
|
+
[tool.ruff.lint]
|
|
67
|
+
select = ["E", "F", "W", "I", "B", "UP", "SIM", "RUF"]
|
|
68
|
+
ignore = [
|
|
69
|
+
"E731", # small lambdas assigned to names
|
|
70
|
+
"SIM108", # ternaries are not always clearer
|
|
71
|
+
"RUF001", "RUF002", "RUF003", # Spanish text with accents and typographic quotes
|
|
72
|
+
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""gruplac-json: turn a public GrupLAC page (Minciencias, Colombia) into one JSON document.
|
|
2
|
+
|
|
3
|
+
>>> from gruplac_json import extract
|
|
4
|
+
>>> data = extract("COL0008423") # downloads the page; Scienti ids if an apis.colav.co key is set
|
|
5
|
+
>>> data["name"], len(data["members"]), len(data["works"])
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
__version__ = version("gruplac-json")
|
|
12
|
+
except PackageNotFoundError: # running from a source tree that was never installed
|
|
13
|
+
__version__ = "0.0.0"
|
|
14
|
+
|
|
15
|
+
from .parser import build, extract, fetch, resolve
|
|
16
|
+
|
|
17
|
+
__all__ = ["__version__", "build", "extract", "fetch", "resolve"]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Command line entry point: `gruplac-json`."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import gzip
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
from . import __version__
|
|
9
|
+
from .parser import decode, extract, fetch, resolve
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main(argv=None):
|
|
13
|
+
ap = argparse.ArgumentParser(
|
|
14
|
+
prog="gruplac-json",
|
|
15
|
+
description="Build a JSON from a research group's public GrupLAC page (Minciencias, Colombia)",
|
|
16
|
+
)
|
|
17
|
+
ap.add_argument("group", help="COL code (COL0008423) or GrupLAC number (00000000001676; leading zeros optional)")
|
|
18
|
+
ap.add_argument("-o", "--output", help="output file (default gruplac_<COL or number>.json; '-' for stdout)")
|
|
19
|
+
ap.add_argument("--html", help="parse a saved page (.html or .html.gz) instead of downloading it")
|
|
20
|
+
ap.add_argument("--save-html", help="also save the downloaded page here")
|
|
21
|
+
ap.add_argument("--scienti", choices=["auto", "off"], default="auto", help="add Scienti ids (needs an apis.colav.co key)")
|
|
22
|
+
ap.add_argument("--institution", help="Scienti dump (udea, univalle, uec, unaula); default: try them in turn")
|
|
23
|
+
ap.add_argument("--model-year", help="Scienti model year (default: the dump's latest)")
|
|
24
|
+
ap.add_argument("--apikey", help="apis.colav.co key (else $COLAV_APIKEY or ~/.config/colav/apikey)")
|
|
25
|
+
ap.add_argument("--ror", choices=["auto", "off"], default="auto", help="look institutions up in the ROR registry")
|
|
26
|
+
ap.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
|
|
27
|
+
a = ap.parse_args(argv)
|
|
28
|
+
log = lambda *x: print(*x, file=sys.stderr)
|
|
29
|
+
try:
|
|
30
|
+
nro, col = resolve(a.group)
|
|
31
|
+
except ValueError as e:
|
|
32
|
+
ap.error(str(e))
|
|
33
|
+
if a.html:
|
|
34
|
+
with open(a.html, "rb") as fh:
|
|
35
|
+
raw = fh.read()
|
|
36
|
+
html = decode(gzip.decompress(raw) if raw[:2] == b"\x1f\x8b" else raw)
|
|
37
|
+
else:
|
|
38
|
+
html = fetch(nro)
|
|
39
|
+
if a.save_html:
|
|
40
|
+
with open(a.save_html, "w", encoding="latin-1", errors="xmlcharrefreplace") as fh: # as the page declares
|
|
41
|
+
fh.write(html)
|
|
42
|
+
data = extract(
|
|
43
|
+
col or nro,
|
|
44
|
+
html=html,
|
|
45
|
+
scienti=a.scienti,
|
|
46
|
+
institution=a.institution,
|
|
47
|
+
model_year=a.model_year,
|
|
48
|
+
apikey=a.apikey,
|
|
49
|
+
ror=a.ror == "auto",
|
|
50
|
+
log=log,
|
|
51
|
+
)
|
|
52
|
+
out = a.output or f"gruplac_{col or nro}.json"
|
|
53
|
+
text = json.dumps(data, ensure_ascii=False, indent=1)
|
|
54
|
+
if out == "-":
|
|
55
|
+
print(text)
|
|
56
|
+
else:
|
|
57
|
+
with open(out, "w", encoding="utf-8") as fh:
|
|
58
|
+
fh.write(text + "\n")
|
|
59
|
+
c = data["counts"]
|
|
60
|
+
log(
|
|
61
|
+
f"{out}: {data['name']} - {c['members']} members, {c['works']} works, {c['projects']} projects, "
|
|
62
|
+
f"{c['events']} events, {sum(len(v) for v in data['other_products'].values())} other products"
|
|
63
|
+
)
|
|
64
|
+
return 0
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
if __name__ == "__main__":
|
|
68
|
+
raise SystemExit(main())
|