Es igual, voy a importarlo desde main.py y pasarle la cadena de conexión como un parametro al constructor de la clase Mongo
#91 Cabrón que tienes de momento dos .py no te enmarañes con eso. Lo que necesites en python yo también te puedo ayudar. Y suerte con el resto del proyecto que tiene buena pinta!!
#92 Se ha quedado una buena abstracción jajajajajaja
Edit ---------------
#83 Vale me la he tirado de listo y esta mierda no funciona, no se pueden devolver objetos instanciados dentro de metodos de otro objeto instanciado?
Si esa misma mierda la hago en orden tal que asi funciona (main.py)
Evidentemente esto en mis lenguajes de la plebe como JS y PHP funcionaria el caso 1 y el 2, pero en python el caso 1 no rula:
AttributeError: 'function' object has no attribute 'command'
EDIT 2 ------------------------
SHIIIT soy retrasado, lo dejo aqui intacto para mi verguenza, he tenido que enchufar el debugger para darme cuenta del retrasito mental que llevaba
Día 14
Python
Hoy he estado trasteando con los fundamentos, una clase, importación de ficheros y probando la conexión a la mongo.
Todo ok, asi que mañana empiezo con el scraping y continuo pegandome con los fundamentos.
Al final intentado arreglar los .gitignore he acabado haciendo 4 commits, small commits, 10/10, would fuck this git master :
Commit 1
Commit 2
Commit 3
Commit 4
MongoDB
He definido el modelo de datos que voy a guardar del scrapper (Excepto la collection users, que viene de la app) y consumir desde la APP:
No se si teneis algo que criticar.
Python v2
Por cierto, ya que estamos, el proceso que se encargue de tirar notificaciones push a los zodiacos lo voy a hacer con Python también.
#94 el horoscopes_daily necesitas saber tanto el signo como el idioma y la fecha para la que es válido? (No ha puesto indices.) Yo estas tres props las veo como root del horóscopo diario, mientras que los contents si los veo como strings.
Te diría que pondría un horoscope_daily para todos los idiomas, por ejemplo:
{ sign, date, ..., love_txt: { es: "", en: "" }, health_txt: { ...} }
Y en la query te encargas de sacar solo el lang que quieras.
No me mola el contents.contents por cierto.
En la otra entidad, como piensas actualizarla/gestionarla? Un signo con sus M relaciones al resto de signos? O relación a relacion (1:1)?
Si es la primera, metería todo en un objeto;
{ sign, destinations:{ cancer: { .... }, aries: {... }}
y dentro de cada signo destino, lo que necesites de compatibilidad
Los texts los puedes poner en una relación, en una colección a parte, con dbrefs o algo así, para mantener los items de la colección más pequeños https://docs.mongodb.com/manual/reference/database-references/ depende de cómo accedas a estos.
Efectivamente me deje el sign en horoscopes_daily, el idioma no, pues traduzco en caliente en React el signo desde el inglés (Y para mi aplicación para identificar los signos utilizo sus nombres en ingles), entonces como clave el idioma no, claves quedarían day y sign.
Tienes razón esto no tiene sentido como lo he planteado, sacaré el contents.contents un nivel y lo dejaré como dices tu.
En principio horoscopes_stale como bien dice su nombre sera data totalmente muerta, la sacare un dia y nunca más, si tengo que actualizarla será vaciando la colección y metiendo data nueva.
Ahora bien, es interesante como lo planteas, mi intención era hacer una "query" cutre con los dos signos seleccionados y buscar que ambos estuvieran ya sea como sign1 o como sign2.
Y lo de los dbrefs me lo miro, aún pudiendolo meter a pelo así aprendo y me empapo con un poco mas de mongodb.
#96 Si es la misma relacion de sign1 -> sign2 que sign2 -> sign1, entonces no te hace falta hacerlo como dije. Yo entendí que sería diferente la relación/textos cuando la relación es hacia un lado o hacia el otro.
Lo de poner los langs separados es por no hacer tus objetos muy grandes, creo que no es recomendable en mongodb, al menos eso lei hace tiempo, la gente acortando hasta el nombre de las props para que el json fuera más pequeño, no recuerdo si había límite. Y así solo resolver un idioma y no todos.
"The maximum BSON document size is 16 megabytes", que serían unos 17 millones de caracteres si no me he descontado.
Edit: coño, la fuente: https://docs.mongodb.com/manual/reference/limits/
#98 Trabajamos en el curro el otro dia con base64 de contratos que paseábamos entre apis y no se nos ocurrió nada mejor que guardar las respuestas de la api en base de datos con el base64 incluido, no nos dimos cuenta y en una semana habíamos duplicado el tamaño de la base de datos. Esa tabla era un agujero negro, ingestionable, Heidi explotaba directamente por los cielos cuando pasabas cerca jajaja
Lo digo porque, un contrato en pdf, con 5-10 páginas pesaba a lo 6-12 mb, asi que creo que mi data del horóscopo estará muy muy lejos jajaja
#99 Sí, y además un pdf no es sólo el texto, hay más chicha dentro del documento. Para llenar 16GB de texto plano tienes que meter el Señor de los Anillos repetido 32 veces XD
Día 15
Python
Hoy he avanzado mucho, de hecho ya tengo todo el contenido en castellano de los signos (Salud, Trabajo y Amor), osea mañana ya me pongo con la data de la compatibilidad en castellano y ya me paso al Inglés.
El código que he tenido que picar a nivel de movimiento entre tags del dom es un PUTISIMO TRUÑO, aquí una pincelada:
pageSign.find_next_sibling('p').find_next_sibling('p').find_next_sibling('p').text.replace('Ver más sobre ' + spSign + '…', '').replace('Dinero y trabajo:', '').strip()
Pero es que no te queda más remedio con el TRUÑAZO GIGANTESCO que tienen de dom en la página de donde la saco, y lo sacó de esa porque tienen la data exacta que busco para mi APP en castellano.
Por cierto me encanta la mierda de poder concatenar metodos al string, fuck PHP.
Y me encanta lo de poder iterar diccionarios facilmente, fuck JavaScript y su Array.Keys(array).
Mañana creo que ya tendre toda la data, y vere si ya la puedo tener insertada en Mongo. Sino, lo de insertar para el viernes.
Un buen commit :
MongoDB
He definido el modelo de datos DEFINITIVO, gracias a @JuAn4k4 por los consejos.
En otro orden de cosas
El otro dia recibi mi primer estrella de un random en github en un proyecto mío, no cuento la del proyecto de la APP que se que fue alguno de vosotros (Gracias) y me hizo mucho ilusión, por ser un random que supongo la probó, le funciono y me lo agradeció.
El repo es este, es un comando de NodeJS que parsea páginas CSR (Client side rendered) y genera un sitemap.xml con todas las URL internas que encuentra (y las que encuentra dentro de esas ) listo para ser cargado en el Search Console de Google.
https://github.com/jvidalv/super-simple-sitemap-generator
La gracia es que funciona con CSR, es decir, espera que acabe de cargar todo el dom antes de empezar parsear, y esto lo hace de forma iterativa por cada página nueva interna que encuentra.
Mañana más!
Lo del codigo de scrapeo siendo feo es algo "normal". Si no tienen una API pues es a lo que tienes que recurrir jajajaj , lo unico que te diría es que te asegures de que tienes un "fallback". Es decir, todo lo que has encadenado se puede ir a la mierda si no encuentra algo del principio de la cadena no? (Muy al estilo JS, que te dice que "nosequé" is not a function of undefined). Así que intenta tener siempre controlado lo mejor posible lo que estás scrapeando!
No he cambiado la lógica de tu programa, simplemente he ajustado el scrap para reducir el chorizo y cambiado un par de cosas: nombres de variables para cumplir el PEP (aquí se usa el camel_case siempre), te he cambiado el parser a lxml
que es mucho más rápido y poco más.
Mongo funciona bien si tu db entera cabe en memoria, sino, es un poco chof. Pero vaya que si borras los stale de vez en cuando no tendrás problemas
Oye @isvidal has probado MongoDB Compass? Normalmente uso la consola para moverme y tal, pero esto es la polla para testear, ¿eh?
#103 Muchas grácias! No tenía ni idea de lo de que aquí era camel_case y no camelCase!
He intentado usar el lxml pero me ha dado problemas instalando en windows, algo de un paquete "wheels" he buscado y asi rapido no he sacado nada en claro, de momento lo dejo con que llevaba por defecto.
#104 Mi intención es llenarla una vez y no más la stale, y la otra dejar solo data de 1 mes para atrás.
#105 Estoy utilizando el DataGrip para trastear, pero lo miro! Merci!
#102 Tengo intención de que el fallback sea el pillar un dia random de 2-3 semanas atrás, si ese dia fallas, te vas a la data guardada de hace 2-3 semanas y la planchas como si fuera de hoy.
#106 ¿Estás usando pip
para la instalación? Esta mañana precisamente lo instalé yo sin problemas.
#107 Yes
pip install lxml
Todo ok, luego al usarlo:
Could not build wheels for lxml, since package 'wheel' is not installed.
#110 Pues ni puta idea. Es exactamente la versión que estoy usando yo. Lo mismo con un pip install wheel
se arregla xD
#112 La otra opción es que se lo cargue todo y si no está usando venv
le va a tocar reinstalar Python xD
#112 #113 Efectivamente, a veces nos emparramos en lo difícil y ni leemos el mensaje, lo primero que he hecho al ver le mensaje es googlearlo, cuando realmente el mensaje no podia ser más claro, con el pip install wheels se ha solucionado.
Ahora estoy peleandome con selenium y los geckodrivers, pues quiero parsear una página que carga con js y no pillo la data con el request simple.
Día 16
Python
Hoy he avanzado un poco a trompicones, me he encontrado que la mayoría de páginas de horóscopos cargan al data dinámica con javascript una vez esta la petición ya respondida AKA CSR entonces con el request
no me daba, pues en el momento de la petición la parte del dom donde estaba la data aún no estaba cargada.
La solución ha sido selenium y headless chrome, después de pegarme un poco con cositas de drivers ya tengo la data diaria de amor / trabajo / salud para el dia en ingles, aqui una pincelada, si eres Scorpio es tu info:
Un buen commit :
Mañana más! Espero tener toda la data ya del dia, y empezar a tocar la stale!
#116 De este código no mucho que añadir, la verdad. Quizás sería interesante mover todo ese tratamiento del texto a una función a la cual le pases una cadena y te la limpie (por claridad y posibilidad de reutilización más que nada).
Por otro lado, una pequeña librería que uso yo en mis scraps es fake-useragent
. Así no pueden bloquearte mirando el User-Agent por defecto.
self.base_url = 'https://www.mediavida.com'
self.session = requests.Session()
self.session.headers['User-Agent'] = UserAgent().random
Día 17
Python
Ya tengo casi tooooda la data, solo me falta de horoscopes_stale
la data en castellano, el de horoscopes_daily
la tengo toda. al final he separado el texto de stale, y ahora hay dos, relationship, y resume.
He implementado lo del user agent que comentaba #117 tanto en request
como en selenium
.
Mañana que tengo muchas más horas pues no trabajo, después de sacar al perro x2, entrenar x2, trabajar en el campo x2, espero meter 4 horas mínimo y dejar el python matado + inserts en mongoDb, y estar ya metido en el Docker configurando el Jenkins.
Un commit decente , se me han quedado 4 cosas del debug como exit y pprints, que ya sacare mañana:
Futuros proyectos
Cuando termine este estoy barajando dos opciones:
- Una aplicación móvil de noticias de Nigeria
- Una versión web del horoscopo con NextJs.
¿?
#118 Si pones un user_agent = random_user_agent()
arriba del todo te ahorras llamadas a la función hhhehhehe.
#119 ya pero como las peligrosas son las que hago dentro de for's a toda castaña, casi que mejor llamarla cada vez asi las 20 peticiones son "distintas".
Pienso yo, no se si estoy equivocado.