-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPRI calculator.py
3450 lines (2678 loc) · 254 KB
/
PRI calculator.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -------------------------------------------------------------------- Importar paquetes-----------------------------------------------------------------------------------------------------------------------
import time #Paquete para medir el tiempo de ejecución del script
start_time = time.time() #Variable que guarda el momento de inicio del script
import pandas as pd #Paquete pandas para poder trabajar con tablas eficientemente
import re #Paquete para poder usar expresiones regulares
from functools import reduce #Paquete para consolidar todos los df finales de cada país
from pandas_ods_reader import read_ods #Paquete para leer archivos .ods
import numpy as np #Paquete numpy
import math #Paquete math
import pdftotext #Paquete para convertir archivos .pdf a .txt
import os #Paquete para extraer la ruta de la carpeta donde está el script
import openpyxl #Paquete para exportar los resultados a excel
import glob #Paquete para encontrar archivos de manera recursiva
from selenium import webdriver #Paquete para navegar de manera automática por internet
from datetime import date, timedelta #Paquete para importar la funciones de fechas
from dateutil.relativedelta import relativedelta #Paquete para funciones de fechas
from webdriver_manager.chrome import ChromeDriverManager #Paquete para utilizar chrome como navegador
from selenium.webdriver.common.by import By #Paquete para definir la forma de buscar elementos HTML en cada página
from selenium.webdriver.support.ui import WebDriverWait #Paquete para garantizar tiempos de espera entre descargas de páginas
from selenium.webdriver.support import expected_conditions as EC #Paquete para verificar conditioes en cada página
from selenium.webdriver.support.select import Select #Paquete para seleccionar elementos de las páginas web
from selenium.webdriver.common.action_chains import ActionChains #Paquete para hacer hover sobre elementos en una página
from selenium.common.exceptions import ElementNotInteractableException #Importar las excepciones de Selenium
from selenium.common.exceptions import TimeoutException #Importar las excepciones de Selenium
from selenium.common.exceptions import NoSuchElementException #Importar las excepciones de Selenium
from selenium.common.exceptions import ElementClickInterceptedException #Importar las excepciones de Selenium
from selenium.common.exceptions import StaleElementReferenceException #Importar las excepciones de Selenium
from selenium.common.exceptions import NoAlertPresentException #Importar las excepciones de Selenium
from bs4 import BeautifulSoup #Paquete para procesar data HTML
from send2trash import send2trash #Paquete para enviar archivos a la papelera de reciclaje
import tabula #Paquete para leer tablas de los .pdf
###########################################################################################################################################################################################
########################################################## Crear las funciones que usaremos #######################################################################################################
###########################################################################################################################################################################################
# 1) Función que limpia la información que no necesitamos y deja un conjunto de medicamentos dado
def limpiar_df(df,precio,ff):
"""Crea todas las columnas auxiliares que serán necesarias para el cálculo del PRI en cada país de referencia, si no han sido ecreadas aún.
Asigna valores a la columna de "FF", recibe como parámetro la columna donde se almacena la info. de la FF.
Elimina los precios <= 0 de la columna (precio).
Traduce los valores de la columna "PA" de acuerdo al diccionario (traductor) y conserva los valores incluidos dentro de la lista (medicamentos).
Finalmente ordena los valores por PA y FF, restableciendo el índice.
df: Data Frame
precio: str
ff: str"""
#Conjunto de palabras que identifican las formas farmacéuticas (FF)
tabletas = "TABL\s|FTBL|KAPS|TABB|TABR|TABMD|Tablett|Kapsel|Depottablett|Tablet|capsule|capsula|\stab|tab\s|\scap|cap\s|pwdr|pwdr|CPR|CPS|COMPRIMIDO|SUPP|BUST|COM\s|COMP\s|SOLIDO ORAL|SÓLIDO ORAL|CARAMELO|Cápsula|gélule|gelu|gastro|granulés|COMPRIMÉ|COMPRIME|Película bucal|CM REC|CONJUNTO"
inyectables = "PULV|RSUSP|INYECTABLE|INYECCI.N|infusjonsvæske|Injeksjonsvæske|suspensjon|injection|infusion|INFUSIÓN|inj|INJETÁVEL|syringe|powder|sir|pen|PO\sLIOF|PARENTERAL|PARENTAL|[*]EV|LIOFILIZADO|PERFUSION|Perfusión|RECONSTITUCIÓN|seringue|perf|I[.]\s*V[.]|IV[.]|JERINGA|AMP|SOLUCIONES Y SUSTANCIAS|AMPD|AMPT|AUGS"
parches = "Depotplaster|patch|[*]\d+CER|TRANSD|SACHE|parche|S.LIDO CUT.NEO|SACHÊ"
sol_oral = "DSTF|LSG|Mikstur|soln.oral|susp.oral|oral sol|SOLUZ|GTT|SOSP|[*]OS|SUS\sOR|SOL\sOR|LÍQUIDO ORAL|oral liquid|oral suspension|oral solution|SOL GOT OR|GOTAS|SOLUCION ORAL|Solución Oral|solution buvable|suspension buvable|Solução oral|SOL[.]ORAL|SUSPENSÃO ORAL"
nasal_spray = "soln.nasal|Nesespray|SPR NAS|nasal|NSPR"
lozenge = "lozenge|MUCOSA OS"
sublingual_spray = "SPRAY,SUBLINGUAL"
#Deja las columnas intactas si ya existen dentro del df
if set(['FF','UMC (mg)',"Quantity"]).issubset(df.columns):
df["FF"] = df["FF"]
df["UMC (mg)"] = df["UMC (mg)"]
df["Quantity"] = df["Quantity"]
#Crea las columnas auxiliares si no existen
else:
df["FF"] = ""
df["UMC (mg)"] = ""
df["Quantity"] = ""
#Asigna valores a la columna con la FF de acuerdo a las palabras definidas, si ya lleno el valor no entra a la siguiente línea
df.loc[(df[ff].str.contains(tabletas,flags=re.IGNORECASE, regex=True)) & (df["FF"]==""),"FF"] = "TAB"
df.loc[(df[ff].str.contains(inyectables,flags=re.IGNORECASE, regex=True)) & (df["FF"]==""),"FF"] = "INJ"
df.loc[(df[ff].str.contains(sol_oral,flags=re.IGNORECASE, regex=True)) & (df["FF"]==""),"FF"] = "SOL ORAL"
df.loc[(df[ff].str.contains(parches,flags=re.IGNORECASE, regex=True)) & (df["FF"]==""),"FF"] = "PATCH"
df.loc[(df[ff].str.contains(lozenge,flags=re.IGNORECASE, regex=True)) & (df["FF"]==""),"FF"] = "LOZENGE"
df.loc[(df[ff].str.contains(nasal_spray,flags=re.IGNORECASE, regex=True)) & (df["FF"]==""),"FF"] = "NASAL SPRAY"
df.loc[(df[ff].str.contains(sublingual_spray,flags=re.IGNORECASE, regex=True)) & (df["FF"]==""),"FF"] = "SUBLINGUAL SPRAY"
df["Precio UMC (mg)"] = "" #Crea la columna auxiliar con el precio por UMC (mg)
df[precio] = df[precio].astype(str) #Limpia la columna con el precio para evitar errores
df[precio] = df[precio].str.replace(" ","") #Eliminar espacios en el precio
df[precio] = df[precio].str.replace("$","").str.replace("€", "").str.replace("B/.","").str.replace("USD","") #Quitar texto de los precios
df[precio] = df[precio].str.replace(",",".") #Reemplazar comas por punto
for ind in df.index: #Eliminar puntos innecesarios, en caso de que se hayan creado en la parte anterior (puntos para expresar miles)
if df[precio][ind].count(".")==2:
df[precio][ind] = df[precio][ind].replace(".","", 1)
elif df[precio][ind].count(".")==3:
df[precio][ind] = df[precio][ind].replace(".","", 2)
df[precio] = df[precio].astype(float) #Volver a convertir el precio a float
#Eliminar precios cero o negativos
df.drop(df[df[precio]<= 0].index,axis=0, inplace=True)
#Traduce los PA de acuerdo al traductor y convserva los medicamentos relevantes definidos en los parámetros
df["PA"] = df["PA"].str.upper().replace(traductor)
df = df[df["PA"].isin(medicamentos)]
#Organiza el df de acuerdo a las columnas "PA" y "FF", finalmente reestablece el índice
df = df.sort_values(['PA',"FF"])
df.reset_index(inplace = True, drop=True)
#La función retorna un df "limpio" y con la información necesaria para poder calcular las UMC y cantidades de cada medicamento
return df
#2) Función que remplaza las "," por "." en un conjunto de columnas y después las convierte a flotante, para poder hacer cálculos. Finalmente convierte las unidades de paliperidona inyectable y fentanyl parche de acuerdo a su tasa de conversión especial
def ajustar_columnas(df, columnas):
"""Reemplaza las comas (,) dentro de las columnas especifcadas de un data frame (df) por un punto (.) y luego las convierte a tipo flotante. Arregla también Fentanyl parche y paliperidona inyectable
df: Data Frame
columnas: list[str]"""
for i in columnas:
df[i] = df[i].astype(str).str.replace(",",".").astype(float)
#Arreglar Fentanyl Parche y paliperidona inyectable de acuerdo a una tasa de conversion especial
df.loc[(df["PA"]=="FENTANYL") & (df["FF"]=="PATCH"), "UMC (mg)"] = df.loc[(df["PA"]=="FENTANYL") & (df["FF"]=="PATCH"), "UMC (mg)"].replace(fentanyl)
df.loc[(df["PA"]=="PALIPERIDONE") & (df["FF"]=="INJ"), "UMC (mg)"] = df.loc[(df["PA"]=="PALIPERIDONE") & (df["FF"]=="INJ"), "UMC (mg)"].replace(paliperidona)
#3) Función que crea un data frame "final" con los resultados agrupados por molécula
def final(df, precio, bd):
"""Agrupa los medicamentos por PA y FF para calcular el precio mínimo por UMC de cada uno de estos grupos.
Recibe como parámetros: un df (dataframe), el nombre de la columna (string) donde está reportado el precio y el nombre de la base de datos original (string)
df: Data Frame
precio: str
bd: str"""
df["Precio UMC (mg)"] = df[precio]/(df["UMC (mg)"]*df["Quantity"])
final = df.groupby(['PA', "FF"])["Precio UMC (mg)"].min().reset_index().rename(columns={"Precio UMC (mg)": bd})
final["PA"] = final["PA"] + " - " + final["FF"]
final.drop(columns=['FF'],inplace=True)
return final
#4) Función que identifica automáticamente el parámetro "skip rows" de los data frames importados de excel
def skip_rows(df):
"""Recibe como parámetro un data frame
df: data frame"""
#Hay data frames con columnas date-time y esto literalmente genera un error desconocido en spyder(¿?), es necesario eliminarlas para evitar errores
df = df.select_dtypes(exclude=['datetime64[ns]'])
df.dropna(axis=1,how="all",inplace=True)
df = df[df.columns[df.isnull().mean() < 0.95]] #Borrar columnas que tengan más del 95% de las filas con NaN para eliminar ruido del df
try:
if (True in df.columns.str.contains("unnamed", flags=re.IGNORECASE, regex=True))==True:
#Caso más general
if (df.count(axis = 1) >= df.shape[1]).idxmax() > 0:
first_row = (df.count(axis = 1) >= df.shape[1]).idxmax()
df.columns = df.loc[first_row]
df = df.loc[first_row+1:]
#Caso menos general
elif df.count(axis = 1).idxmax() > 0:
first_row = df.count(axis = 1).idxmax()
df.columns = df.loc[first_row]
df = df.loc[first_row+1:]
#Casos particular en el cual es necesario "saltar" una sola columna
else:
first_row = 0
df.columns = df.loc[first_row]
df = df.loc[first_row+1:]
return df
except AttributeError:
return df
#5) Función que convierte en Data Frame la información de monedas extranjeras del Banco de la República
def tasas_de_cambio(source, t0, t1):
"""Recibe como parámetros la fuente de la página (source) y dos fechas tipo texto que indican una ventana de tiempo.
Siendo (t0) la fecha inicial y (t1) la fecha final.
Retorna un data frame con la info correspondiente a cada divisa en la venta de tiempo escogida.
source: str
t0, t1: str"""
#Crear la tabla con base a los elementos HTML
soup = BeautifulSoup(source, 'html.parser')
tables = soup.find_all("table")
table = tables[0]
tab_data = [[cell.text for cell in row.find_all(["th","td"])]
for row in table.find_all("tr")]
#Crear el data frame
df = pd.DataFrame(tab_data)
#Limpiar el dataframe
df = df.iloc[:,1:len(monedas)+2]
#Crear el encabezado del data frame
df.columns = ["FECHA"] + monedas
#Conservar la data de las fechas de interés
df = df.iloc[df[df["FECHA"]==t0].index.values[0]:df[df["FECHA"]==t1].index.values[0]+1,:].dropna()
#Reemplazar comas por puntos
df = df.apply(lambda x: x.str.replace(',','.'))
#Convertir la fecha de texto a tipo date
df['FECHA'] = pd.to_datetime(df['FECHA'], format='%d/%m/%Y').dt.date
#Reemplazar valores vacíos por NaN
df = df.replace(r'^\s*$', np.NaN, regex=True)
#Convertir las tasas a tipo flotante
df[monedas] = df[monedas].astype(float)
return df
#6) Función que genera un tiempo de espera en la ejecución del script acutal, hasta que las descargas de Chrome finalicen.
def download_wait(directory, timeout, nfiles=None):
"""Args: directory : str (The path to the folder where the files will be downloaded)
timeout : int (How many seconds to wait until timing out)
nfiles : int, defaults to None (If provided, also wait for the expected number of files)."""
seconds = 0
dl_wait = True
while dl_wait and seconds < timeout:
time.sleep(1)
dl_wait = False
files = os.listdir(directory)
if nfiles and len(files) != nfiles:
dl_wait = True
for fname in files:
if fname.endswith('.crdownload'):
dl_wait = True
seconds += 1
return seconds
#7) Función que borra versiones anteriores de archivos en el directorio de trabajo, buscándolos de acuerdo a una expresión regular en la lista de "archivos".
def borrar(archivos):
"""archivos: list[str]"""
for archivo in archivos:
for filename in os.listdir(carpeta):
if re.search(archivo, filename):
send2trash(filename)
#8) Función que renombra archivos en el directorio de trabajo, buscándolos de acuerdo a una expresión regular "archivo".
def renombrar(archivo,nuevo_nombre):
"""archivo: str
nuevo_nombre: str"""
for filename in os.listdir(carpeta):
if re.search(archivo,filename):
os.rename(filename,nuevo_nombre)
#9) Función que regresa una lista con todos los archivos encontrados en el directorio de trabajo de acuerdo a una expresión regular "archivo".
def buscar_archivo(archivo):
"""archivo: str"""
lista = []
for filename in os.listdir(carpeta):
if re.findall(archivo,filename):
lista.append(filename)
return lista
#10) Función que regresa el archivo más reciente en el directorio de trabajo
def archivo_reciente():
list_of_files = glob.glob(carpeta + "/*")
latest_file = max(list_of_files, key=os.path.getctime)
return latest_file
#11) Función que borra archivos vacíos del directorio de trabajo
def borrar_empty():
for filename in os.listdir(carpeta):
if os.path.getsize(filename) == 0:
send2trash(filename)
###########################################################################################################################################################################################
########################################################## Definir los parámetros de la calculadora #######################################################################################################
###########################################################################################################################################################################################
#Carpeta donde esta el script de la calculadora, en esta ruta guardaremos todos nuestros resultados
carpeta = os.getcwd() +"\\"
#Usaremos estos encabezados para evitar posibles problemas a la hora de descargar los archivos de manera automática
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0", "Accept-Encoding": "*", "Connection": "keep-alive"}
#Definir los parámetros del navegador de Google Chrome, el cual usaremos para hacer consultas en diversas fuentes de internet.
chromeOptions = webdriver.ChromeOptions()
prefs = {"profile.default_content_setting_values.notifications" : 2, "download.default_directory" : carpeta, "download.prompt_for_download": False,"download.directory_upgrade": True, "plugins.always_open_pdf_externally": True}
chromeOptions.add_experimental_option("prefs",prefs)
#------------------------------------------------------------------ URL -----------------------------------------------------------------------------------------------------------------------
#Definir los url y los respectivos países donde están las bases de datos
url = pd.read_excel(carpeta + "Parámetros.xlsx", sheet_name = "URL")
url["PAÍS"] = url["PAÍS"].str.lower()
#------------------------------------------------------------------------ TRADUCCION ----------------------------------------------------------------------------------------------------------------------------
#Definir el diccionario con los parámetros para traducir
traductor = pd.read_excel(carpeta + "Parámetros.xlsx",sheet_name="TRADUCTOR")
traductor = dict(zip(traductor["TRADUCCIÓN"],traductor["PA"]))
#------------------------------------------------------------------------ MEDICAMENTOS ----------------------------------------------------------------------------------------------------------------------------
#Definir los medicamentos a consultar
medicamentos = pd.read_excel(carpeta + "Parámetros.xlsx",sheet_name="MEDICAMENTOS")
#Definimos un diccionario que mapea los valores del nombre comercial al principio activo en inglés
comercial_pa = dict(zip(medicamentos["NOMBRE COMERCIAL"], medicamentos["MOLECULE"]))
#Definimos un diccionario que mapea los valores del nombre de la molécula en portugues al principio activo en inglés
traductor_por = dict(zip(medicamentos["MOLECULA (POR)"], medicamentos["MOLECULE"]))
#Definimos un diccionario que mapea los valores del nombre de la molécula en español al principio activo en inglés
traductor_esp = dict(zip(medicamentos["MOLECULA (ESP)"], medicamentos["MOLECULE"]))
#Creamos una lista con los nombres comerciales de los medicamentos a consultar (LATAM y EUROPA)
marca_medicamentos = medicamentos.drop(medicamentos[medicamentos["INCLUIR"]!="X"].index, axis=0)["NOMBRE COMERCIAL"].values.tolist() #LATAM
marca_medicamentos_eur = medicamentos.drop(medicamentos[medicamentos["INCLUIR"]!="X"].index, axis=0)["NOMBRE COMERCIAL (EUR)"].values.tolist() #EUR
#Creamos una lista con los nombres de la moléculas en español a consultar
medicamentos_esp = medicamentos.drop(medicamentos[medicamentos["INCLUIR"]!="X"].index, axis=0)["MOLECULA (ESP)"].values.tolist()
#Creamos una lista de tuples con la marca del medicamentos y el nombre de la molécula en español
medicamentos_per = list(zip(marca_medicamentos, medicamentos_esp))
medicamentos_esp = list(set(medicamentos_esp)) #Borrar posibles duplicados para no repetir el nombre de las moléculas
#Creamos una lista con los nombres de la moléculas en español a consultar
medicamentos_por = medicamentos.drop(medicamentos[medicamentos["INCLUIR"]!="X"].index, axis=0)["MOLECULA (POR)"].values.tolist()
#Creamos una lista con los nombres de la moléculas en inglés a consultar
medicamentos = medicamentos.drop(medicamentos[medicamentos["INCLUIR"]!="X"].index, axis=0)["MOLECULE"].values.tolist()
#Creamos una lista de tuples con la molécula y la marca del medicamento (eur)
medicamentos_fr = list(zip(medicamentos,marca_medicamentos_eur))
#--------------------------------------------------------------------- FENTANYL (PARCHE) ---------------------------------------------------------------------------------------------------------------------------------------
#Durogesic tiene una tasa de conversión especial por ser un parche (mcg/h a mg):
fentanyl = {0.012:2.1, 0.025:4.2, 0.037:6.3, 0.0375:6.3, 0.05:8.4, 0.0625:10.5, 0.075:12.6, 0.0875:14.7, 0.1:16.8}
#--------------------------------------------------------------------- PALIPERIDONA (INYECTABLE) ---------------------------------------------------------------------------------------------------------------------------------------
#la paliperidona inyectable (trinza e invega) tienen una tasa de conversión especial de palmitato de paliperidona a paliperidona:
invega = {39:25, 78:50, 117:75, 156:100, 234:150}
trinza = {273:175 ,410:263, 546:350, 819:525}
paliperidona = {**invega, **trinza}
#----------------------------------------------------------------- DIVISAS EXTRANJERAS ----------------------------------------------------------------------------------------------------------------------------------------
#Código ISO de las monedas locales en cada uno de los países de referencia
monedas = ["ARS","AUD","BRL","CAD","CLP","EUR","GBP","MXN","NOK","PEN","UYU"] #BanRep las ordena en orden alfabético de acuerdo al ISO
#---------------------------------------------------------------- PERIODO DE REFERENCIA ----------------------------------------------------------------------------------------------------------------------------------------
#Definir las medicamentos a consultar utilizando la pestaña FECHAS
periodo = pd.read_excel(carpeta + "Parámetros.xlsx",sheet_name="FECHAS")
#Definir la ventana tiempo con las siguientes fechas: actual (today), un día menos (yesterday) y con un año menos (last_year)
#Asignar valores a today
try:
if math.isnan(periodo["VALORES"][1]): #Si la fecha está vacía, asignar la fecha de hoy
today = date.today()
except TypeError:
today = periodo["VALORES"][1].date() #De lo contrario utilizar el valor de la fila
#Asignar valores a last_year
try:
if math.isnan(periodo["VALORES"][0]): #Si la fecha está vacía, asignar la fecha de hoy con un año menos
last_year = date.today().replace(date.today().year - 1)
except TypeError:
last_year = periodo["VALORES"][0].date() #De lo contrario utilizar el valor de la fila
#Asignar valores a yesterday (today con un día menos)
yesterday = today - timedelta(days=1)
#Convertir las fechas a string con formato %d/%m/%Y
today_str = today.strftime('%d/%m/%Y')
yesterday_str = yesterday.strftime('%d/%m/%Y')
last_year_str = last_year.strftime('%d/%m/%Y')
#Obtener el año de las fechas (en tipo str)
año_inicial = str(today.year)
año_final = str(last_year.year)
#####################################################################################################################################################################
############################################################## Descargar bases de datos de internet #################################################################
#####################################################################################################################################################################
#Inicializar el navegador de Google Chrome y configurar la carpeta de descargas usando la carpeta del script
driver = webdriver.Chrome(ChromeDriverManager().install(),chrome_options=chromeOptions)
########################################################################################################################################################################
#------------------------------------------------------------- CREAR LOS DATA FRAMES DE CADA PAÍS ---------------------------------------------------------------------
##########################################################################################################################################################################
#Usamos este bucle para importar los archivos a nuestra carpeta de trabajo
for ind in url.index:
borrar(["crdownload"])
#Crear data frames con los archivos existentes (excel u .ods) de cada país en caso de que no hayn sido seleccionados por el usuario
if url["INCLUIR"][ind]!= "X":
for pais in buscar_archivo(url["PAÍS"][ind]):
#Crear cada variable dinámicamente, de acuerdo al nombre del archivo de Excel
nombre = pais[:pais.find(".")]
if pais.find(".xls")!= -1:
vars()[nombre] = skip_rows(pd.read_excel(pais))
elif pais.find(".ods")!= -1:
vars()[nombre] = skip_rows(read_ods(pais, sheet = 1))
############################################################ BASES DE DATOS CON FUENTES DESCARGABLES ###################################################################################
#--- Buscar la info. de los países seleccionados por el usuario usando el navegador de Chrome ------------------------------------------------------------------------------------------
########################################################################################################################################################################################
elif url["PAÍS"][ind]=="aus" and url["INCLUIR"][ind]=="X": #PBS (AUS) -------------------------------------------------------------------------------------------------------------------------------------------
borrar(["aus","manufacturer"]) #################################################################################################################################################
driver.get(url["URL"][ind])
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.PARTIAL_LINK_TEXT, 'Efficient Funding of Chemotherapy')))
driver.find_element_by_partial_link_text('Efficient Funding of Chemotherapy').click()
driver.find_element_by_partial_link_text('excluding Efficient Funding of Chemotherapy').click()
download_wait(directory = carpeta, timeout = 60*5)
renombrar("non-efc","aus.xlsx")
renombrar("prices-efc","aus1.xlsx")
aus = skip_rows(pd.read_excel("aus.xlsx"))
aus1 = skip_rows(pd.read_excel("aus1.xlsx"))
############################################################################################################################################################################################
elif url["PAÍS"][ind]=="bra" and url["INCLUIR"][ind]=="X": #ANVISA (BRA) --------------------------------------------------------------------------------------------------------------------------------------------
borrar(["bra",'conformidade']) #####################################################################################################################################################
driver.get(url["URL"][ind])
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.XPATH, '//a[contains(@href,"conformidade")]')))
try: #Aceptar los cookies de la página
driver.find_element_by_xpath('//button[contains(.,"ACEITO")]').click()
except:
pass
driver.find_element_by_xpath('(//a[contains(@href,"xls")])[1]').click()
download_wait(directory = carpeta, timeout = 60*20)
renombrar("conformidade","bra.xls")
bra = skip_rows(pd.read_excel("bra.xls"))
driver.find_element_by_xpath('(//a[contains(@href,"xls")])[2]').click()
download_wait(directory = carpeta, timeout = 60*20)
renombrar("conformidade","bra1.xls")
bra1 = skip_rows(pd.read_excel("bra1.xls"))
#############################################################################################################################################################################
elif url["PAÍS"][ind]=="can" and url["INCLUIR"][ind]=="X": #RAMQ (CAN) -------------------------------------------------------------------------------------------------------------------------------
borrar(["can",'liste']) #############################################################################################################################################
driver.get(url["URL"][ind])
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.PARTIAL_LINK_TEXT, 'Liste des médicaments')))
driver.find_element_by_partial_link_text('Liste des médicaments').click()
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.CLASS_NAME, 'file-download')))
driver.find_element_by_class_name('file-download').click()
download_wait(directory = carpeta, timeout = 60*10)
renombrar("liste","can.pdf")
#############################################################################################################################################################################
elif url["PAÍS"][ind]=="ger" and url["INCLUIR"][ind]=="X": #DIMDI (GER) -------------------------------------------------------------------------------------------------------------------------------
borrar(["ger",'festbetraege']) #############################################################################################################################################
driver.get(url["URL"][ind])
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.XPATH, "//*[@onclick ='setCookieAndHide()']")))
driver.find_element_by_xpath("//*[@onclick ='setCookieAndHide()']").click()
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.XPATH, '//a[contains(@href,"pdf")]')))
driver.find_element_by_xpath('//a[contains(@href,"pdf")]').click()
download_wait(directory = carpeta, timeout = 60*10)
renombrar("festbetraege","ger.pdf")
###############################################################################################################################################################################################
elif url["PAÍS"][ind]=="ecu" and url["INCLUIR"][ind]=="X": #CONSEJO DE FIJACIÓN DE PRECIOS (ECU) -----------------------------------------------------------------------------------------------------------------------
borrar(["ecu[.]",'onsolidado']) ##########################################################################################################################################################
driver.get(url["URL"][ind])
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.XPATH, "//a[contains(@href,'onsolidado')]")))
driver.find_element_by_xpath('//a[contains(@href,"onsolidado")]').click()
while True:
try:
download_wait(directory = carpeta, timeout = 60*10)
renombrar("onsolidado","ecu.xls")
ecu = skip_rows(pd.read_excel("ecu.xls"))
break
except FileNotFoundError:
time.sleep(1)
continue
##############################################################################################################################################################################################
elif url["PAÍS"][ind]=="nor" and url["INCLUIR"][ind]=="X": #NOMA (NOR) ------------------------------------------------------------------------------------------------------------------------------------------------
borrar(["nor","ackage prices"]) ######################################################################################################################################################
driver.get(url["URL"][ind])
while True:
try:
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.XPATH, '//a[contains(.,"reimbursement list")]')))
driver.find_element_by_xpath('//a[contains(.,"reimbursement list")]').click()
download_wait(directory = carpeta, timeout = 60*10)
renombrar("ackage prices","nor.xlsx")
nor = skip_rows(pd.read_excel("nor.xlsx"))
break
except (ElementClickInterceptedException, FileNotFoundError):
time.sleep(1)
continue
##############################################################################################################################################################################################
elif url["PAÍS"][ind]=="uk" and url["INCLUIR"][ind]=="X": #eMIT (UK) --------------------------------------------------------------------------------------------------------------------------------------------------
borrar(["uk",'eMIT']) ################################################################################################################################################################
driver.get(url["URL"][ind])
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.LINK_TEXT, 'eMIT national database')))
driver.find_element_by_link_text('eMIT national database').click()
download_wait(directory = carpeta, timeout = 60*10)
renombrar("eMIT","uk.ods")
uk = skip_rows(read_ods("uk.ods", sheet = 1))
##############################################################################################################################################################################################
elif url["PAÍS"][ind]=="nhs" and url["INCLUIR"][ind]=="X": #NHS (UK) --------------------------------------------------------------------------------------------------------------------------------------------------
borrar(["nhs",'Drug Tariff']) ################################################################################################################################################################
driver.get(url["URL"][ind])
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.ID, 'ccc-close')))
driver.find_element_by_id('ccc-close').click()
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.XPATH, '//*[contains(@href, "pdf")]')))
driver.find_element_by_xpath('//*[contains(@href, "pdf")]').click()
download_wait(directory = carpeta, timeout = 60*10)
renombrar("Drug Tariff","nhs.pdf")
#############################################################################################################################################################################################
elif url["PAÍS"][ind]=="eeuu" and url["INCLUIR"][ind]=="X": #FSS (EEUU) ----------------------------------------------------------------------------------------------------------------------------------------------
borrar(["eeuu","FssPharmPrices"]) ###################################################################################################################################################
driver.get(url["URL"][ind])
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.LINK_TEXT, 'pricing data')))
driver.find_element_by_link_text('pricing data').click()
download_wait(directory = carpeta, timeout = 60*10)
renombrar("FssPharmPrices","eeuu.xlsx")
eeuu = skip_rows(pd.read_excel("eeuu.xlsx"))
#############################################################################################################################################################################################
elif url["PAÍS"][ind]=="esp" and url["INCLUIR"][ind]=="X": #PETRONE (ESP) --------------------------------------------------------------------------------------------------------------------------------------------
borrar(["esp","ESH","ITH"]) #########################################################################################################################################################
driver.get(url["URL"][ind])
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.XPATH, "//a[@href = '/xpet/media/ESH.xls']")))
driver.find_element_by_xpath("//a[@href = '/xpet/media/ESH.xls']").click()
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.XPATH, "//a[@href = '/xpet/media/ITH.xls']")))
driver.find_element_by_xpath("//a[@href = '/xpet/media/ITH.xls']").click()
download_wait(directory = carpeta, timeout = 60*10)
renombrar("ESH","esp.xls")
renombrar("ITH","esp1.xls")
esp = skip_rows(pd.read_excel("esp.xls"))
esp1 = skip_rows(pd.read_excel("esp1.xls"))
######################################################################################################################################################################################
################################################################## BASES DE DATOS DE CONSULTA ONLINE #################################################################################
######################################################################################################################################################################################
elif url["PAÍS"][ind] == "per" and url["INCLUIR"][ind]=="X": #DIGEMID (PER) ----------------------------------------------------------------------------------------------------
per = pd.DataFrame() #df donde se guardará toda la info. consolidada #########################################################################################################
for medicamento in medicamentos_per: #Iterar sobre los medicamentos de interés
i_inicial = 1
m_inicial = 0
while True:
try:
driver.get(url["URL"][ind]) #Ingresar a la página de DIGEMID
driver.maximize_window()
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.ID, 'btnBuscar'))) #Esperar a que los elementos de la página sean clickeables
siguiente = False
for m in range(m_inicial,2):
driver.find_element_by_id('txtBuscador').clear() #Borrar los elementos de la lista de búsqueda
driver.find_element_by_id('txtBuscador').send_keys(medicamento[m]) #Ingresar el nombre del medicamento
time.sleep(3) #Esperar a que carguen los elementos de la lista desplegable
total = len(driver.find_elements_by_xpath("//*[@class = 'ui-menu-item']"))
if total > 0: #Verificar si el medicamento existe en la base de datos
break
elif m==1: #Si el medicamento no existe, intentar con el nombre de la molécula
siguiente = True
if siguiente == True:
break #Salimos del while infinito si no existe el medicamento ni por nombre comercial ni por PA
for i in range(i_inicial, total+1): #Iterar sobre el total de resultados
validar = False
while True: #Crear una espera dinámica hasta que se despliguen nuevamente todos los elementos de la lista
try:
driver.find_element_by_xpath("(//*[@class = 'ui-menu-item'])" + "["+ str(i) + "]").click()
break
except (NoSuchElementException, ElementClickInterceptedException):
time.sleep(1)
continue
id_medicamento = driver.find_element_by_id('txtBuscador').get_attribute('value')
if re.search("/\s*ml" , id_medicamento , flags = re.IGNORECASE) is not None:
validar = True #Si el medicamento está en XXMG/ML es necesario validar la cantidad de ML totales
driver.find_element_by_id("btnBuscar").click()
try: #Hay medicamentos que aparecen en la lista despegable pero después de dar click la página aparece vacía (error de DIGEMID)
#Exportar todos los resultados de la búsqueda a un archivo de excel
WebDriverWait(driver, 40).until(EC.visibility_of_element_located((By.XPATH, "//*[@class = 'dataTables_info']"))) #Esperar a que carguen los elementos de la página
while True: #Crear un espera dinámica hasta que se desplieguen los resultados
resultados = driver.find_element_by_xpath("//*[@class = 'dataTables_info']").text
if re.search("\d" , resultados) is not None:
break
else:
time.sleep(1)
continue
if resultados == "Mostrando 0 a 0 de 0 registros": #Si la búsqueda arroja cero resultados
driver.get(url["URL"][ind]) #Volver a la pagína inicial para continuar iterando
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.ID, 'btnBuscar')))
driver.find_element_by_id('txtBuscador').send_keys(medicamento[m])
continue
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[contains(@href, 'exportar')]")))
driver.find_element_by_xpath("//a[contains(@href, 'exportar')]").click() #Dar click en exportar
download_wait(directory = carpeta, timeout = 60*10) #Esperar a que se descargue el elemento
per1 = skip_rows(pd.read_excel(archivo_reciente())) #leer el excel dentro de un df
per1.dropna(inplace = True) #Borrar filas con valores vacíos
per1.reset_index(drop = True , inplace = True) #Resetear índice
per1["indice"] = per1.index + 1 #Guardar la posición del medicamento dentro del resultado de la búsqueda
#Eliminar duplicados
per1.drop_duplicates(subset = ["Nombre de Producto","Precio Unit","Titular"], inplace = True)
per1.reset_index(drop = True , inplace = True) #Resetear el índice
per1["PA"] = driver.find_element_by_xpath('//span[contains(@id, "PA")]').text #Asignar a la columna "PA" el principio activo del medicamento
per1["Cantidades"] = 1 #Asignar un valor default de 1 para las cantidades
for k in per1.index: #Iterar sobre el df auxiliar para llenar los ML de los medicamentos que necesitan ser validados
if (validar == True) and (per1["indice"][k]<=150): #Si es necesario validar, hacerlo máximo hasta el resultado 150
#Buscar el link con los detalles del producto
WebDriverWait(driver, 40).until(EC.element_to_be_clickable((By.XPATH, "(//*[contains(@href ,'FichaProducto')])[" + str(per1["indice"][k]) + "]")))
ventana_1 = driver.window_handles[0] #Guardamos la ventana principal (ventana 1)
#Hacemos click en el hipervínculo (hiper)
hiper = driver.find_element_by_xpath("(//*[contains(@href ,'FichaProducto')])[" + str(per1["indice"][k]) + "]")
driver.execute_script('arguments[0].scrollIntoView()', hiper) #Hacemos scroll para hacer visible el hiperviculo y que no ocurra un error (¿?)
hiper.click()
ventana_2 = driver.window_handles[1] #Guardamos la ventana auxiliar (ventana 2)
driver.switch_to.window(ventana_2) #Cambiamos a la ventana 2
WebDriverWait(driver, 40).until(EC.visibility_of_element_located((By.TAG_NAME, "body"))) #Esperamos a que cargue el contenido
detalle = driver.find_element_by_tag_name('body').text #Guardar la info. de la ficha del producto
per1["Cantidades"][k] = detalle #Escribir esto en el df auxiliar
driver.close() #Cerrar la ventana auxiliar
driver.switch_to.window(ventana_1) #Cambiamos a la ventana 1
#Extraer la info.con los ML de todo el BODY de acuerdo con una expresión regular
if re.search("[\d,.]+\s*ml", per1["Cantidades"][k], flags = re.IGNORECASE) is not None:
per1["Cantidades"][k] = re.search("[\d,.]+", re.search("[\d,.]+\s*ml", per1["Cantidades"][k], flags = re.IGNORECASE).group()).group()
else: #Si no la encuentra asignamos un valor por defecto de 1
per1["Cantidades"][k] = "1"
elif (validar == True) and (per1["indice"][k]>150):
per1["Cantidades"][k] = "" #Para los resultados > 150, cogeremos la info. de los medicamentos anteriores
per = per.append(per1) #Unir el df auxiliar con el df principal
#Mandar a la papelera de reciclaje el excel descargado para no llenar innecesariamente de archivos nuestro wd
send2trash(archivo_reciente())
except TimeoutException: #Dejamos pasar la excepción para errores en la página de DIGEMID
pass
driver.get(url["URL"][ind]) #Volver a la pagína inicial para continuar iterando
WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.ID, 'btnBuscar')))
driver.find_element_by_id('txtBuscador').send_keys(medicamento[m])
except TimeoutException:
i_inicial = i
m_inicial = m
driver.close()
driver = webdriver.Chrome(ChromeDriverManager().install(),chrome_options=chromeOptions) #Inicializamos otra ventana
continue #Reiniciamos la búsqueda PERO empezando desde i-inicial y m-inicial
break #Si todo sale bien llegamos a esta línea saliendo del loop y continuando con el siguiente medicamento de la lista
per.drop_duplicates(subset=['Nombre de Producto','Titular', 'Precio Unit'], inplace=True) #Eliminar duplicados
per.reset_index(drop = True, inplace = True) #Resetear el ínidice
per.to_excel("per.xlsx" , index = False) #Exportar df a excel
#########################################################################################################################################################################################
elif url["PAÍS"][ind]=="arg" and url["INCLUIR"][ind]=="X": #ANMAT (ARG) -------------------------------------------------------------------------------------------------------------
arg = pd.DataFrame() #Crear df prinicipal #######################################################################################################################################
driver.get(url["URL"][ind]) #Ingresar a la página de ANMAT
WebDriverWait(driver, 25).until(EC.visibility_of_element_located((By.CLASS_NAME, "z-textbox"))) #Esperar a que carguen los elementos de la página
for medicamento in medicamentos_esp: #Iterar sobre los medicamentos de interés
pagina = 1
terminar = False
while True:
try: #Crear una espera dinámica en caso de que ocurra la siguiente excepción
driver.find_element_by_id('zk_comp_81').click() #Borrar búsqueda anterior
time.sleep(2)
#Iniciar nueva búsqueda
buscar= driver.find_element_by_class_name('z-textbox')
buscar.clear() #Borrar el texto en la barra de búsquda
buscar.send_keys(medicamento) #Ingresar el nombre del medicamento en la barra de búsqueda
driver.find_element_by_id("zk_comp_80").click()
break
except ElementClickInterceptedException:
time.sleep(1)
continue
time.sleep(12)
#Revisar si la búsqueda arrojo resultados y de lo contrario continuar
if driver.find_element_by_xpath("//*[@id = 'zk_comp_86-empty']").text == 'No se han encontrado resultados':
continue
attrs= [] #Lista para guardar los atributos de la flecha
#Extraer los elementos de la tabla e navegar sobre el panel de resultados
while True: #Navegar sobre los resultados hasta que el atributo de la flecha se vuelva "disabled"
arg1 = pd.DataFrame() #Crear df auxiliar para ir guardando los resultados en cada iteración
headers = [] #Crear una lista vacía para guardar los encabezados de la tabla
rows = driver.find_elements_by_xpath("//*[@id='zk_comp_86-cave']/tbody/tr") #Número de filas
columns = driver.find_elements_by_xpath("//*[@id='zk_comp_86-cave']/tbody/tr[1]/td") #Número de columnas
for i in range(1,len(rows)): #Llenar el df iterando sobre los elementos de la tabla
for j in range(2,len(columns)-2):
if j == 8: #La columna 8 está oculta y tiene información basura que no es de interés
continue
else:
data = "//*[@id='zk_comp_86-cave']/tbody/tr[" + str(i) + "]/td[" + str(j) + "]"
try:
arg1.loc[i,j]= driver.find_element_by_xpath(data).text
except:
continue
if i==1: #Guardar el nombre de las columnas en la lista headers
columna = "//*[@id='zk_comp_86-headtbl']/tbody/tr/th[" + str(j) + "]"
headers.append(driver.find_element_by_xpath(columna).text)
arg = arg.append(arg1) #Combinar el df auxiliar con el df principal
siguiente = driver.find_element_by_name('zk_comp_99-next') #Buscar la flecha de "siguiente"
#Examinar las propiedades de la flecha
for attr in siguiente.get_property('attributes'):
if attr['name']=='disabled':
terminar = True
#Parar de iterar sobre el panel de navegación cuando la flecha este "disabled"
if terminar==True:
break
else: #Hacer click en "siguiente" si hay más resultados disponibles
while True:
try:
driver.find_element_by_name('zk_comp_99-next').click()
pagina = pagina + 1
while int(driver.find_element_by_name("zk_comp_99-real").get_attribute("value")) != pagina:
time.sleep(1)
break
except StaleElementReferenceException:
time.sleep(1)
arg.columns = headers #Asignar nombres a las columnas del df con headers
arg.reset_index(drop = True , inplace = True) #Resetar el índice del df
arg.to_excel("arg.xlsx" , index = False) #Exportar df principal a excel
############################################################################################################################################################################################
elif url["PAÍS"][ind]=="por" and url["INCLUIR"][ind]=="X": #INFARMED (POR) -------------------------------------------------------------------------------------------------------------
k = 1 ##############################################################################################################################################################################
por = pd.DataFrame() #Crear un df frame principal donde guardaremos la info
for medicamento in medicamentos_por: #Iterar sobre la lista de medicamentos seleccionados por el usuario
#Cuando hay muchos medicamentos en la búsqueda, el servidor de INFOMED puede caerse y la idea no es comenzar desde el principio
k_inicial = 1 #Creamos un variable auxiliar que nos guarde la iteración en la que ibamos
while True: #Usamos un while para continuar iterando hasta que sea exitoso
try:
driver.get(url["URL"][ind]) #Entramos a la página
#Esperamos a que carguen los elementos (barra de búsqueda)
WebDriverWait(driver, 40).until(EC.element_to_be_clickable((By.XPATH, "//*[@id='mainForm:dci_input']")))
#Covertimos el medicamento del archvio parámetros a la forma en que aparece en INFARMED
medicamento = medicamento.split(" ")
medicamento = [palabra.lower().capitalize() for palabra in medicamento]
separator = " "
medicamento = separator.join(medicamento)
#Limpiamos la barra de búsqueda e iniciamos una nueva consulta
driver.find_element_by_xpath("//*[@id='mainForm:dci_input']").clear()
driver.find_element_by_xpath("//*[@id='mainForm:dci_input']").send_keys(medicamento)
try: #Revisamos si el medicamento aparece en la página, si no, forzamos un break y continuamos con el siguiente
WebDriverWait(driver, 3).until(EC.visibility_of_element_located((By.XPATH, "//li[starts-with(., '" + medicamento + "')]")))
except TimeoutException: #Si el medicamento no aparece se generará un time out y forzamos un break
break
#Hacemos click en el medicamento que aparece
driver.find_element_by_xpath("//li[starts-with(., '" + medicamento + "')]").click()
#Búscamos sólo las presentaciones que son actualmente comercializadas - 'Comercialização das Apresentações'
WebDriverWait(driver, 40).until(EC.element_to_be_clickable((By.XPATH, "//*[@title ='Comercialização das Apresentações']")))
estado = driver.find_element_by_xpath("//*[@title ='Comercialização das Apresentações']")
estado.click()
WebDriverWait(driver, 40).until(EC.element_to_be_clickable((By.XPATH, "//li[starts-with(., 'Comercializado')]")))
driver.find_element_by_xpath("//li[starts-with(., 'Comercializado')]").click()
#Damos click en el botón buscar
driver.find_element_by_xpath("//*[@id='mainForm:btnDoSearch']").click()
time.sleep(10) #Esperamos 10 segundos a que se actualicen los resultados
#Revisamos si existen resultados para esa búsqueda
WebDriverWait(driver, 40).until(EC.visibility_of_element_located((By.XPATH, "//*[@class = 'ui-paginator-current']")))
existe = driver.find_element_by_xpath("//*[@class = 'ui-paginator-current']").text
if existe == "A mostrar 0 - 0 de um total de 0 registos. Está a visualizar a página 1 de 1": #Si no existen registros forzamos un break y continuamos con el siguiente medicamento
break
#Desplegamos la opción de mostrar 100 resultados
WebDriverWait(driver, 40).until(EC.element_to_be_clickable((By.XPATH, "//a[contains(@id,'linkNome')]")))
num_resultados = driver.find_element_by_xpath('//select[contains(@class, "paginator")]')
Select(num_resultados).select_by_visible_text("100")
time.sleep(10) #Esperamos 10 seg a que se despliguen todos los resultados
for k in range(k_inicial, len(driver.find_elements_by_xpath("//a[contains(@id,'linkNome')]"))+1):
#Crear una nueva ventana
link = driver.current_url
ventana_1 = driver.window_handles[0] #La ventana principal se llamará ventana_1
driver.execute_script("window.open('');") #Abrir una ventana nueva
ventana_2 = driver.window_handles[1] #La ventana auxiliar se llamará ventana_2
driver.switch_to.window(ventana_2)
driver.get(link)
#Iteramos sobre todos los resultados disponibles, iniciamos desde k-inicial
WebDriverWait(driver, 40).until(EC.element_to_be_clickable((By.XPATH, "//a[contains(@id,'linkNome')]")))
headers_por = [] #Lista donde se guardan los encabezados de la tabla
datos = [] #Lista donde se guarda la información de la k-ésima fila
#Llenar la listas de los encabezados y la k-ésima fila
WebDriverWait(driver, 40).until(EC.visibility_of_element_located((By.XPATH, "//*[contains(@id, 'medicamentos_data')]/tr["+ str(k)+ "]")))
for j in range(2,7): #Las columnas 2 a 6 son las que importan
header = driver.find_element_by_xpath('(//*[@role = "columnheader"])['+ str(j)+ ']').text
headers_por.append(header)
dato = driver.find_element_by_xpath("//*[contains(@id, 'medicamentos_data')]/tr["+ str(k)+ "]/td["+ str(j)+ "]").text
datos.append(dato)
#A veces los las filas no son clicekables por una animación que sale en la página. Creamos una espera dinámica para evitar posibles errores
while True:
try: #Damos click sobre el vínculo de la k-ésima fila
driver.find_element_by_xpath("(//a[contains(@id,'linkNome')])[" + str(k) + "]").click()
break
except:
time.sleep(1)
continue
#Examinamos el elemento 'card body' el cual tiene información sobre la cantidad de presentaciones
WebDriverWait(driver, 40).until(EC.visibility_of_element_located((By.XPATH, "(//*[@class='card-body'])[5]/div")))
num_resultados = driver.find_element_by_xpath("(//*[@class='card-body'])[5]/div").text
#A lo sumo pueden haber tres presentaciones comercializadas, por eso escogemos el mínimo entre lo que diga la página y tres
num_resultados = min(3, int(num_resultados[:num_resultados.find(" ")]))
#Extraemos la información de precios y cantidades de las presentaciones comercizalizadas
for i in range(1, num_resultados + 1):
#Las cantidades están en el elemento panel grid header
cantidades = driver.find_element_by_xpath("(//*[contains(@class,'panelgrid-header')])[" + str(i) + "]").text
#Los precios están en el elemento panel de precios
precios = driver.find_element_by_xpath("(//*[@id = 'preco-panel'])["+ str(i)+ "]").text
#Creamos una lista con todos los precios de acuerdo a una expresión regular
precios = re.findall("[\d,.]+\s*€", precios)
por1 = pd.DataFrame([datos]) #Creamos un data frame auxiliar y le asignamos los valores de la k-ésima fila
#Copiamos las filas en función de la cantidad de precios encontrados, si no se encontraron precios, el dataframe tendra cero filas
por1 = pd.DataFrame(np.repeat(por1.values,len(precios),axis=0), columns = headers_por)
por1["Presentacion"] = cantidades #Creamos la columna "Presentacion" donde se guardarán las cantidades
por1["Preco"] = "" #Creamos la columna Preco donde se guardarán los precios
for z in por1.index: #Iteramos sobre las filas
por1["Preco"][z] = precios[z] #Asignamos a cada fila el precio encontrado
por = por.append(por1) #Unimos el df auxiliar con el df principal
#Nos devolvemos a la página inicial donde estaban todos los resultados
driver.close() #Cerrar la ventana auxiliar
driver.switch_to.window(ventana_1) #Volver a la ventana principal
except TimeoutException: #Si la página muere y se hace un timeout, hacemos lo siguiente
k_inicial = k #Guardamos la k iteración en la que ibamos en nuestra variable auxiliar k-inicial
driver.quit() #Cerramos el navegador
driver = webdriver.Chrome(ChromeDriverManager().install(),chrome_options=chromeOptions) #Inicializamos otra ventana
continue #Reiniciamos la búsqueda PERO empezando desde k-inicial
break #Si todo sale bien llegamos a esta línea saliendo del loop y continuando con el siguiente medicamento de la lista
por.drop_duplicates(inplace=True) #Borramos posibles duplicados
por.reset_index(drop = True, inplace = True) #Reseteamos el ínidice
por.to_excel("por.xlsx" , index = False) #Exportamos los resultados de la consulta a un excel
############################################################################################################################################################################################
elif url["PAÍS"][ind]=="fra" and url["INCLUIR"][ind]=="X": #L'AM (FRA) -----------------------------------------------------------------------------------------------------------------
#Crear los data frame auxiliares para todas las consultas CIP y UCD #################################################################################################################
fra_cip = pd.DataFrame()
fra_ucd = pd.DataFrame()
#Iterar sobre una lista de medicamentos que contiene el nombre comercial y el principio activo
for medicamento in medicamentos_fr:
#Creamos estas variables auxiliares por si la consulta llega a fallar
i_inicial = 1
k_inicial = 0
z_inicial = 1
while True:
try:
#Hay dos tipos de búsqueda: CIP o UCD, es importante hacer los dos tipos de consulta
#i=1 para CIP e i = 2 para UCD
for i in range(i_inicial,3):
#k=0 es el nombre de la molécula y k=1 para el nombre comercial
for k in range(k_inicial,2):
driver.get(url["URL"][ind]) #Entramos a la página
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.NAME, "p_nom_commercial")))
driver.find_element_by_name("p_nom_commercial").clear()
driver.find_element_by_name("p_nom_commercial").send_keys(medicamento[k].replace(" / "," ")) #Ingresar el medicamento en la barra de búsqueda
if i==1: #Seleccionar todas las opciones de CIP
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.NAME, "p_cip")))
driver.find_element_by_name("p_cip").click()
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.NAME, "p_homol_ass")))
driver.find_element_by_name("p_homol_ass").click()
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.NAME, "p_homol_coll")))
driver.find_element_by_name("p_homol_coll").click()
elif i==2: #Seleccionar todas las opciones de UCD
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.NAME, "p_ucd")))
driver.find_element_by_name("p_ucd").click()
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.NAME, "p_homol_retro")))
driver.find_element_by_name("p_homol_retro").click()
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.NAME, "p_homol_taa")))
driver.find_element_by_name("p_homol_taa").click()
#Click en el botón validar
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, '*//input[@value = "Valider"]')))
driver.find_element_by_xpath('*//input[@value = "Valider"]').click()
#Si la búsqueda no retorna ningún resultado continuar iterando
WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//*[@class ='titreActu']")))
if driver.find_element_by_xpath("//*[@class ='titreActu']").text == "Aucune donnée ne correspond à votre sélection !":
continue
#Continuar con el algoritmo dependiendo si la consulta tiene uno o varios registros
muchos_registros = False
#No sumamos +1 en el bucle porque no queremos llegar al último elemento (que es un link de descarga a Excel)
for z in range(z_inicial, max(2,len(driver.find_elements_by_xpath("//*[@class = 'liensoul']")))):
if len(driver.find_elements_by_xpath("//*[@class = 'liensoul']"))>0:
muchos_registros = True #Avisar que hay más de un registro
#Hacer click en cada registro si hay más de uno
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "(//*[@class = 'liensoul'])[" + str(z) + "]")))
codigo = driver.find_element_by_xpath("(//*[@class = 'liensoul'])["+ str(z) +"]").get_attribute("href") #Obtener el hipervínculo con el detalle del medicamento
ventana_1 = driver.window_handles[0] #La ventana principal se llamará ventana_1
driver.execute_script("window.open('');") #Abrir una ventana nueva
ventana_2 = driver.window_handles[1] #La ventana auxiliar se llamará ventana_2
driver.switch_to.window(ventana_2) #Cambiar a la ventana 2
driver.get(codigo) #Buscar el detalle del medicamento en una ventana nueva
#Crear df auxiliares en cada iteración para consolidar los data frames principales
fra1_cip = pd.DataFrame()
fra1_ucd = pd.DataFrame()
#Crear listas con los encabezados de cada tabla
header_cip = []
header_ucd = []
if i==1: #CIP
try: #Si no existen precios para ese registro, volver a la página anterior con todos los registros
WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//table")))
if driver.find_element_by_xpath("//table[13]").text != "Historique Remboursement :":
if muchos_registros == True:
driver.close() #Cerrar la ventana auxiliar
driver.switch_to.window(ventana_1) #Volver a la ventana prinicipal
continue
except NoSuchElementException: #Si no existe la tabla 13, continuar iterando
if muchos_registros == True:
driver.close() #Cerrar la ventana auxiliar
driver.switch_to.window(ventana_1) #Volver a la ventana principal
continue
#Llenar el data frame iterando sobre las filas y columnas de la tabla
rows = len(driver.find_elements_by_xpath("//table[14]/tbody/tr"))
columns = len(driver.find_elements_by_xpath("//table[14]/tbody/tr[1]/td"))
for x in range(2 , rows+1):
for y in range(1 , columns+1):
if x==2:
nombre_columna = "//table[14]/tbody/tr[1]/td[" + str(y) + "]"
header_cip.append(driver.find_element_by_xpath(nombre_columna).text)
data = "//table[14]/tbody/tr[" + str(x) + "]/td[" + str(y) + "]"
fra1_cip.loc[x,y] = driver.find_element_by_xpath(data).text
fra1_cip.columns = header_cip #Asignar nombre de columnas al df
#Llenar información correspondiente a la descripción del medicamento
fra1_cip["Désignation"] = driver.find_element_by_xpath("//table[2]/tbody/tr[4]/td[3]").text
fra1_cip["Conditionnement"] = driver.find_element_by_xpath("//table[2]/tbody/tr[5]/td[3]").text
fra1_cip["Type"] = "CIP"
fra1_cip["PA"] = medicamento[0] #Guardamos en la columna "PA" el principio activo
fra_cip = fra_cip.append(fra1_cip) #Combinar el df principal con el auxiliar
#Eliminar duplicados y columnas que no son de interés. Finalmente cambiar el nombre las columnas
fra_cip.drop_duplicates(subset = ["Prix Fabricant HT €","Désignation","Conditionnement"], inplace = True)
elif i==2: #UCD
try: #Si no existen precios para ese registro, volver a la página anterior con todos los reistros
WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//table")))
if driver.find_element_by_xpath("//table[12]").text != "Historique Remboursement :":
if muchos_registros == True:
driver.close() #Cerrar la ventana auxiliar
driver.switch_to.window(ventana_1) #Volver a la ventana prinicipal
continue
except NoSuchElementException: #Si no existe la tabla 12, continuar iterando
if muchos_registros == True:
driver.close() #Cerrar la ventana auxiliar
driver.switch_to.window(ventana_1) #Volver a la ventana principal