First commit.
History is present
This commit is contained in:
commit
cabebe4395
23 changed files with 1047 additions and 0 deletions
1
README.md
Normal file
1
README.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
16
dbs/pinopisolo.db
Normal file
16
dbs/pinopisolo.db
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{"actions": ["search_and_retweet"], "buddy": ["InfoAntifa", "LibreriAntigone", "romaoccupata", "Assospartaco", "BANDA_BASSOTTI", "rivamesta", "zeropregi", "progettoDegage", "contropiano", "DinamoPress", "ilmanifesto", "Radiondarossa", "repubblica", "notav_info", "Infoaut", "sap_clandestina", "zerocalcare", "FPrenestino", "AnpiRoma", "RFeminista_", "RomaAntifa", "AntifaOstia", "romattiva", "MilitantBlog", "RATM", "matteosalvinimi\u00a0", "gruppohobbit\u00a0", "CircoloFuturista", "MSR_cat\u00a0", "Occidentale", "OrdineNuovo", "romatoday\u00a0", "PBT_Torino", "Nigel_Farage", "UKIP", "SimoneCasaPound\u00a0", "MarcelloRuffo", "IannoneCpi", "ilgiornale\u00a0", "ChiaraScalzi85\u00a0", "BloccoStudentesco\u00a0", "prog_sociale", "ForzaNuova\u00a0", "AlbaDoratait\u00a0", "distefanoTW\u00a0", "CasaPoundItalia\u00a0", "giorgiameloni", "FratellidItalia"], "hash": ["fascismo", "antifascismo", "razzismo", "italia", "italiano", "italiaglitaliani", "stopinvasione", "puliziaetnica", "mussolini", "quandoceralui", "hitler", "farequadrato", "apologia", "nazismo", "antinazismo", "fakenews", "complotto", "noeuro", "scontri", "centrisociali", "occupazione", "lavoro", "sinistra", "manifestazione", "blackbloc", "vandalismo", "fanatismo", "destra", "parlamento", "violenza", "polizia", "esercito", "rom", "campirom", "roma", "guerra", "sciopero", "precari", "casa", "mafia", "camorra", "ndrangheta", "sindacato", "clandestino", "immigrato", "immigrati", "barconi", "negri", "cassazione", "pd", "leganord", "fdi", "an", "grillo", "m5s", "donne", "violenzasulledonne", "bambini", "famiglia", "dio", "patria", "difesa", "nazione", "paese", "madeinitaly", "salvini", "populismo", "casapound", "lepen", "schifo", "feccia", "odio", "amore", "forzanuova", "forteprenestino", "nietsche", "ezrapound", "democrazia", "politica", "votare", "elezioni", "parlamento"], "time": 1509234065}
|
||||||
|
{"actions": ["search_and_retweet"], "buddy": ["InfoAntifa", "LibreriAntigone", "romaoccupata", "Assospartaco", "BANDA_BASSOTTI", "rivamesta", "zeropregi", "progettoDegage", "contropiano", "DinamoPress", "ilmanifesto", "Radiondarossa", "repubblica", "notav_info", "Infoaut", "sap_clandestina", "zerocalcare", "FPrenestino", "AnpiRoma", "RFeminista_", "RomaAntifa", "AntifaOstia", "romattiva", "MilitantBlog", "RATM", "matteosalvinimi\u00a0", "gruppohobbit\u00a0", "CircoloFuturista", "MSR_cat\u00a0", "Occidentale", "OrdineNuovo", "romatoday\u00a0", "PBT_Torino", "Nigel_Farage", "UKIP", "SimoneCasaPound\u00a0", "MarcelloRuffo", "IannoneCpi", "ilgiornale\u00a0", "ChiaraScalzi85\u00a0", "BloccoStudentesco\u00a0", "prog_sociale", "ForzaNuova\u00a0", "AlbaDoratait\u00a0", "distefanoTW\u00a0", "CasaPoundItalia\u00a0", "giorgiameloni", "FratellidItalia"], "hash": ["fascismo", "antifascismo", "razzismo", "italia", "italiano", "italiaglitaliani", "stopinvasione", "puliziaetnica", "mussolini", "quandoceralui", "hitler", "farequadrato", "apologia", "nazismo", "antinazismo", "fakenews", "complotto", "noeuro", "scontri", "centrisociali", "occupazione", "lavoro", "sinistra", "manifestazione", "blackbloc", "vandalismo", "fanatismo", "destra", "parlamento", "violenza", "polizia", "esercito", "rom", "campirom", "roma", "guerra", "sciopero", "precari", "casa", "mafia", "camorra", "ndrangheta", "sindacato", "clandestino", "immigrato", "immigrati", "barconi", "negri", "cassazione", "pd", "leganord", "fdi", "an", "grillo", "m5s", "donne", "violenzasulledonne", "bambini", "famiglia", "dio", "patria", "difesa", "nazione", "paese", "madeinitaly", "salvini", "populismo", "casapound", "lepen", "schifo", "feccia", "odio", "amore", "forzanuova", "forteprenestino", "nietsche", "ezrapound", "democrazia", "politica", "votare", "elezioni", "parlamento"], "time": 1509234070}
|
||||||
|
{"actions": ["search_and_retweet"], "buddy": ["InfoAntifa", "LibreriAntigone", "romaoccupata", "Assospartaco", "BANDA_BASSOTTI", "rivamesta", "zeropregi", "progettoDegage", "contropiano", "DinamoPress", "ilmanifesto", "Radiondarossa", "repubblica", "notav_info", "Infoaut", "sap_clandestina", "zerocalcare", "FPrenestino", "AnpiRoma", "RFeminista_", "RomaAntifa", "AntifaOstia", "romattiva", "MilitantBlog", "RATM", "matteosalvinimi\u00a0", "gruppohobbit\u00a0", "CircoloFuturista", "MSR_cat\u00a0", "Occidentale", "OrdineNuovo", "romatoday\u00a0", "PBT_Torino", "Nigel_Farage", "UKIP", "SimoneCasaPound\u00a0", "MarcelloRuffo", "IannoneCpi", "ilgiornale\u00a0", "ChiaraScalzi85\u00a0", "BloccoStudentesco\u00a0", "prog_sociale", "ForzaNuova\u00a0", "AlbaDoratait\u00a0", "distefanoTW\u00a0", "CasaPoundItalia\u00a0", "giorgiameloni", "FratellidItalia"], "hash": ["fascismo", "antifascismo", "razzismo", "italia", "italiano", "italiaglitaliani", "stopinvasione", "puliziaetnica", "mussolini", "quandoceralui", "hitler", "farequadrato", "apologia", "nazismo", "antinazismo", "fakenews", "complotto", "noeuro", "scontri", "centrisociali", "occupazione", "lavoro", "sinistra", "manifestazione", "blackbloc", "vandalismo", "fanatismo", "destra", "parlamento", "violenza", "polizia", "esercito", "rom", "campirom", "roma", "guerra", "sciopero", "precari", "casa", "mafia", "camorra", "ndrangheta", "sindacato", "clandestino", "immigrato", "immigrati", "barconi", "negri", "cassazione", "pd", "leganord", "fdi", "an", "grillo", "m5s", "donne", "violenzasulledonne", "bambini", "famiglia", "dio", "patria", "difesa", "nazione", "paese", "madeinitaly", "salvini", "populismo", "casapound", "lepen", "schifo", "feccia", "odio", "amore", "forzanuova", "forteprenestino", "nietsche", "ezrapound", "democrazia", "politica", "votare", "elezioni", "parlamento"], "time": 1509234632}
|
||||||
|
{"actions": ["search_and_retweet"], "buddy": ["InfoAntifa", "LibreriAntigone", "romaoccupata", "Assospartaco", "BANDA_BASSOTTI", "rivamesta", "zeropregi", "progettoDegage", "contropiano", "DinamoPress", "ilmanifesto", "Radiondarossa", "repubblica", "notav_info", "Infoaut", "sap_clandestina", "zerocalcare", "FPrenestino", "AnpiRoma", "RFeminista_", "RomaAntifa", "AntifaOstia", "romattiva", "MilitantBlog", "RATM", "matteosalvinimi\u00a0", "gruppohobbit\u00a0", "CircoloFuturista", "MSR_cat\u00a0", "Occidentale", "OrdineNuovo", "romatoday\u00a0", "PBT_Torino", "Nigel_Farage", "UKIP", "SimoneCasaPound\u00a0", "MarcelloRuffo", "IannoneCpi", "ilgiornale\u00a0", "ChiaraScalzi85\u00a0", "BloccoStudentesco\u00a0", "prog_sociale", "ForzaNuova\u00a0", "AlbaDoratait\u00a0", "distefanoTW\u00a0", "CasaPoundItalia\u00a0", "giorgiameloni", "FratellidItalia"], "hash": ["fascismo", "antifascismo", "razzismo", "italia", "italiano", "italiaglitaliani", "stopinvasione", "puliziaetnica", "mussolini", "quandoceralui", "hitler", "farequadrato", "apologia", "nazismo", "antinazismo", "fakenews", "complotto", "noeuro", "scontri", "centrisociali", "occupazione", "lavoro", "sinistra", "manifestazione", "blackbloc", "vandalismo", "fanatismo", "destra", "parlamento", "violenza", "polizia", "esercito", "rom", "campirom", "roma", "guerra", "sciopero", "precari", "casa", "mafia", "camorra", "ndrangheta", "sindacato", "clandestino", "immigrato", "immigrati", "barconi", "negri", "cassazione", "pd", "leganord", "fdi", "an", "grillo", "m5s", "donne", "violenzasulledonne", "bambini", "famiglia", "dio", "patria", "difesa", "nazione", "paese", "madeinitaly", "salvini", "populismo", "casapound", "lepen", "schifo", "feccia", "odio", "amore", "forzanuova", "forteprenestino", "nietsche", "ezrapound", "democrazia", "politica", "votare", "elezioni", "parlamento"], "time": 1509234658}
|
||||||
|
{"actions": ["search_and_retweet"], "buddy": ["InfoAntifa", "LibreriAntigone", "romaoccupata", "Assospartaco", "BANDA_BASSOTTI", "rivamesta", "zeropregi", "progettoDegage", "contropiano", "DinamoPress", "ilmanifesto", "Radiondarossa", "repubblica", "notav_info", "Infoaut", "sap_clandestina", "zerocalcare", "FPrenestino", "AnpiRoma", "RFeminista_", "RomaAntifa", "AntifaOstia", "romattiva", "MilitantBlog", "RATM", "matteosalvinimi\u00a0", "gruppohobbit\u00a0", "CircoloFuturista", "MSR_cat\u00a0", "Occidentale", "OrdineNuovo", "romatoday\u00a0", "PBT_Torino", "Nigel_Farage", "UKIP", "SimoneCasaPound\u00a0", "MarcelloRuffo", "IannoneCpi", "ilgiornale\u00a0", "ChiaraScalzi85\u00a0", "BloccoStudentesco\u00a0", "prog_sociale", "ForzaNuova\u00a0", "AlbaDoratait\u00a0", "distefanoTW\u00a0", "CasaPoundItalia\u00a0", "giorgiameloni", "FratellidItalia"], "hash": ["fascismo", "antifascismo", "razzismo", "italia", "italiano", "italiaglitaliani", "stopinvasione", "puliziaetnica", "mussolini", "quandoceralui", "hitler", "farequadrato", "apologia", "nazismo", "antinazismo", "fakenews", "complotto", "noeuro", "scontri", "centrisociali", "occupazione", "lavoro", "sinistra", "manifestazione", "blackbloc", "vandalismo", "fanatismo", "destra", "parlamento", "violenza", "polizia", "esercito", "rom", "campirom", "roma", "guerra", "sciopero", "precari", "casa", "mafia", "camorra", "ndrangheta", "sindacato", "clandestino", "immigrato", "immigrati", "barconi", "negri", "cassazione", "pd", "leganord", "fdi", "an", "grillo", "m5s", "donne", "violenzasulledonne", "bambini", "famiglia", "dio", "patria", "difesa", "nazione", "paese", "madeinitaly", "salvini", "populismo", "casapound", "lepen", "schifo", "feccia", "odio", "amore", "forzanuova", "forteprenestino", "nietsche", "ezrapound", "democrazia", "politica", "votare", "elezioni", "parlamento"], "time": 1509234672}
|
||||||
|
{"actions": ["search_and_retweet"], "buddy": ["InfoAntifa", "LibreriAntigone", "romaoccupata", "Assospartaco", "BANDA_BASSOTTI", "rivamesta", "zeropregi", "progettoDegage", "contropiano", "DinamoPress", "ilmanifesto", "Radiondarossa", "repubblica", "notav_info", "Infoaut", "sap_clandestina", "zerocalcare", "FPrenestino", "AnpiRoma", "RFeminista_", "RomaAntifa", "AntifaOstia", "romattiva", "MilitantBlog", "RATM", "matteosalvinimi\u00a0", "gruppohobbit\u00a0", "CircoloFuturista", "MSR_cat\u00a0", "Occidentale", "OrdineNuovo", "romatoday\u00a0", "PBT_Torino", "Nigel_Farage", "UKIP", "SimoneCasaPound\u00a0", "MarcelloRuffo", "IannoneCpi", "ilgiornale\u00a0", "ChiaraScalzi85\u00a0", "BloccoStudentesco\u00a0", "prog_sociale", "ForzaNuova\u00a0", "AlbaDoratait\u00a0", "distefanoTW\u00a0", "CasaPoundItalia\u00a0", "giorgiameloni", "FratellidItalia"], "hash": ["fascismo", "antifascismo", "razzismo", "italia", "italiano", "italiaglitaliani", "stopinvasione", "puliziaetnica", "mussolini", "quandoceralui", "hitler", "farequadrato", "apologia", "nazismo", "antinazismo", "fakenews", "complotto", "noeuro", "scontri", "centrisociali", "occupazione", "lavoro", "sinistra", "manifestazione", "blackbloc", "vandalismo", "fanatismo", "destra", "parlamento", "violenza", "polizia", "esercito", "rom", "campirom", "roma", "guerra", "sciopero", "precari", "casa", "mafia", "camorra", "ndrangheta", "sindacato", "clandestino", "immigrato", "immigrati", "barconi", "negri", "cassazione", "pd", "leganord", "fdi", "an", "grillo", "m5s", "donne", "violenzasulledonne", "bambini", "famiglia", "dio", "patria", "difesa", "nazione", "paese", "madeinitaly", "salvini", "populismo", "casapound", "lepen", "schifo", "feccia", "odio", "amore", "forzanuova", "forteprenestino", "nietsche", "ezrapound", "democrazia", "politica", "votare", "elezioni", "parlamento"], "time": 1509234711}
|
||||||
|
{"actions": ["search_and_retweet"], "buddy": ["InfoAntifa", "LibreriAntigone", "romaoccupata", "Assospartaco", "BANDA_BASSOTTI", "rivamesta", "zeropregi", "progettoDegage", "contropiano", "DinamoPress", "ilmanifesto", "Radiondarossa", "repubblica", "notav_info", "Infoaut", "sap_clandestina", "zerocalcare", "FPrenestino", "AnpiRoma", "RFeminista_", "RomaAntifa", "AntifaOstia", "romattiva", "MilitantBlog", "RATM", "matteosalvinimi\u00a0", "gruppohobbit\u00a0", "CircoloFuturista", "MSR_cat\u00a0", "Occidentale", "OrdineNuovo", "romatoday\u00a0", "PBT_Torino", "Nigel_Farage", "UKIP", "SimoneCasaPound\u00a0", "MarcelloRuffo", "IannoneCpi", "ilgiornale\u00a0", "ChiaraScalzi85\u00a0", "BloccoStudentesco\u00a0", "prog_sociale", "ForzaNuova\u00a0", "AlbaDoratait\u00a0", "distefanoTW\u00a0", "CasaPoundItalia\u00a0", "giorgiameloni", "FratellidItalia"], "hash": ["fascismo", "antifascismo", "razzismo", "italia", "italiano", "italiaglitaliani", "stopinvasione", "puliziaetnica", "mussolini", "quandoceralui", "hitler", "farequadrato", "apologia", "nazismo", "antinazismo", "fakenews", "complotto", "noeuro", "scontri", "centrisociali", "occupazione", "lavoro", "sinistra", "manifestazione", "blackbloc", "vandalismo", "fanatismo", "destra", "parlamento", "violenza", "polizia", "esercito", "rom", "campirom", "roma", "guerra", "sciopero", "precari", "casa", "mafia", "camorra", "ndrangheta", "sindacato", "clandestino", "immigrato", "immigrati", "barconi", "negri", "cassazione", "pd", "leganord", "fdi", "an", "grillo", "m5s", "donne", "violenzasulledonne", "bambini", "famiglia", "dio", "patria", "difesa", "nazione", "paese", "madeinitaly", "salvini", "populismo", "casapound", "lepen", "schifo", "feccia", "odio", "amore", "forzanuova", "forteprenestino", "nietsche", "ezrapound", "democrazia", "politica", "votare", "elezioni", "parlamento"], "time": 1509234747}
|
||||||
|
{"actions": ["search_and_retweet"], "buddy": ["InfoAntifa", "LibreriAntigone", "romaoccupata", "Assospartaco", "BANDA_BASSOTTI", "rivamesta", "zeropregi", "progettoDegage", "contropiano", "DinamoPress", "ilmanifesto", "Radiondarossa", "repubblica", "notav_info", "Infoaut", "sap_clandestina", "zerocalcare", "FPrenestino", "AnpiRoma", "RFeminista_", "RomaAntifa", "AntifaOstia", "romattiva", "MilitantBlog", "RATM", "matteosalvinimi\u00a0", "gruppohobbit\u00a0", "CircoloFuturista", "MSR_cat\u00a0", "Occidentale", "OrdineNuovo", "romatoday\u00a0", "PBT_Torino", "Nigel_Farage", "UKIP", "SimoneCasaPound\u00a0", "MarcelloRuffo", "IannoneCpi", "ilgiornale\u00a0", "ChiaraScalzi85\u00a0", "BloccoStudentesco\u00a0", "prog_sociale", "ForzaNuova\u00a0", "AlbaDoratait\u00a0", "distefanoTW\u00a0", "CasaPoundItalia\u00a0", "giorgiameloni", "FratellidItalia"], "hash": ["fascismo", "antifascismo", "razzismo", "italia", "italiano", "italiaglitaliani", "stopinvasione", "puliziaetnica", "mussolini", "quandoceralui", "hitler", "farequadrato", "apologia", "nazismo", "antinazismo", "fakenews", "complotto", "noeuro", "scontri", "centrisociali", "occupazione", "lavoro", "sinistra", "manifestazione", "blackbloc", "vandalismo", "fanatismo", "destra", "parlamento", "violenza", "polizia", "esercito", "rom", "campirom", "roma", "guerra", "sciopero", "precari", "casa", "mafia", "camorra", "ndrangheta", "sindacato", "clandestino", "immigrato", "immigrati", "barconi", "negri", "cassazione", "pd", "leganord", "fdi", "an", "grillo", "m5s", "donne", "violenzasulledonne", "bambini", "famiglia", "dio", "patria", "difesa", "nazione", "paese", "madeinitaly", "salvini", "populismo", "casapound", "lepen", "schifo", "feccia", "odio", "amore", "forzanuova", "forteprenestino", "nietsche", "ezrapound", "democrazia", "politica", "votare", "elezioni", "parlamento"], "time": 1509234854}
|
||||||
|
{"actions": ["search_and_retweet"], "buddy": ["InfoAntifa", "LibreriAntigone", "romaoccupata", "Assospartaco", "BANDA_BASSOTTI", "rivamesta", "zeropregi", "progettoDegage", "contropiano", "DinamoPress", "ilmanifesto", "Radiondarossa", "repubblica", "notav_info", "Infoaut", "sap_clandestina", "zerocalcare", "FPrenestino", "AnpiRoma", "RFeminista_", "RomaAntifa", "AntifaOstia", "romattiva", "MilitantBlog", "RATM", "matteosalvinimi\u00a0", "gruppohobbit\u00a0", "CircoloFuturista", "MSR_cat\u00a0", "Occidentale", "OrdineNuovo", "romatoday\u00a0", "PBT_Torino", "Nigel_Farage", "UKIP", "SimoneCasaPound\u00a0", "MarcelloRuffo", "IannoneCpi", "ilgiornale\u00a0", "ChiaraScalzi85\u00a0", "BloccoStudentesco\u00a0", "prog_sociale", "ForzaNuova\u00a0", "AlbaDoratait\u00a0", "distefanoTW\u00a0", "CasaPoundItalia\u00a0", "giorgiameloni", "FratellidItalia"], "hash": ["fascismo", "antifascismo", "razzismo", "italia", "italiano", "italiaglitaliani", "stopinvasione", "puliziaetnica", "mussolini", "quandoceralui", "hitler", "farequadrato", "apologia", "nazismo", "antinazismo", "fakenews", "complotto", "noeuro", "scontri", "centrisociali", "occupazione", "lavoro", "sinistra", "manifestazione", "blackbloc", "vandalismo", "fanatismo", "destra", "parlamento", "violenza", "polizia", "esercito", "rom", "campirom", "roma", "guerra", "sciopero", "precari", "casa", "mafia", "camorra", "ndrangheta", "sindacato", "clandestino", "immigrato", "immigrati", "barconi", "negri", "cassazione", "pd", "leganord", "fdi", "an", "grillo", "m5s", "donne", "violenzasulledonne", "bambini", "famiglia", "dio", "patria", "difesa", "nazione", "paese", "madeinitaly", "salvini", "populismo", "casapound", "lepen", "schifo", "feccia", "odio", "amore", "forzanuova", "forteprenestino", "nietsche", "ezrapound", "democrazia", "politica", "votare", "elezioni", "parlamento"], "time": 1509234865}
|
||||||
|
{"actions": ["search_and_retweet"], "buddy": ["InfoAntifa", "LibreriAntigone", "romaoccupata", "Assospartaco", "BANDA_BASSOTTI", "rivamesta", "zeropregi", "progettoDegage", "contropiano", "DinamoPress", "ilmanifesto", "Radiondarossa", "repubblica", "notav_info", "Infoaut", "sap_clandestina", "zerocalcare", "FPrenestino", "AnpiRoma", "RFeminista_", "RomaAntifa", "AntifaOstia", "romattiva", "MilitantBlog", "RATM", "matteosalvinimi\u00a0", "gruppohobbit\u00a0", "CircoloFuturista", "MSR_cat\u00a0", "Occidentale", "OrdineNuovo", "romatoday\u00a0", "PBT_Torino", "Nigel_Farage", "UKIP", "SimoneCasaPound\u00a0", "MarcelloRuffo", "IannoneCpi", "ilgiornale\u00a0", "ChiaraScalzi85\u00a0", "BloccoStudentesco\u00a0", "prog_sociale", "ForzaNuova\u00a0", "AlbaDoratait\u00a0", "distefanoTW\u00a0", "CasaPoundItalia\u00a0", "giorgiameloni", "FratellidItalia"], "hash": ["fascismo", "antifascismo", "razzismo", "italia", "italiano", "italiaglitaliani", "stopinvasione", "puliziaetnica", "mussolini", "quandoceralui", "hitler", "farequadrato", "apologia", "nazismo", "antinazismo", "fakenews", "complotto", "noeuro", "scontri", "centrisociali", "occupazione", "lavoro", "sinistra", "manifestazione", "blackbloc", "vandalismo", "fanatismo", "destra", "parlamento", "violenza", "polizia", "esercito", "rom", "campirom", "roma", "guerra", "sciopero", "precari", "casa", "mafia", "camorra", "ndrangheta", "sindacato", "clandestino", "immigrato", "immigrati", "barconi", "negri", "cassazione", "pd", "leganord", "fdi", "an", "grillo", "m5s", "donne", "violenzasulledonne", "bambini", "famiglia", "dio", "patria", "difesa", "nazione", "paese", "madeinitaly", "salvini", "populismo", "casapound", "lepen", "schifo", "feccia", "odio", "amore", "forzanuova", "forteprenestino", "nietsche", "ezrapound", "democrazia", "politica", "votare", "elezioni", "parlamento"], "time": 1509234890}
|
||||||
|
{"actions": ["search_and_retweet"], "buddy": ["InfoAntifa", "LibreriAntigone", "romaoccupata", "Assospartaco", "BANDA_BASSOTTI", "rivamesta", "zeropregi", "progettoDegage", "contropiano", "DinamoPress", "ilmanifesto", "Radiondarossa", "repubblica", "notav_info", "Infoaut", "sap_clandestina", "zerocalcare", "FPrenestino", "AnpiRoma", "RFeminista_", "RomaAntifa", "AntifaOstia", "romattiva", "MilitantBlog", "RATM", "matteosalvinimi\u00a0", "gruppohobbit\u00a0", "CircoloFuturista", "MSR_cat\u00a0", "Occidentale", "OrdineNuovo", "romatoday\u00a0", "PBT_Torino", "Nigel_Farage", "UKIP", "SimoneCasaPound\u00a0", "MarcelloRuffo", "IannoneCpi", "ilgiornale\u00a0", "ChiaraScalzi85\u00a0", "BloccoStudentesco\u00a0", "prog_sociale", "ForzaNuova\u00a0", "AlbaDoratait\u00a0", "distefanoTW\u00a0", "CasaPoundItalia\u00a0", "giorgiameloni", "FratellidItalia"], "hash": ["fascismo", "antifascismo", "razzismo", "italia", "italiano", "italiaglitaliani", "stopinvasione", "puliziaetnica", "mussolini", "quandoceralui", "hitler", "farequadrato", "apologia", "nazismo", "antinazismo", "fakenews", "complotto", "noeuro", "scontri", "centrisociali", "occupazione", "lavoro", "sinistra", "manifestazione", "blackbloc", "vandalismo", "fanatismo", "destra", "parlamento", "violenza", "polizia", "esercito", "rom", "campirom", "roma", "guerra", "sciopero", "precari", "casa", "mafia", "camorra", "ndrangheta", "sindacato", "clandestino", "immigrato", "immigrati", "barconi", "negri", "cassazione", "pd", "leganord", "fdi", "an", "grillo", "m5s", "donne", "violenzasulledonne", "bambini", "famiglia", "dio", "patria", "difesa", "nazione", "paese", "madeinitaly", "salvini", "populismo", "casapound", "lepen", "schifo", "feccia", "odio", "amore", "forzanuova", "forteprenestino", "nietsche", "ezrapound", "democrazia", "politica", "votare", "elezioni", "parlamento"], "time": 1509234992}
|
||||||
|
{"actions": ["search_and_retweet"], "buddy": ["InfoAntifa", "LibreriAntigone", "romaoccupata", "Assospartaco", "BANDA_BASSOTTI", "rivamesta", "zeropregi", "progettoDegage", "contropiano", "DinamoPress", "ilmanifesto", "Radiondarossa", "repubblica", "notav_info", "Infoaut", "sap_clandestina", "zerocalcare", "FPrenestino", "AnpiRoma", "RFeminista_", "RomaAntifa", "AntifaOstia", "romattiva", "MilitantBlog", "RATM", "matteosalvinimi\u00a0", "gruppohobbit\u00a0", "CircoloFuturista", "MSR_cat\u00a0", "Occidentale", "OrdineNuovo", "romatoday\u00a0", "PBT_Torino", "Nigel_Farage", "UKIP", "SimoneCasaPound\u00a0", "MarcelloRuffo", "IannoneCpi", "ilgiornale\u00a0", "ChiaraScalzi85\u00a0", "BloccoStudentesco\u00a0", "prog_sociale", "ForzaNuova\u00a0", "AlbaDoratait\u00a0", "distefanoTW\u00a0", "CasaPoundItalia\u00a0", "giorgiameloni", "FratellidItalia"], "hash": ["fascismo", "antifascismo", "razzismo", "italia", "italiano", "italiaglitaliani", "stopinvasione", "puliziaetnica", "mussolini", "quandoceralui", "hitler", "farequadrato", "apologia", "nazismo", "antinazismo", "fakenews", "complotto", "noeuro", "scontri", "centrisociali", "occupazione", "lavoro", "sinistra", "manifestazione", "blackbloc", "vandalismo", "fanatismo", "destra", "parlamento", "violenza", "polizia", "esercito", "rom", "campirom", "roma", "guerra", "sciopero", "precari", "casa", "mafia", "camorra", "ndrangheta", "sindacato", "clandestino", "immigrato", "immigrati", "barconi", "negri", "cassazione", "pd", "leganord", "fdi", "an", "grillo", "m5s", "donne", "violenzasulledonne", "bambini", "famiglia", "dio", "patria", "difesa", "nazione", "paese", "madeinitaly", "salvini", "populismo", "casapound", "lepen", "schifo", "feccia", "odio", "amore", "forzanuova", "forteprenestino", "nietsche", "ezrapound", "democrazia", "politica", "votare", "elezioni", "parlamento"], "time": 1509235079}
|
||||||
|
{"actions": ["search_and_retweet"], "buddy": ["InfoAntifa", "LibreriAntigone", "romaoccupata", "Assospartaco", "BANDA_BASSOTTI", "rivamesta", "zeropregi", "progettoDegage", "contropiano", "DinamoPress", "ilmanifesto", "Radiondarossa", "repubblica", "notav_info", "Infoaut", "sap_clandestina", "zerocalcare", "FPrenestino", "AnpiRoma", "RFeminista_", "RomaAntifa", "AntifaOstia", "romattiva", "MilitantBlog", "RATM", "matteosalvinimi\u00a0", "gruppohobbit\u00a0", "CircoloFuturista", "MSR_cat\u00a0", "Occidentale", "OrdineNuovo", "romatoday\u00a0", "PBT_Torino", "Nigel_Farage", "UKIP", "SimoneCasaPound\u00a0", "MarcelloRuffo", "IannoneCpi", "ilgiornale\u00a0", "ChiaraScalzi85\u00a0", "BloccoStudentesco\u00a0", "prog_sociale", "ForzaNuova\u00a0", "AlbaDoratait\u00a0", "distefanoTW\u00a0", "CasaPoundItalia\u00a0", "giorgiameloni", "FratellidItalia"], "hash": ["fascismo", "antifascismo", "razzismo", "italia", "italiano", "italiaglitaliani", "stopinvasione", "puliziaetnica", "mussolini", "quandoceralui", "hitler", "farequadrato", "apologia", "nazismo", "antinazismo", "fakenews", "complotto", "noeuro", "scontri", "centrisociali", "occupazione", "lavoro", "sinistra", "manifestazione", "blackbloc", "vandalismo", "fanatismo", "destra", "parlamento", "violenza", "polizia", "esercito", "rom", "campirom", "roma", "guerra", "sciopero", "precari", "casa", "mafia", "camorra", "ndrangheta", "sindacato", "clandestino", "immigrato", "immigrati", "barconi", "negri", "cassazione", "pd", "leganord", "fdi", "an", "grillo", "m5s", "donne", "violenzasulledonne", "bambini", "famiglia", "dio", "patria", "difesa", "nazione", "paese", "madeinitaly", "salvini", "populismo", "casapound", "lepen", "schifo", "feccia", "odio", "amore", "forzanuova", "forteprenestino", "nietsche", "ezrapound", "democrazia", "politica", "votare", "elezioni", "parlamento"], "time": 1509235175}
|
||||||
|
{"actions": ["search_and_retweet"], "buddy": ["InfoAntifa", "LibreriAntigone", "romaoccupata", "Assospartaco", "BANDA_BASSOTTI", "rivamesta", "zeropregi", "progettoDegage", "contropiano", "DinamoPress", "ilmanifesto", "Radiondarossa", "repubblica", "notav_info", "Infoaut", "sap_clandestina", "zerocalcare", "FPrenestino", "AnpiRoma", "RFeminista_", "RomaAntifa", "AntifaOstia", "romattiva", "MilitantBlog", "RATM", "matteosalvinimi\u00a0", "gruppohobbit\u00a0", "CircoloFuturista", "MSR_cat\u00a0", "Occidentale", "OrdineNuovo", "romatoday\u00a0", "PBT_Torino", "Nigel_Farage", "UKIP", "SimoneCasaPound\u00a0", "MarcelloRuffo", "IannoneCpi", "ilgiornale\u00a0", "ChiaraScalzi85\u00a0", "BloccoStudentesco\u00a0", "prog_sociale", "ForzaNuova\u00a0", "AlbaDoratait\u00a0", "distefanoTW\u00a0", "CasaPoundItalia\u00a0", "giorgiameloni", "FratellidItalia"], "hash": ["fascismo", "antifascismo", "razzismo", "italia", "italiano", "italiaglitaliani", "stopinvasione", "puliziaetnica", "mussolini", "quandoceralui", "hitler", "farequadrato", "apologia", "nazismo", "antinazismo", "fakenews", "complotto", "noeuro", "scontri", "centrisociali", "occupazione", "lavoro", "sinistra", "manifestazione", "blackbloc", "vandalismo", "fanatismo", "destra", "parlamento", "violenza", "polizia", "esercito", "rom", "campirom", "roma", "guerra", "sciopero", "precari", "casa", "mafia", "camorra", "ndrangheta", "sindacato", "clandestino", "immigrato", "immigrati", "barconi", "negri", "cassazione", "pd", "leganord", "fdi", "an", "grillo", "m5s", "donne", "violenzasulledonne", "bambini", "famiglia", "dio", "patria", "difesa", "nazione", "paese", "madeinitaly", "salvini", "populismo", "casapound", "lepen", "schifo", "feccia", "odio", "amore", "forzanuova", "forteprenestino", "nietsche", "ezrapound", "democrazia", "politica", "votare", "elezioni", "parlamento"], "time": 1509235215}
|
||||||
|
{"actions": ["search_and_retweet"], "buddy": ["InfoAntifa", "LibreriAntigone", "romaoccupata", "Assospartaco", "BANDA_BASSOTTI", "rivamesta", "zeropregi", "progettoDegage", "contropiano", "DinamoPress", "ilmanifesto", "Radiondarossa", "repubblica", "notav_info", "Infoaut", "sap_clandestina", "zerocalcare", "FPrenestino", "AnpiRoma", "RFeminista_", "RomaAntifa", "AntifaOstia", "romattiva", "MilitantBlog", "RATM", "matteosalvinimi\u00a0", "gruppohobbit\u00a0", "CircoloFuturista", "MSR_cat\u00a0", "Occidentale", "OrdineNuovo", "romatoday\u00a0", "PBT_Torino", "Nigel_Farage", "UKIP", "SimoneCasaPound\u00a0", "MarcelloRuffo", "IannoneCpi", "ilgiornale\u00a0", "ChiaraScalzi85\u00a0", "BloccoStudentesco\u00a0", "prog_sociale", "ForzaNuova\u00a0", "AlbaDoratait\u00a0", "distefanoTW\u00a0", "CasaPoundItalia\u00a0", "giorgiameloni", "FratellidItalia"], "hash": ["fascismo", "antifascismo", "razzismo", "italia", "italiano", "italiaglitaliani", "stopinvasione", "puliziaetnica", "mussolini", "quandoceralui", "hitler", "farequadrato", "apologia", "nazismo", "antinazismo", "fakenews", "complotto", "noeuro", "scontri", "centrisociali", "occupazione", "lavoro", "sinistra", "manifestazione", "blackbloc", "vandalismo", "fanatismo", "destra", "parlamento", "violenza", "polizia", "esercito", "rom", "campirom", "roma", "guerra", "sciopero", "precari", "casa", "mafia", "camorra", "ndrangheta", "sindacato", "clandestino", "immigrato", "immigrati", "barconi", "negri", "cassazione", "pd", "leganord", "fdi", "an", "grillo", "m5s", "donne", "violenzasulledonne", "bambini", "famiglia", "dio", "patria", "difesa", "nazione", "paese", "madeinitaly", "salvini", "populismo", "casapound", "lepen", "schifo", "feccia", "odio", "amore", "forzanuova", "forteprenestino", "nietsche", "ezrapound", "democrazia", "politica", "votare", "elezioni", "parlamento"], "time": 1509235242}
|
||||||
|
{"actions": ["search_and_retweet"], "buddy": ["InfoAntifa", "LibreriAntigone", "romaoccupata", "Assospartaco", "BANDA_BASSOTTI", "rivamesta", "zeropregi", "progettoDegage", "contropiano", "DinamoPress", "ilmanifesto", "Radiondarossa", "repubblica", "notav_info", "Infoaut", "sap_clandestina", "zerocalcare", "FPrenestino", "AnpiRoma", "RFeminista_", "RomaAntifa", "AntifaOstia", "romattiva", "MilitantBlog", "RATM", "matteosalvinimi\u00a0", "gruppohobbit\u00a0", "CircoloFuturista", "MSR_cat\u00a0", "Occidentale", "OrdineNuovo", "romatoday\u00a0", "PBT_Torino", "Nigel_Farage", "UKIP", "SimoneCasaPound\u00a0", "MarcelloRuffo", "IannoneCpi", "ilgiornale\u00a0", "ChiaraScalzi85\u00a0", "BloccoStudentesco\u00a0", "prog_sociale", "ForzaNuova\u00a0", "AlbaDoratait\u00a0", "distefanoTW\u00a0", "CasaPoundItalia\u00a0", "giorgiameloni", "FratellidItalia"], "hash": ["fascismo", "antifascismo", "razzismo", "italia", "italiano", "italiaglitaliani", "stopinvasione", "puliziaetnica", "mussolini", "quandoceralui", "hitler", "farequadrato", "apologia", "nazismo", "antinazismo", "fakenews", "complotto", "noeuro", "scontri", "centrisociali", "occupazione", "lavoro", "sinistra", "manifestazione", "blackbloc", "vandalismo", "fanatismo", "destra", "parlamento", "violenza", "polizia", "esercito", "rom", "campirom", "roma", "guerra", "sciopero", "precari", "casa", "mafia", "camorra", "ndrangheta", "sindacato", "clandestino", "immigrato", "immigrati", "barconi", "negri", "cassazione", "pd", "leganord", "fdi", "an", "grillo", "m5s", "donne", "violenzasulledonne", "bambini", "famiglia", "dio", "patria", "difesa", "nazione", "paese", "madeinitaly", "salvini", "populismo", "casapound", "lepen", "schifo", "feccia", "odio", "amore", "forzanuova", "forteprenestino", "nietsche", "ezrapound", "democrazia", "politica", "votare", "elezioni", "parlamento"], "time": 1509235254}
|
3
requirements.txt
Normal file
3
requirements.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
tweepy
|
||||||
|
pymongo
|
||||||
|
logging
|
37
setup.py
Normal file
37
setup.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
|
||||||
|
def read(fname):
|
||||||
|
with open(os.path.join(os.path.dirname(__file__), fname)) as buf:
|
||||||
|
return buf.read()
|
||||||
|
|
||||||
|
|
||||||
|
conf = dict(
|
||||||
|
name='valeriovive',
|
||||||
|
version='0.1',
|
||||||
|
description='Twitter Filter Bubble Experiment',
|
||||||
|
long_description=read('README.md'),
|
||||||
|
author='cocconat',
|
||||||
|
author_email='g3-3k@paranoici.org',
|
||||||
|
url='https://github.com/g3-3k/valeriovive',
|
||||||
|
license='AGPL',
|
||||||
|
packages=['valeriovive'],
|
||||||
|
install_requires=[
|
||||||
|
'tweepy',
|
||||||
|
'pymongo',
|
||||||
|
'mutagen',
|
||||||
|
'logging',
|
||||||
|
],
|
||||||
|
zip_safe=False,
|
||||||
|
|
||||||
|
classifiers=[
|
||||||
|
"License :: OSI Approved :: GNU Affero General Public License v3",
|
||||||
|
"Operating System :: POSIX :: Linux",
|
||||||
|
"Programming Language :: Python :: 2",
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
setup(**conf)
|
BIN
valeriovive/.twitter_agent.py.swp
Normal file
BIN
valeriovive/.twitter_agent.py.swp
Normal file
Binary file not shown.
6
valeriovive/__init__.py
Normal file
6
valeriovive/__init__.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
from .experiment import Experiment
|
||||||
|
from .nano import Nano
|
||||||
|
from .twitter_agent import TwitterAgent
|
||||||
|
from .scheduler import Scheduler, dict_from_json
|
||||||
|
from .daemon import Daemon
|
52
valeriovive/__main__.py
Normal file
52
valeriovive/__main__.py
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import logging
|
||||||
|
from experiment import ExperimentDaemon, Experiment, ExperimentDebug, ExperimentShell
|
||||||
|
import sys,argparse, os
|
||||||
|
|
||||||
|
def getparser():
|
||||||
|
parser = argparse.ArgumentParser(description='run TIBER instance')
|
||||||
|
parser.add_argument('-c','--conf',dest='conf_file', type=str, default=None,
|
||||||
|
help='configuration_file for the experiment')
|
||||||
|
parser.add_argument('--start', dest='start', action='store_true', default=False,
|
||||||
|
help='start valeriovive ')
|
||||||
|
parser.add_argument('--restart', dest='restart', action='store_true',default=False,
|
||||||
|
help='restart valeriovive ')
|
||||||
|
parser.add_argument('--stop', dest='stop', action='store_true',default=False,
|
||||||
|
help='stop valeriovive ')
|
||||||
|
parser.add_argument('--oneshot', dest='oneshot', action='store_true',default=False,
|
||||||
|
help='do one shot twitter action ')
|
||||||
|
parser.add_argument('--debug', dest='debug', action='store_true',default=False,
|
||||||
|
help='get object in ipython console')
|
||||||
|
parser.add_argument('--remove-friends', dest='remove_friends', action='store_true',default=False,
|
||||||
|
help='remove all following accounts')
|
||||||
|
parser.add_argument('--shell', dest='shell', action='store_true',default=False,
|
||||||
|
help='open a shell')
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging_path=os.path.join(os.getcwd(),'valeriovive/logging.ini')
|
||||||
|
logging.config.fileConfig(logging_path)
|
||||||
|
args = getparser()
|
||||||
|
if args.debug or args.oneshot:
|
||||||
|
exp=ExperimentDebug(args)
|
||||||
|
elif args.shell:
|
||||||
|
print("entering shell!")
|
||||||
|
exp=ExperimentShell()
|
||||||
|
elif args.start:
|
||||||
|
exp=ExperimentDaemon("/tmp/valeriovive.pid", args)
|
||||||
|
exp.start()
|
||||||
|
sys.exit(0)
|
||||||
|
elif args.restart:
|
||||||
|
exp=ExperimentDaemon("/tmp/valeriovive.pid", args)
|
||||||
|
exp.restart()
|
||||||
|
sys.exit(0)
|
||||||
|
elif args.stop:
|
||||||
|
exp=ExperimentDaemon("/tmp/valeriovive.pid", args)
|
||||||
|
exp.stop()
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print ("usage: %s start|stop|restart" % sys.argv[0])
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
|
||||||
|
|
BIN
valeriovive/__pycache__/__init__.cpython-36.pyc
Normal file
BIN
valeriovive/__pycache__/__init__.cpython-36.pyc
Normal file
Binary file not shown.
BIN
valeriovive/__pycache__/__main__.cpython-36.pyc
Normal file
BIN
valeriovive/__pycache__/__main__.cpython-36.pyc
Normal file
Binary file not shown.
BIN
valeriovive/__pycache__/daemon.cpython-36.pyc
Normal file
BIN
valeriovive/__pycache__/daemon.cpython-36.pyc
Normal file
Binary file not shown.
BIN
valeriovive/__pycache__/experiment.cpython-36.pyc
Normal file
BIN
valeriovive/__pycache__/experiment.cpython-36.pyc
Normal file
Binary file not shown.
BIN
valeriovive/__pycache__/nano.cpython-36.pyc
Normal file
BIN
valeriovive/__pycache__/nano.cpython-36.pyc
Normal file
Binary file not shown.
BIN
valeriovive/__pycache__/scheduler.cpython-36.pyc
Normal file
BIN
valeriovive/__pycache__/scheduler.cpython-36.pyc
Normal file
Binary file not shown.
BIN
valeriovive/__pycache__/twitter_agent.cpython-36.pyc
Normal file
BIN
valeriovive/__pycache__/twitter_agent.cpython-36.pyc
Normal file
Binary file not shown.
138
valeriovive/daemon.py
Normal file
138
valeriovive/daemon.py
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# This class contains the class for the Linux system daemon.
|
||||||
|
|
||||||
|
|
||||||
|
import sys, os, time, atexit
|
||||||
|
from signal import SIGTERM
|
||||||
|
import logging
|
||||||
|
class Daemon:
|
||||||
|
"""
|
||||||
|
A generic daemon class.
|
||||||
|
|
||||||
|
Usage: subclass the Daemon class and override the run() method
|
||||||
|
"""
|
||||||
|
def __init__(self, pidfile, args, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
|
||||||
|
self.stdin = stdin
|
||||||
|
self.stdout = stdout
|
||||||
|
self.stderr = stderr
|
||||||
|
self.pidfile = pidfile
|
||||||
|
self.args = args
|
||||||
|
self.log = logging.getLogger("daemon")
|
||||||
|
|
||||||
|
|
||||||
|
def daemonize(self):
|
||||||
|
"""
|
||||||
|
do the UNIX double-fork magic, see Stevens' "Advanced
|
||||||
|
Programming in the UNIX Environment" for details (ISBN 0201563177)
|
||||||
|
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
pid = os.fork()
|
||||||
|
if pid > 0:
|
||||||
|
# exit first parent
|
||||||
|
sys.exit(0)
|
||||||
|
except OSError as e:
|
||||||
|
self.log.error("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# decouple from parent environment
|
||||||
|
ex_path=os.getcwd()
|
||||||
|
os.chdir("/")
|
||||||
|
os.setsid()
|
||||||
|
os.umask(0)
|
||||||
|
|
||||||
|
# do second fork
|
||||||
|
try:
|
||||||
|
pid = os.fork()
|
||||||
|
if pid > 0:
|
||||||
|
# exit from second parent
|
||||||
|
sys.exit(0)
|
||||||
|
except OSError as e:
|
||||||
|
self.log.error("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# # redirect standard file descriptors
|
||||||
|
# sys.stdout.flush()
|
||||||
|
# sys.stderr.flush()
|
||||||
|
# si = file(self.stdin, 'r')
|
||||||
|
# so = file(self.stdout, 'a+')
|
||||||
|
# se = file(self.stderr, 'a+', 0)
|
||||||
|
# os.dup2(si.fileno(), sys.stdin.fileno())
|
||||||
|
# os.dup2(so.fileno(), sys.stdout.fileno())
|
||||||
|
# os.dup2(se.fileno(), sys.stderr.fileno())
|
||||||
|
|
||||||
|
# write pidfile
|
||||||
|
atexit.register(self.delpid)
|
||||||
|
pid = str(os.getpid())
|
||||||
|
open(self.pidfile,'w+').write("%s\n" % pid)
|
||||||
|
os.chdir(ex_path)
|
||||||
|
|
||||||
|
def delpid(self):
|
||||||
|
os.remove(self.pidfile)
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
"""
|
||||||
|
Start the daemon
|
||||||
|
"""
|
||||||
|
self.log.debug("daemon started")
|
||||||
|
# Check for a pidfile to see if the daemon already runs
|
||||||
|
try:
|
||||||
|
pf = open(self.pidfile,'r')
|
||||||
|
pid = int(pf.read().strip())
|
||||||
|
pf.close()
|
||||||
|
except IOError:
|
||||||
|
pid = None
|
||||||
|
|
||||||
|
if pid:
|
||||||
|
message = "pidfile %s already exist. Daemon already running?\n"
|
||||||
|
sys.stderr.write(message % self.pidfile)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Start the daemon
|
||||||
|
self.daemonize()
|
||||||
|
self.run()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
"""
|
||||||
|
Stop the daemon
|
||||||
|
"""
|
||||||
|
self.log.debug("daemon stopped ")
|
||||||
|
# Get the pid from the pidfile
|
||||||
|
try:
|
||||||
|
pf = open(self.pidfile,'r')
|
||||||
|
pid = int(pf.read().strip())
|
||||||
|
pf.close()
|
||||||
|
except IOError:
|
||||||
|
pid = None
|
||||||
|
|
||||||
|
if not pid:
|
||||||
|
message = "pidfile %s does not exist. Daemon not running?\n"
|
||||||
|
sys.stderr.write(message % self.pidfile)
|
||||||
|
return # not an error in a restart
|
||||||
|
|
||||||
|
# Try killing the daemon process
|
||||||
|
try:
|
||||||
|
while 1:
|
||||||
|
os.kill(pid, SIGTERM)
|
||||||
|
time.sleep(0.1)
|
||||||
|
except OSError as err:
|
||||||
|
err = str(err)
|
||||||
|
if err.find("No such process") > 0:
|
||||||
|
if os.path.exists(self.pidfile):
|
||||||
|
os.remove(self.pidfile)
|
||||||
|
else:
|
||||||
|
print (str(err))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def restart(self):
|
||||||
|
"""
|
||||||
|
Restart the daemon
|
||||||
|
"""
|
||||||
|
self.stop()
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""
|
||||||
|
You should override this method when you subclass Daemon. It will be called after the process has been
|
||||||
|
daemonized by start() or restart().
|
||||||
|
"""
|
31
valeriovive/database.py
Normal file
31
valeriovive/database.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
class DB(object):
|
||||||
|
'''
|
||||||
|
db.add({timestamp: time.time(),
|
||||||
|
agent: 'tizio',
|
||||||
|
action: 'search',
|
||||||
|
target: 'tasse'
|
||||||
|
})
|
||||||
|
db.add({timestamp: time.time(),
|
||||||
|
agent: 'tizio',
|
||||||
|
action: 'wall',
|
||||||
|
seen: [
|
||||||
|
{user: 'zerogreggi', msg: 'ho le pecore'},
|
||||||
|
{user: 'caio', msg: 'ci faccio il formaggio'},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
searches = [s for s in db.all() if s['action'] == 'wall']
|
||||||
|
'''
|
||||||
|
def __init__(self, fname):
|
||||||
|
self.fname = fname
|
||||||
|
|
||||||
|
def add(self, doc):
|
||||||
|
with open(self.fname, 'a') as buf:
|
||||||
|
buf.write(json.dumps(doc))
|
||||||
|
buf.write('\n')
|
||||||
|
|
||||||
|
def all(self):
|
||||||
|
with open(self.fname) as buf:
|
||||||
|
for line in buf:
|
||||||
|
yield json.loads(line)
|
134
valeriovive/experiment.py
Normal file
134
valeriovive/experiment.py
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
from valeriovive.nano import Nano
|
||||||
|
from valeriovive.scheduler import Scheduler,dict_from_json
|
||||||
|
|
||||||
|
import logging.config
|
||||||
|
import sys, time, os
|
||||||
|
from valeriovive.daemon import Daemon
|
||||||
|
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
|
||||||
|
class ExperimentDaemon(Daemon):
|
||||||
|
def run(self):
|
||||||
|
experiment=Experiment(self.args)
|
||||||
|
experiment.start_experiment()
|
||||||
|
|
||||||
|
def ExperimentShell():
|
||||||
|
Experiment.run_shell()
|
||||||
|
|
||||||
|
|
||||||
|
def ExperimentDebug(args):
|
||||||
|
experiment=Experiment(args)
|
||||||
|
experiment.oneshot()
|
||||||
|
|
||||||
|
class Experiment(Scheduler):
|
||||||
|
"""
|
||||||
|
Experiment classs
|
||||||
|
controls the evolution of the experiment with the Scheduler
|
||||||
|
Each parameter can be set through this class
|
||||||
|
As many config file as many bots will be created, the bot are stored
|
||||||
|
in the 'bots' attribute.
|
||||||
|
"""
|
||||||
|
def __init__(self,*args, **kwargs):
|
||||||
|
self.log = logging.getLogger("root")
|
||||||
|
Scheduler.__init__(self, self.events_manager)
|
||||||
|
self.bots=[]
|
||||||
|
if "conf" in kwargs:
|
||||||
|
self.prepare_experiment(kwargs["conf"])
|
||||||
|
if "remove_friends" in kwargs:
|
||||||
|
self.remove_friends=True
|
||||||
|
self.log.debug("Experiment configured with {}".format(self.conf_file ))
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_experiment(cls, **kwargs):
|
||||||
|
return Experiment(kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
Prepare experiment with conf_file params
|
||||||
|
"""
|
||||||
|
def prepare_experiment(self, conf_file=None):
|
||||||
|
|
||||||
|
##set the conf file or use the default
|
||||||
|
if isinstance(conf_file, str):
|
||||||
|
self.conf = dict_from_json(conf_file)
|
||||||
|
self.conf_file = os.path.join(os.getcwd(),conf_file)
|
||||||
|
else:
|
||||||
|
self.log.error("if you re not setting conf file, you are wrong")
|
||||||
|
self.conf_file = os.path.join(os.getcwd(),'valeriovive/nani.json')
|
||||||
|
self.conf = dict_from_json(self.conf_file)
|
||||||
|
self.log.debug("conf file is {}".format(self.conf_file))
|
||||||
|
|
||||||
|
##pass the conf file to each agent
|
||||||
|
for agent in self.conf['agents']:
|
||||||
|
nano = Nano(agent, self.conf_file)
|
||||||
|
self.bots.append(nano)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def run_shell():
|
||||||
|
settings={}
|
||||||
|
|
||||||
|
while True:
|
||||||
|
s = input()
|
||||||
|
if s == "start":
|
||||||
|
exp = Experiment.create_experiment(settings)
|
||||||
|
elif s == "set conf":
|
||||||
|
print("digit the path to conf file")
|
||||||
|
conf_path = input()
|
||||||
|
try:
|
||||||
|
settings["conf"]=conf_path
|
||||||
|
except:
|
||||||
|
print("set configuration failed")
|
||||||
|
elif s == "remove friends":
|
||||||
|
settings["remove_friends"]=True
|
||||||
|
elif s == "exit" or s == "quit" or s == "q":
|
||||||
|
# break
|
||||||
|
|
||||||
|
def start_experiment(self, duration=0):
|
||||||
|
'''
|
||||||
|
Start the experiment.
|
||||||
|
Argument:
|
||||||
|
duration -- expressed in seconds
|
||||||
|
if duration not set, it will continue indefinitely
|
||||||
|
'''
|
||||||
|
self.log.debug("Experiment routine starting")
|
||||||
|
self.routine_manager(self.conf_file)
|
||||||
|
|
||||||
|
def oneshot(self):
|
||||||
|
"""
|
||||||
|
Play one only experience for the bot"
|
||||||
|
"""
|
||||||
|
self.log.debug("Experiment one shot")
|
||||||
|
for nano in self.bots:
|
||||||
|
if self.remove_friends:
|
||||||
|
nano.remove_friends()
|
||||||
|
else:
|
||||||
|
nano.set_behaviour()
|
||||||
|
nano.online_experience()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def common_hours(self):
|
||||||
|
return self.conf['common']['hours']
|
||||||
|
|
||||||
|
def events_manager(self):
|
||||||
|
"""
|
||||||
|
Do the relevant action for the experiment:
|
||||||
|
1) For each nano, at scheduled time, start online experience
|
||||||
|
"""
|
||||||
|
for nano in self.bots:
|
||||||
|
nano.set_behaviour()
|
||||||
|
##retrieve action hours
|
||||||
|
try:
|
||||||
|
nano.events = Scheduler.events_from_hours(nano.get_hours())
|
||||||
|
except:
|
||||||
|
nano.events = Scheduler.events_from_hours(self.common_hours)
|
||||||
|
##schedule actions
|
||||||
|
for event_time in nano.events:
|
||||||
|
self.schedule_event(event_time, nano.online_experience)
|
||||||
|
logging.debug("nano {} scheduled at {}".format(nano.name, str(event_time)))
|
||||||
|
|
||||||
|
|
||||||
|
|
39
valeriovive/logging.ini
Normal file
39
valeriovive/logging.ini
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
[loggers]
|
||||||
|
keys=root
|
||||||
|
|
||||||
|
[handlers]
|
||||||
|
keys=consoleHandler
|
||||||
|
|
||||||
|
[formatters]
|
||||||
|
keys=simpleFormatter
|
||||||
|
|
||||||
|
[logger_root]
|
||||||
|
level=DEBUG
|
||||||
|
handlers=consoleHandler
|
||||||
|
|
||||||
|
[logger_scheduler]
|
||||||
|
level=DEBUG
|
||||||
|
handlers=consoleHandler
|
||||||
|
|
||||||
|
[logger_daemon]
|
||||||
|
level=DEBUG
|
||||||
|
handlers=consoleHandler
|
||||||
|
|
||||||
|
[logger_twitter_agent]
|
||||||
|
level=DEBUG
|
||||||
|
handlers=consoleHandler
|
||||||
|
|
||||||
|
[logger_nano]
|
||||||
|
level=DEBUG
|
||||||
|
handlers=consoleHandler
|
||||||
|
|
||||||
|
[handler_consoleHandler]
|
||||||
|
class=StreamHandler
|
||||||
|
level=DEBUG
|
||||||
|
formatter=simpleFormatter
|
||||||
|
args=(sys.stdout,)
|
||||||
|
|
||||||
|
[formatter_simpleFormatter]
|
||||||
|
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
|
||||||
|
datefmt=
|
||||||
|
|
31
valeriovive/nani.json
Normal file
31
valeriovive/nani.json
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{"agents":["sbinzolo"],
|
||||||
|
"individual_behaviour":false,
|
||||||
|
"sbinzolo":{
|
||||||
|
"name":"sbinzolo",
|
||||||
|
"dbpath": "sbinzolo.db",
|
||||||
|
"twitter":{
|
||||||
|
"consumer_key":"wG4qh5Uu9WAJiJAtYHEOUoTPd",
|
||||||
|
"consumer_set":"lR9mCtErxJ1rWwNaR9RtvpmSsKs301qxvwCt0658CUjAkydMXx",
|
||||||
|
"access_token":"863857515276230657-UajuyvISnw8537s8lXUBLI8h2zudpYR",
|
||||||
|
"secret_token":"UMBh1YFokq85Sl48FTFl0V4fJa7vBhwViyta8KOpe5lCq"
|
||||||
|
},
|
||||||
|
"actions":["search_and_retweet","search_and_follow","retweet_my_friends"],
|
||||||
|
"buddies":["Leila","Armando","FortePrenestino"],
|
||||||
|
"hashtags":["fasciappesi","cazziemazzi","giuliascopa"],
|
||||||
|
"hours":[0, 10, 17, 23]
|
||||||
|
},
|
||||||
|
"common":{
|
||||||
|
"actions":["search_and_retweet","search_and_follow","retweet_my_friends"],
|
||||||
|
"buddies":["Leila","Armando","FortePrenestino"],
|
||||||
|
"hashtags":["fasciappesi","cazziemazzi","giuliascopa"],
|
||||||
|
"hours":[0, 10, 17, 23],
|
||||||
|
"end_date":"2020-04-03",
|
||||||
|
"scheduler_interval":"midnight",
|
||||||
|
"buddies" : [
|
||||||
|
"InfoAntifa","LibreriAntigone","romaoccupata","Assospartaco","BANDA_BASSOTTI","rivamesta","zeropregi","progettoDegage","contropiano","DinamoPress","ilmanifesto","Radiondarossa","repubblica","notav_info","Infoaut","sap_clandestina","zerocalcare","FPrenestino","AnpiRoma","RFeminista_","RomaAntifa",
|
||||||
|
"AntifaOstia","romattiva","MilitantBlog","RATM","matteosalvinimi ","gruppohobbit ","CircoloFuturista","MSR_cat ","Occidentale","OrdineNuovo","romatoday ","PBT_Torino ","Nigel_Farage ","UKIP”,”SimoneCasaPound ","MarcelloRuffo ","IannoneCpi ","ilgiornale ","ChiaraScalzi85 ","BloccoStudentesco ","prog_sociale","ForzaNuova ","AlbaDoratait ","distefanoTW ","CasaPoundItalia ","giorgiameloni","FratellidItalia"],
|
||||||
|
|
||||||
|
"hashtags" : ["fascismo","antifascismo","razzismo","italia","italiano","italiaglitaliani","stopinvasione","puliziaetnica","mussolini","quandoceralui","hitler","farequadrato","apologia","nazismo","antinazismo","fakenews","complotto","noeuro","scontri","centrisociali","occupazione","lavoro","sinistra","manifestazione","blackbloc","vandalismo","fanatismo","destra","parlamento","violenza","polizia","esercito","rom","campirom","roma","guerra","sciopero","precari","casa","mafia","camorra","ndrangheta","sindacato","clandestino","immigrato","immigrati","barconi","negri","cassazione","pd","leganord","fdi","an","grillo","m5s","donne","violenzasulledonne","bambini","famiglia","dio","patria","difesa","nazione","paese","madeinitaly","salvini","populismo","casapound","lepen","schifo","feccia","odio","amore","forzanuova","forteprenestino","nietsche","ezrapound","democrazia","politica","votare","elezioni","parlamento"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
134
valeriovive/nano.py
Normal file
134
valeriovive/nano.py
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
from valeriovive.twitter_agent import TwitterAgent
|
||||||
|
import random
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
from valeriovive.scheduler import dict_from_json
|
||||||
|
|
||||||
|
|
||||||
|
class Nano:
|
||||||
|
'''
|
||||||
|
Create Nano Object
|
||||||
|
Nano is the active element of the experiment,it does stuff
|
||||||
|
Nano remains during all the experiment.
|
||||||
|
Nano is actually the bot and will be initialited with conf.file path. That cannot change.
|
||||||
|
Nano has no perception of time.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
==========
|
||||||
|
CONF:
|
||||||
|
common_conf dict See README
|
||||||
|
own_conf dict See README
|
||||||
|
|
||||||
|
__twitter_agent TwitterAgent(Tweepy)
|
||||||
|
|
||||||
|
Behaviour:
|
||||||
|
actions set of __twitter agent methods
|
||||||
|
buddy_list list(strigs)
|
||||||
|
hash_list
|
||||||
|
events list(hours(int[0-23]))
|
||||||
|
|
||||||
|
Methods
|
||||||
|
===========
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
def __init__(self, name, conf_file):
|
||||||
|
self.name=name
|
||||||
|
self.conf_file=conf_file
|
||||||
|
self.twitter_agent = TwitterAgent(name,dict_from_json(self.conf_file)[self.name]["twitter"])
|
||||||
|
self.actions =[]
|
||||||
|
###
|
||||||
|
self.buddy_list = []
|
||||||
|
self.hash_list = []
|
||||||
|
self.actions_list =[]
|
||||||
|
|
||||||
|
self.events=None
|
||||||
|
|
||||||
|
### loggers
|
||||||
|
self.logger = logging.getLogger(name)
|
||||||
|
self.logger.info('created Nano {} obj, and file {}'.format(self.name,conf_file))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def conf(self):
|
||||||
|
return dict_from_json(self.conf_file)[self.name]
|
||||||
|
|
||||||
|
# def twitter_conf(conf_file):
|
||||||
|
# try:
|
||||||
|
# return dict_from_json(conf_file)[self.name]["twitter"]
|
||||||
|
# except KeyError:
|
||||||
|
# raise ValueError("missing twitter conf in the configuration file")
|
||||||
|
"""
|
||||||
|
Set behaviour
|
||||||
|
|
||||||
|
Dict needs to contain buddies , hashtags , actions
|
||||||
|
"""
|
||||||
|
def set_behaviour(self):
|
||||||
|
if self.buddy_list == dict_from_json(self.conf_file)["individual_behaviour"]:
|
||||||
|
self.buddy_list = dict_from_json(self.conf_file)[self.name]['buddies']
|
||||||
|
self.hash_list = dict_from_json(self.conf_file)[self.name]['hashtags']
|
||||||
|
self.actions_list = dict_from_json(self.conf_file)[self.name]['actions']
|
||||||
|
else:
|
||||||
|
self.buddy_list = dict_from_json(self.conf_file)["common"]['buddies']
|
||||||
|
self.hash_list = dict_from_json(self.conf_file)["common"]['hashtags']
|
||||||
|
self.actions_list = dict_from_json(self.conf_file)["common"]['actions']
|
||||||
|
self.logger.debug("buddies: {} \n, hashtags: {} \n, actions: {}\n".format(self.buddy_list,self.hash_list,self.actions_list))
|
||||||
|
self.get_actions()
|
||||||
|
|
||||||
|
def get_hours(self):
|
||||||
|
return dict_from_json(self.conf_file[self.name]['hours'])
|
||||||
|
|
||||||
|
def get_actions(self):
|
||||||
|
"""
|
||||||
|
Retrieve functions from config and add to actions_list
|
||||||
|
"""
|
||||||
|
self.actions=[]
|
||||||
|
if "search_and_follow" in self.actions_list:
|
||||||
|
self.actions.append(self.twitter_agent.search_and_follow)
|
||||||
|
if "search_and_retweet" in self.actions_list:
|
||||||
|
self.actions.append(self.twitter_agent.search_and_retweet)
|
||||||
|
if "get_user_timeline" in self.actions_list:
|
||||||
|
self.actions.append(self.twitter_agent.get_user_timeline)
|
||||||
|
if "destroy_all_friends" in self.actions_list:
|
||||||
|
self.actions.append(self.twitter_agent.destroy_all_friends)
|
||||||
|
|
||||||
|
# if "retweet_my_friends" in self.actions:
|
||||||
|
# self.actions.append(self.__twitter_agent.retweet_my_friends)
|
||||||
|
|
||||||
|
"""
|
||||||
|
Start Online Session
|
||||||
|
log with tweepy and do stuff as in behaviour
|
||||||
|
"""
|
||||||
|
def online_experience(self):
|
||||||
|
random.shuffle(self.actions)
|
||||||
|
self.twitter_agent.connect()
|
||||||
|
if not self.twitter_agent.connected:
|
||||||
|
self.logger.error("cannot connect to Twitter!")
|
||||||
|
return
|
||||||
|
# self.twitter_agent.get_user_timeline()
|
||||||
|
for action in self.actions:
|
||||||
|
self.logger.debug("next action is {}".format(action.__name__))
|
||||||
|
try:
|
||||||
|
action(self.buddy_list, self.hash_list)
|
||||||
|
except :
|
||||||
|
self.logger.exception("Action {} failed".format(action.__name__))
|
||||||
|
if 'dbpath' in self.conf:
|
||||||
|
with open(self.conf['dbpath'], 'a') as buf:
|
||||||
|
record = {}
|
||||||
|
record['actions'] = [a.__name__ for a in self.actions]
|
||||||
|
record['buddy']= self.buddy_list
|
||||||
|
record['hash'] = self.hash_list
|
||||||
|
record['time'] = int(time.time())
|
||||||
|
buf.write(json.dumps(record))
|
||||||
|
buf.write("\n")
|
||||||
|
|
||||||
|
def remove_friends(self):
|
||||||
|
self.twitter_agent.connect()
|
||||||
|
try:
|
||||||
|
self.twitter_agent.destroy_all_friends()
|
||||||
|
except :
|
||||||
|
self.logger.error("cannot connect to Twitter!")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
0
valeriovive/nanoBot.sh
Normal file
0
valeriovive/nanoBot.sh
Normal file
77
valeriovive/scheduler.py
Normal file
77
valeriovive/scheduler.py
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import json, sched, datetime, time
|
||||||
|
import logging
|
||||||
|
import threading
|
||||||
|
import random
|
||||||
|
|
||||||
|
def dict_from_json(json_file):
|
||||||
|
with open(json_file) as json_data:
|
||||||
|
dict_ = json.load(json_data)
|
||||||
|
return dict_
|
||||||
|
|
||||||
|
class Scheduler:
|
||||||
|
def __init__(self, events_manager):
|
||||||
|
self.log = logging.getLogger(__name__)
|
||||||
|
self.log.info(" starting {} ".format(__name__))
|
||||||
|
self.events = []
|
||||||
|
self.hours = []
|
||||||
|
self.events_manager = events_manager
|
||||||
|
|
||||||
|
"""
|
||||||
|
Converts hours in dates.
|
||||||
|
Every day convert the hour in the exact date yyyy-mm-dd hh-mm
|
||||||
|
"""
|
||||||
|
@staticmethod
|
||||||
|
def events_from_hours(hours):
|
||||||
|
if not isinstance(hours, list):
|
||||||
|
hours = list(hours)
|
||||||
|
events = [datetime.datetime.today().replace(hour=hour,
|
||||||
|
minute=random.choice(range(60)))
|
||||||
|
for hour in hours]
|
||||||
|
return events
|
||||||
|
|
||||||
|
def routine_manager(self, conf_file):
|
||||||
|
"""
|
||||||
|
Routine manager
|
||||||
|
Always running untill --stop
|
||||||
|
conf_file is a path to json file.
|
||||||
|
The configuration file is read continously
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
logging.info("routine manager start at {}".format(str(datetime.datetime.now())))
|
||||||
|
conf = dict_from_json(conf_file)['common']
|
||||||
|
except:
|
||||||
|
self.log.error(conf_file+ " is the wrong configuration file")
|
||||||
|
while True and datetime.datetime.now() < datetime.datetime.strptime(conf["end_date"],"%Y-%m-%d"):
|
||||||
|
self.events_manager()
|
||||||
|
self.log.debug("routine manager loop at {}".format(str(datetime.datetime.now())))
|
||||||
|
conf = dict_from_json(conf_file)['common']
|
||||||
|
try:
|
||||||
|
if conf["scheduler_interval"] == "midnight":
|
||||||
|
interval_seconds = (datetime.datetime.today().replace(hour=23, minute=59) - datetime.datetime.now()).total_seconds()
|
||||||
|
self.log.info("Next routine_manager loop at {}".format(datetime.datetime.today().replace(hour=23, minute=59)))
|
||||||
|
if isinstance(conf["scheduler_interval"], int):
|
||||||
|
interval_seconds = datetime.timedelta(hours=conf["scheduler_interval"])
|
||||||
|
except KeyError:
|
||||||
|
self.log.error("Scheduler properties not found in {}", conf_file)
|
||||||
|
time.sleep(interval_seconds)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def schedule_event(event_time, action, **kwargs):
|
||||||
|
"""
|
||||||
|
Schedule event with threading
|
||||||
|
|
||||||
|
Params:
|
||||||
|
==========
|
||||||
|
event_time datetime format
|
||||||
|
action function
|
||||||
|
**kwargs function arguments
|
||||||
|
"""
|
||||||
|
delta = (event_time - datetime.datetime.now()).total_seconds()
|
||||||
|
if delta > 0:
|
||||||
|
logging.debug("time interval to next action is {}".format(delta))
|
||||||
|
T = threading.Timer(int(delta), action, **kwargs)
|
||||||
|
T.start()
|
||||||
|
else:
|
||||||
|
logging.debug("event {} scheduled in the past!".format(str(event_time)))
|
||||||
|
|
||||||
|
|
348
valeriovive/twitter_agent.py
Normal file
348
valeriovive/twitter_agent.py
Normal file
|
@ -0,0 +1,348 @@
|
||||||
|
import tweepy
|
||||||
|
from tweepy import OAuthHandler
|
||||||
|
import tweepy.streaming
|
||||||
|
from tweepy import StreamListener
|
||||||
|
from pymongo import MongoClient
|
||||||
|
import logging
|
||||||
|
import random
|
||||||
|
from copy import copy
|
||||||
|
|
||||||
|
class MyStreamListener(tweepy.StreamListener):
|
||||||
|
|
||||||
|
def on_status(self, status):
|
||||||
|
print(status.text)
|
||||||
|
|
||||||
|
def on_error(self, status_code):
|
||||||
|
if status_code == 420:
|
||||||
|
#returning False in on_data disconnects the stream
|
||||||
|
return False
|
||||||
|
|
||||||
|
class TwitterAgent():
|
||||||
|
"""
|
||||||
|
Twitter_agent class, initiated with keys, is a Tweepy based Object
|
||||||
|
TwitterAgent get init with a dictionary
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
|
||||||
|
name String name of the agent
|
||||||
|
cfg Dict conf
|
||||||
|
api Tweepy Object
|
||||||
|
userdb Pymando db
|
||||||
|
twettsdb Pymando db
|
||||||
|
"""
|
||||||
|
def __init__(self,name,cfg):
|
||||||
|
##cfg is a json with
|
||||||
|
#consumer_key
|
||||||
|
#consumer_set
|
||||||
|
#access_token
|
||||||
|
#secret_token
|
||||||
|
self.name=name
|
||||||
|
self.userdb=None
|
||||||
|
self.tweetsdb=None
|
||||||
|
self.cfg =cfg
|
||||||
|
self.api =None
|
||||||
|
self.db_instance()
|
||||||
|
self.ERROR=[]
|
||||||
|
self.listener = None
|
||||||
|
self.streamer = None
|
||||||
|
|
||||||
|
### loggers
|
||||||
|
self.logger = logging.getLogger(name+": TwitterAgent")
|
||||||
|
self.logger.info('created Twitter Agent{} obj'.format(self.name))
|
||||||
|
"""
|
||||||
|
Authenticate
|
||||||
|
"""
|
||||||
|
@staticmethod
|
||||||
|
def authenticate(cfg):
|
||||||
|
auth=OAuthHandler(cfg["consumer_key"],cfg["consumer_set"])
|
||||||
|
auth.set_access_token(cfg["access_token"],cfg["secret_token"])
|
||||||
|
return tweepy.API(auth), auth
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
self.api , auth= self.authenticate(self.cfg)
|
||||||
|
self.streamer = tweepy.Stream(auth, listener=MyStreamListener())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def connected(self):
|
||||||
|
try:
|
||||||
|
return self.api.me()
|
||||||
|
except:
|
||||||
|
self.logger.error(ValueError)
|
||||||
|
|
||||||
|
"""
|
||||||
|
Instanciate Pymong db [a dictionary type]
|
||||||
|
tweetsdb will cotain the whole tweet
|
||||||
|
userdb will contain tweets's authors and relative followers
|
||||||
|
"""
|
||||||
|
def db_instance(self):
|
||||||
|
try:
|
||||||
|
client=MongoClient('localhost', 27017)
|
||||||
|
db=client.get_database('dict')
|
||||||
|
self.db=db[self.name]
|
||||||
|
#error list it's for those user resulting missing to followers retrieve
|
||||||
|
except:
|
||||||
|
raise ValueError("Error during mongodb initialization")
|
||||||
|
|
||||||
|
"""
|
||||||
|
Add Friends to authenticated user profile
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
buddy_list list(strings) Users list for next session
|
||||||
|
hash_list list(strings) Hash list for next session
|
||||||
|
"""
|
||||||
|
def add_friends(self, buddy_list, hash_list):
|
||||||
|
self.logger.debug("add_friends")
|
||||||
|
if not isinstance(buddy_list,list):
|
||||||
|
buddy_list=list(buddy_list)
|
||||||
|
for buddy in buddy_list:
|
||||||
|
try:
|
||||||
|
self.api.create_friendship(user_id=buddy)
|
||||||
|
except:
|
||||||
|
logging.warning("{} didn't find this buddy: {} \n".format(self.name,buddy))
|
||||||
|
|
||||||
|
"""
|
||||||
|
Search the hash_list and retweet some status
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
buddy_list list(strings) Users list for next session
|
||||||
|
hash_list list(strings) Hash list for next session
|
||||||
|
"""
|
||||||
|
def search_and_retweet(self, buddy_list, hash_list):
|
||||||
|
self.logger.debug("search_and_retweet")
|
||||||
|
if not isinstance(hash_list,list):
|
||||||
|
hash_list=list(hash_list)
|
||||||
|
for tag in hash_list:
|
||||||
|
if random.random() > 0.7:
|
||||||
|
hash_cursor = tweepy.Cursor(self.api.search, q="#"+tag).items()
|
||||||
|
for tweet in hash_cursor:
|
||||||
|
if tweet.retweeted: continue
|
||||||
|
if random.random() > 0.7:
|
||||||
|
print(tweet.id, tweet.user, tweet.retweeted)
|
||||||
|
self.api.retweet(tweet.id)
|
||||||
|
return 0
|
||||||
|
# cursor=tweepy.Cursor("c", id=user, count=5000).pages()
|
||||||
|
|
||||||
|
"""
|
||||||
|
Search the hash_list and follow some users
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
buddy_list list(strings) Users list for next session
|
||||||
|
hash_list list(strings) Hash list for next session
|
||||||
|
"""
|
||||||
|
|
||||||
|
def search_and_follow(self, buddy_list, hash_list):
|
||||||
|
self.logger.debug("search_and_follow")
|
||||||
|
if not isinstance(hash_list,list):
|
||||||
|
hash_list=list(hash_list)
|
||||||
|
my_hash_list = copy(hash_list)
|
||||||
|
random.shuffle(my_hash_list)
|
||||||
|
my_hash_list = my_hash_list[:int(0.3*len(my_hash_list))]
|
||||||
|
for tag in my_hash_list:
|
||||||
|
self.logger.debug("searching for hashtag "+tag)
|
||||||
|
hash_cursor = tweepy.Cursor(self.api.search, q="#"+tag).items(5)
|
||||||
|
for num, tweet in enumerate(hash_cursor):
|
||||||
|
if random.random() > 0.8:
|
||||||
|
self.logger.debug("searching for tweet "+tweet.text)
|
||||||
|
self.api.create_friendship(tweet.author.id)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
"""
|
||||||
|
Search the buddy_list and retweet some users
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
buddy_list list(strings) Users list for next session
|
||||||
|
hash_list list(strings) Hash list for next session
|
||||||
|
"""
|
||||||
|
def retweet_my_friends(self, buddy_list, hash_list):
|
||||||
|
self.logger.debug("retweet_my_friends")
|
||||||
|
if not isinstance(buddy_list, list):
|
||||||
|
buddy_list=list(buddy_list)
|
||||||
|
random.shuffle(buddy_list)
|
||||||
|
for buddy in buddy_list:
|
||||||
|
try:
|
||||||
|
tweets = self.api.user_timeline(screen_name=buddy)
|
||||||
|
#self.stream.filter(buddy, _with='followings', async = True)
|
||||||
|
except:
|
||||||
|
logging.warning("user {} timeline not accesible \n".format(buddy))
|
||||||
|
for tweet in tweets:
|
||||||
|
if random.random()>0.8:
|
||||||
|
self.api.retweet(tweet.id)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def destroy_all_friends(self):
|
||||||
|
self.logger.debug("destroy_all_friends")
|
||||||
|
for friend in self.api.friends_ids(self.api.me().id):
|
||||||
|
self.api.destroy_friendship(friend)
|
||||||
|
|
||||||
|
#This function obtain tweet for the indicated query,
|
||||||
|
#it will save into db untill the element get the willed value-count.
|
||||||
|
#in order to start from last saved tweet after a possible break,
|
||||||
|
#it uses the external parameters lastid, wich is obtained from db itself in runtime
|
||||||
|
|
||||||
|
"""
|
||||||
|
Save the user user timeline
|
||||||
|
"""
|
||||||
|
def get_user_timeline(self):
|
||||||
|
self.logger.debug("get_timeline")
|
||||||
|
try:
|
||||||
|
timeline = self.api.home_timeline(count=200)
|
||||||
|
except:
|
||||||
|
self.logger.error("User timeline return error")
|
||||||
|
for tweet in timeline:
|
||||||
|
self.logger.debug("Tweet from {}, : {}".format(tweet.author.name,tweet.text))
|
||||||
|
self.db.insert({"status":{
|
||||||
|
"author_name":tweet.author.name,
|
||||||
|
"text": tweet.text,
|
||||||
|
"status":tweet._json}
|
||||||
|
})
|
||||||
|
self.logger.debug("item inserted in the db")
|
||||||
|
return 0
|
||||||
|
# def save_tweets(self,db,query,api=None,count=5000,lastid=0):
|
||||||
|
# api=self.api
|
||||||
|
# try:
|
||||||
|
# while db.count() <count:
|
||||||
|
# cursor=api[0].search(q=query,since_id=lastid)
|
||||||
|
# for tweet in cursor:
|
||||||
|
# #some information will be saved, this isn't complete but exahustive
|
||||||
|
# db.insert({"status":{"author_name":tweet.author.name,\
|
||||||
|
# "author_id":tweet.author.id,\
|
||||||
|
# "author_json":tweet.author._json,\
|
||||||
|
# "status_json":tweet._json}\
|
||||||
|
# })
|
||||||
|
# lastid=tweet.id
|
||||||
|
# return lastid
|
||||||
|
# except:
|
||||||
|
# return lastid
|
||||||
|
|
||||||
|
#this function returns all elements already "scrapied", that is which followers already are in userdb.
|
||||||
|
#this is to restart program since any lose too.
|
||||||
|
# def scrapied (self,userdb=None):
|
||||||
|
# userdb=self.userdb
|
||||||
|
# for i in userdb.find():
|
||||||
|
# yield int(i['user'].keys()[0])
|
||||||
|
|
||||||
|
# #a simple rotate function very usefull for api index scrolling
|
||||||
|
# def rotate(self,l):
|
||||||
|
# return l[1:] + l[:1]
|
||||||
|
|
||||||
|
# #it parses tweetsdb and return all authors, obviously the db is parsed only at first instance,
|
||||||
|
# #then everything is saved to user_list, and authors popped from there.
|
||||||
|
# #
|
||||||
|
|
||||||
|
# def get_users(self, tweetsdb, last_user=0, user_list=False):
|
||||||
|
# tweetsdb=self.tweetsdb
|
||||||
|
# if user_list:
|
||||||
|
# #pop an item from list and return it
|
||||||
|
# user_list.pop(0)
|
||||||
|
# return user_list
|
||||||
|
# else:
|
||||||
|
# users=[int(str(user['status']['author_id']).strip()) for user in tweetsdb.find()]
|
||||||
|
# user_list=sorted(set(users),reverse=True)[last_user:]
|
||||||
|
# #don't reapeat user
|
||||||
|
# for user in scrapied(userdb):
|
||||||
|
# try:
|
||||||
|
# user_list.remove(user)
|
||||||
|
# except:
|
||||||
|
# continue
|
||||||
|
# return user_list
|
||||||
|
|
||||||
|
# #most difficult to write down!
|
||||||
|
# #this function return followers for each author, adopting some tricks to keep memory of cursor
|
||||||
|
# #and same time get a new api when apiratelimit is exceeded
|
||||||
|
# # def get_followers(self,user,api=none):
|
||||||
|
# # api=self.api
|
||||||
|
# # followers=[]
|
||||||
|
# # count=1
|
||||||
|
# # cursor=tweepy.cursor(api[0].followers_ids, id=user, count=5000).pages()
|
||||||
|
# # while true:
|
||||||
|
# # try:
|
||||||
|
# # for page in cursor:
|
||||||
|
# # followers.extend(page)
|
||||||
|
# # print "page", count, "of user", user
|
||||||
|
# # sys.stdout.flush()
|
||||||
|
# # count +=1
|
||||||
|
# # return followers
|
||||||
|
|
||||||
|
# # except tweepy.ratelimiterror:
|
||||||
|
# #new api in case is at zero page retrieved
|
||||||
|
# # if cursor.next_cursor==-1:
|
||||||
|
# # self.rotate(self.api)
|
||||||
|
# # self.get_followers(user)
|
||||||
|
# # else:
|
||||||
|
# # print "let's take a break, it will restart from last page; api_index is", api[0],"current cursor", cursor.next_cursor
|
||||||
|
# # sys.stdout.flush()
|
||||||
|
# # for i in range(15):
|
||||||
|
# # print 15-i, "minutes to wait"
|
||||||
|
# # time.sleep(60)
|
||||||
|
# # continue
|
||||||
|
# # except:
|
||||||
|
# # print "Unexpected!!! on user", user
|
||||||
|
# # self.ERROR.append(user)
|
||||||
|
# # break
|
||||||
|
|
||||||
|
# #this function is a kind of main, retrieve users and scrapies followers for each one, then pop user and reapeat.
|
||||||
|
# def followers(self,api=None,userdb=None,tweetsdb=None):
|
||||||
|
# api=self.api
|
||||||
|
# tweetsdb=self.tweetsdb
|
||||||
|
# userdb=self.userdb
|
||||||
|
# user_list=get_users(tweetsdb)
|
||||||
|
# while user_list:
|
||||||
|
# if api[0].rate_limit_status()['resources']['followers']['/followers/ids']['remaining'] <1:
|
||||||
|
# api=self.rotate(api)
|
||||||
|
# print ("api_index has incremented")
|
||||||
|
|
||||||
|
# user=user_list[0]
|
||||||
|
# followers =self.get_followers(user,api=api)
|
||||||
|
# userdb.insert({"user":{str(user):followers}})
|
||||||
|
# user_list=get_users(tweetsdb,user_list=user_list)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# # In[26]:
|
||||||
|
|
||||||
|
# #lastid=int(tweetsdb.find()[len([tweetsdb.find()])-1]['status']['status_json']['id_str'])
|
||||||
|
|
||||||
|
|
||||||
|
# # In[33]:
|
||||||
|
|
||||||
|
# #len(list(scrapied(userdb)))
|
||||||
|
|
||||||
|
|
||||||
|
# # In[35]:
|
||||||
|
|
||||||
|
# #len(get_users(tweetsdb))
|
||||||
|
|
||||||
|
|
||||||
|
# # In[ ]:
|
||||||
|
# '''
|
||||||
|
# lastid=int(tweetsdb.find()[len([tweetsdb.find()])-1]['status']['status_json']['id_str'])
|
||||||
|
# count=10000
|
||||||
|
# #keep it running until count
|
||||||
|
# while tweetsdb.count() < count:
|
||||||
|
# api_index=0
|
||||||
|
# lastid=get_tweets(db=tweetsdb,api=api,query="Daesh",count=count,lastid=lastid,api_index=api_index)
|
||||||
|
# rotate(api)
|
||||||
|
# print tweetsdb.count()
|
||||||
|
# time.sleep(60*15)
|
||||||
|
|
||||||
|
# if len(get_users(tweetsdb)):
|
||||||
|
# followers(api=api,userdb=userdb,tweetsdb=tweetsdb)
|
||||||
|
# '''
|
||||||
|
|
||||||
|
|
||||||
|
# # In[9]:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# # In[8]:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# # In[34]:
|
||||||
|
|
||||||
|
|
||||||
|
# # In[84]:
|
Loading…
Reference in a new issue