{"id":21048292,"url":"https://github.com/angelbarrera92/ave-round-tripper","last_synced_at":"2025-05-15T19:32:13.252Z","repository":{"id":144305448,"uuid":"528960904","full_name":"angelbarrera92/ave-round-tripper","owner":"angelbarrera92","description":"This project tries to solve a not-so-common problem:  Find the cheapest round trip between two cities on AVE (RENFE) line and get notifications when prices change.  People are not aware of price changes on AVE (RENFE) service. Furthermore, they used to think that the price were always the same.","archived":false,"fork":false,"pushed_at":"2023-06-19T06:41:34.000Z","size":1732,"stargazers_count":5,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-03T13:44:22.496Z","etag":null,"topics":["ave","grafana","renfe","scraper","telegram"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/angelbarrera92.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-08-25T17:53:25.000Z","updated_at":"2024-05-07T10:15:45.000Z","dependencies_parsed_at":null,"dependency_job_id":"137cf8c6-6033-4299-ad04-fd02cc5fb3f3","html_url":"https://github.com/angelbarrera92/ave-round-tripper","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angelbarrera92%2Fave-round-tripper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angelbarrera92%2Fave-round-tripper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angelbarrera92%2Fave-round-tripper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angelbarrera92%2Fave-round-tripper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/angelbarrera92","download_url":"https://codeload.github.com/angelbarrera92/ave-round-tripper/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254407454,"owners_count":22066249,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ave","grafana","renfe","scraper","telegram"],"created_at":"2024-11-19T14:43:06.311Z","updated_at":"2025-05-15T19:32:13.245Z","avatar_url":"https://github.com/angelbarrera92.png","language":"Python","funding_links":[],"categories":["Transporte y Movilidad"],"sub_categories":["Radio y Podcasts"],"readme":"# AVE *(RENFE)* Round Trip\n\nThis project tries to solve a not-so-common problem:\n\n*Find the cheapest round trip between two cities on AVE (RENFE) line and get notifications when prices change.*\n\nPeople are not aware of price changes on AVE *(RENFE)* service. \nFurthermore, they used to think that the price were always the same.\n\n## My personal use case\n\nI go to Zaragoza *(from Madrid)* sometimes per month. I go to Zaragoza early in the morning, and I return to Madrid on the same day. \nSo I need a way to find the cheapest round trip between Zaragoza and Madrid.\n\n## TL;DR\n\nTo make the project run out of the box *(locally)*:\n\n- Modify the `.pg.env` file by adding your telegram bot token and your telegram chat id.\n\n```bash\nexport TRAVEL_NOTIFICATION_TOKEN=\u003cTO_BE_DEFINED\u003e\nexport TRAVEL_NOTIFICATION_CHAT_ID=\u003cTO_BE_DEFINED\u003e\n```\n\n- Then:\n\n```bash\n$ docker-compose up -d\n# or\n$ docker compose up -d\n```\n\nWait a few seconds/minutes, then open your browser and access to [http://localhost:3000/](http://localhost:3000/).\nLog in with the following credentials:\n\n- Username: `ave`\n- Password: `could-be-less-expensive`\n\n![login](resources/images/login.png)\n![dashboards](resources/images/dashboards.png)\n![trains](resources/images/trains.png)\n![telegram](resources/images/telegram.png)\n\n## Develop\n\nYou will require `python` along with `pip` and `virtualenv`.\n\n```bash\n$ virtualenv -p python3 venv\n$ source venv/bin/activate\n$ pip install --upgrade pip\n$ pip install -r requirements-dev.txt\n```\n\nFor a smooth experience, use `docker` and `docker compose` to run this project locally.\n\n### OS Database dependencies\n\nIf you have an error while installing the python dependencies locally:\n\n```bash\n$ pip install -r requirements-dev.txt \nCollecting selenium==4.4.0\n  Using cached selenium-4.4.0-py3-none-any.whl (985 kB)\nCollecting SQLAlchemy==1.4.40\n  Using cached SQLAlchemy-1.4.40-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.6 MB)\nCollecting python-telegram-bot==13.13\n  Using cached python_telegram_bot-13.13-py3-none-any.whl (513 kB)\nCollecting mysqlclient==2.1.1\n  Using cached mysqlclient-2.1.1.tar.gz (88 kB)\n  Preparing metadata (setup.py) ... done\nCollecting beautifulsoup4==4.11.1\n  Using cached beautifulsoup4-4.11.1-py3-none-any.whl (128 kB)\nCollecting psycopg2==2.9.3\n  Using cached psycopg2-2.9.3.tar.gz (380 kB)\n  Preparing metadata (setup.py) ... error\n  error: subprocess-exited-with-error\n  \n  × python setup.py egg_info did not run successfully.\n  │ exit code: 1\n  ╰─\u003e [25 lines of output]\n      /home/angel/personal/ave-round-tripper/venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py:463: SetuptoolsDeprecationWarning: The license_file parameter is deprecated, use license_files instead.\n        warnings.warn(msg, warning_class)\n      running egg_info\n      creating /tmp/pip-pip-egg-info-24949_g2/psycopg2.egg-info\n      writing /tmp/pip-pip-egg-info-24949_g2/psycopg2.egg-info/PKG-INFO\n      writing dependency_links to /tmp/pip-pip-egg-info-24949_g2/psycopg2.egg-info/dependency_links.txt\n      writing top-level names to /tmp/pip-pip-egg-info-24949_g2/psycopg2.egg-info/top_level.txt\n      writing manifest file '/tmp/pip-pip-egg-info-24949_g2/psycopg2.egg-info/SOURCES.txt'\n      \n      Error: pg_config executable not found.\n      \n      pg_config is required to build psycopg2 from source.  Please add the directory\n      containing pg_config to the $PATH or specify the full executable path with the\n      option:\n      \n          python setup.py build_ext --pg-config /path/to/pg_config build ...\n      \n      or with the pg_config option in 'setup.cfg'.\n      \n      If you prefer to avoid building psycopg2 from source, please install the PyPI\n      'psycopg2-binary' package instead.\n      \n      For further information please check the 'doc/src/install.rst' file (also at\n      \u003chttps://www.psycopg.org/docs/install.html\u003e).\n      \n      [end of output]\n  \n  note: This error originates from a subprocess, and is likely not a problem with pip.\nerror: metadata-generation-failed\n\n× Encountered error while generating package metadata.\n╰─\u003e See above for output.\n\nnote: This is an issue with the package mentioned above, not pip.\nhint: See above for details.\n```\n\nTry installing the DB dependencies in your OS.\n\nPostgreSQL:\n\n```bash\n$ dnf install -y postgresql-devel\n# or\n$ apt-get install -y libpq-dev\n```\n\n## Run it locally\n\n### Configuration\n\n- `TRAVEL_LOG_LEVEL`: Log level for the program. Default: `info`.\n- `TRAVEL_DB_PATH`: In case you want to use `sqlite3`, specify the path to the db file. Exclusive with `TRAVEL_DB_ENGINE`.\n- `TRAVEL_DB_ENGINE`: Choose `mysql` or `postgresql`. Exclusive with `TRAVEL_DB_PATH`.\n- `TRAVEL_DB_HOST`: *(Required if TRAVEL_DB_ENGINE is `postgresql` or `mysql`)*. The hostname of the database.\n- `TRAVEL_DB_PORT`: *(Required if TRAVEL_DB_ENGINE is `postgresql` or `mysql`)*. The port of the database.\n- `TRAVEL_DB_USER`: *(Required if TRAVEL_DB_ENGINE is `postgresql` or `mysql`)*. The username of the database.\n- `TRAVEL_DB_PASSWORD`: *(Required if TRAVEL_DB_ENGINE is `postgresql` or `mysql`)*. The password of the database.\n- `TRAVEL_DB_NAME`: *(Required if TRAVEL_DB_ENGINE is `postgresql` or `mysql`)*. The name of the database.\n- `TRAVEL_NOTIFICATION_TOKEN`: The telegram bot token.\n- `TRAVEL_NOTIFICATION_CHAT_ID`: The telegram chat id.\n- `TRAVEL_DEBUG`: If set to `no` *(default)*, the program will run forever. Set to `yes` to just run one loop.\n- `TRAVEL_FROM`: The origin of the trip. Default: `Madrid`.\n- `TRAVEL_TO`: The destination of the trip. Default: `Zaragoza`.\n- `TRAVEL_DAYS`: Number of days to search for. Default: `30`.\n- `TRAVEL_RENFE_PRICE_CHANGE_NOTIFICATION`: Send a notification every time a price changes. Default: `False`.\n- `ROUND_TRIP_ENABLED`: Check for round trips. Default: `True`.\n- `ROUND_TRIP_NOTIFICATION_MAX_PRICE`: Max price to pay for a round trip. Default: `40`. This is the sum of both prices. \n- `ROUND_TRIP_ORIGIN_DEPARTURE_TIME`: Time of departure for the round trip. Default: `06:30`. Only accepts one.\n- `ROUND_TRIP_DESTINATION_DEPARTURE_TIME`: List of possible departure times for the round trip. Default: `15:45,17:45,18:26,20:45`.\n- `TRAVEL_START_DATE`: Date to start searching from. Default `''` *(empty value, means, **today**)*. Format: `DD/MM/YYYY`.\n- `TRAVEL_HISTORICAL_DATA_DAYS`: Save up to this number of days of historical data. Default: `30`. Useful for analyzing trends.\n\nYou will find a couple of `.env` files at the root of the project, so you can start using them right away.\n\n### Telegram bot and group\n\nCreate a telegram bot and a group. Then get and set the bot token and chat id.\nThere are many tutorials on how to do this.\n\n### Running the program\n\nBefore running the program, ensure you have the telegram bot and the group set up in the `.sqlite.env` file.\nThen:\n\n```bash\n$ source .sqlite.env\n$ python main.py\n{\"time\":\"2022-08-25 21:19:15,360\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:127\", \"level\":\"INFO\", \"msg\":\"db mode is: sqlite. Path: trains.sqlite.db\"}\n{\"time\":\"2022-08-25 21:19:16,219\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:54\", \"level\":\"INFO\", \"msg\":\"processing 25/08/2022\"}\n{\"time\":\"2022-08-25 21:19:16,219\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:54\", \"level\":\"INFO\", \"msg\":\"running RenfeScraper\"}\n{\"time\":\"2022-08-25 21:19:19,287\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:214\", \"level\":\"ERROR\", \"msg\":\"error while parsing renfe results\"}\n{\"time\":\"2022-08-25 21:19:19,322\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:54\", \"level\":\"INFO\", \"msg\":\"running RenfeScraper\"}\n{\"time\":\"2022-08-25 21:19:21,612\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:214\", \"level\":\"ERROR\", \"msg\":\"error while parsing renfe results\"}\n{\"time\":\"2022-08-25 21:19:21,633\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:26\", \"level\":\"INFO\", \"msg\":\"running round_trip oportunity finder for 25/08/2022\"}\n{\"time\":\"2022-08-25 21:19:21,633\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:31\", \"level\":\"INFO\", \"msg\":\"querying origin trains\"}\n{\"time\":\"2022-08-25 21:19:21,676\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:26\", \"level\":\"INFO\", \"msg\":\"running round_trip oportunity finder for 25/08/2022\"}\n{\"time\":\"2022-08-25 21:19:21,676\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:31\", \"level\":\"INFO\", \"msg\":\"querying origin trains\"}\n{\"time\":\"2022-08-25 21:19:21,718\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:26\", \"level\":\"INFO\", \"msg\":\"running round_trip oportunity finder for 25/08/2022\"}\n{\"time\":\"2022-08-25 21:19:21,718\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:31\", \"level\":\"INFO\", \"msg\":\"querying origin trains\"}\n{\"time\":\"2022-08-25 21:19:21,757\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:26\", \"level\":\"INFO\", \"msg\":\"running round_trip oportunity finder for 25/08/2022\"}\n{\"time\":\"2022-08-25 21:19:21,758\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:31\", \"level\":\"INFO\", \"msg\":\"querying origin trains\"}\n{\"time\":\"2022-08-25 21:19:21,802\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:90\", \"level\":\"INFO\", \"msg\":\"1/30 days processed\"}\n{\"time\":\"2022-08-25 21:19:21,802\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:95\", \"level\":\"INFO\", \"msg\":\"inner loop toke: 5 seconds\"}\n{\"time\":\"2022-08-25 21:19:21,802\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:54\", \"level\":\"INFO\", \"msg\":\"processing 26/08/2022\"}\n{\"time\":\"2022-08-25 21:19:21,802\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:54\", \"level\":\"INFO\", \"msg\":\"running RenfeScraper\"}\n{\"time\":\"2022-08-25 21:19:23,138\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:76\", \"level\":\"INFO\", \"msg\":\"filling up input fields\"}\n{\"time\":\"2022-08-25 21:19:24,359\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:147\", \"level\":\"INFO\", \"msg\":\"submitting the form\"}\n{\"time\":\"2022-08-25 21:19:25,497\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:152\", \"level\":\"INFO\", \"msg\":\"waiting for results\"}\n{\"time\":\"2022-08-25 21:19:29,052\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:193\", \"level\":\"INFO\", \"msg\":\"trayecto: {'salida': '06.30', 'duracion': '1 h. 21 min.', 'llegada': '07.51', 'tipo': 'AVE', 'prices': ['desde 29,10 €', 'desde 26,20 €', 'desde 34,85 €']}\"}\n{\"time\":\"2022-08-25 21:19:29,052\", \"module\":\"/home/angel/personal/ave-round-tripper/main.py:193\", \"level\":\"INFO\", \"msg\":\"trayecto: {'salida': '07.15', 'duracion': '4 h. 3 min.', 'llegada': '11.18', 'tipo': 'REG.EXP.', 'prices': ['desde 29,55 €']}\"}\n```\n\n## Warning\n\nRunning this script locally is not recommended.\nSeems like Renfe uses akamai in non-blocking mode, but it will report your public IP as a dangerous one, so you won't be able to\naccess other sites protected by akamai:\n\n- [adidas.com](https://www.adidas.com)\n- [elcorteingles.es](https://www.elcorteingles.es)\n\nare a few examples of sites protected by akamai.\n\n# License\n\n[MIT License](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fangelbarrera92%2Fave-round-tripper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fangelbarrera92%2Fave-round-tripper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fangelbarrera92%2Fave-round-tripper/lists"}