├── requirements.txt
├── styles.css
├── README.md
├── flask_app.py
├── tests.py
├── LICENSE
├── restaurants.txt
├── main.py
└── parser.py
/requirements.txt:
--------------------------------------------------------------------------------
1 | beautifulsoup4
2 | requests
3 | flask
4 | flask-caching
5 |
--------------------------------------------------------------------------------
/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | height:100%;
3 | font-size:14px;
4 | font-family:Arial, Helvetica, Sans-serif;
5 | letter-spacing:0.01em;
6 | }
7 |
8 | div.title {
9 | font-weight: bold;
10 | }
11 |
12 | div.endnote {
13 | font-size:10px;
14 | }
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | lunch-parser
2 | ============
3 |
4 | Scripts useful for parsing the menus of the restaurants near Campus Solna of Karolinska Institutet and BMC of Uppsala University and generating a simple html page.
5 |
6 | Usage:
7 | python3 main.py restaurant_name > index.html
8 |
9 | The supported restaurants are also listed when you run main.py without any arguments.
10 |
11 | If new restaurants are added, add the parser function to `parser.py`, the relevant keyword and function name to `MAPPER` in `main.py`, and URLs etc to `restaurants.txt`.
12 |
13 | An experimental version can be run via flask `FLASK_APP=flask_app.py flask run`, with the ki menus listed under /ki and uu under /uu.
--------------------------------------------------------------------------------
/flask_app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from flask_caching import Cache
3 |
4 | import main
5 |
6 | app = Flask(__name__)
7 | cache = Cache(app, config={'CACHE_TYPE': 'simple'})
8 |
9 | @app.route('/')
10 | def display_available():
11 | content = ('' +
12 | '
' +
13 | 'Restaurant Menu Parser' +
14 | '' +
15 | '' +
16 | 'KI (Solna)
' +
17 | 'UU (BMC)
' +
18 | '' +
19 | '')
20 | return content
21 |
22 | @app.route('/ki')
23 | @cache.cached(timeout=3600)
24 | def make_menu_ki():
25 | return main.gen_ki_menu()
26 |
27 | @app.route('/uu')
28 | @cache.cached(timeout=3600)
29 | def make_menu_uu():
30 | return main.gen_uu_menu()
31 |
--------------------------------------------------------------------------------
/tests.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import main as mn
4 | import parser as ps
5 |
6 | def test_read_restaurants() :
7 | import tempfile
8 | import os
9 |
10 | text = '''#identifier Name URL Menu URL Open Streetmap
11 | 61an Restaurang 61:an http://gastrogate.com/restaurang/61an/ http://gastrogate.com/restaurang/61an/page/3/ https://www.openstreetmap.org/#map=19/59.22071/17.93717
12 | alfred Alfreds restaurang http://www.alfredsrestaurang.se/ http://www.alfredsrestaurang.se/ https://www.openstreetmap.org/#map=19/59.21944/17.94074
13 | arom Café Arom http://aromsh.se/ http://aromsh.se/?page_id=13 http://www.openstreetmap.org/#map=18/59.21955/17.94160'''
14 |
15 | file_name = tempfile.mkstemp()[1]
16 | with open(file_name, 'w') as f:
17 | f.write(text)
18 |
19 | answer = [['61an', 'Restaurang 61:an', 'http://gastrogate.com/restaurang/61an/', 'http://gastrogate.com/restaurang/61an/page/3/' , 'https://www.openstreetmap.org/#map=19/59.22071/17.93717'],
20 | ['alfred', 'Alfreds restaurang', 'http://www.alfredsrestaurang.se/', 'http://www.alfredsrestaurang.se/', 'https://www.openstreetmap.org/#map=19/59.21944/17.94074'],
21 | ['arom', 'Café Arom', 'http://aromsh.se/', 'http://aromsh.se/?page_id=13', 'http://www.openstreetmap.org/#map=18/59.21955/17.94160']]
22 |
23 | assert mn.read_restaurants(file_name) == answer
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014-2018, Linus Östberg
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of kimenu nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 |
--------------------------------------------------------------------------------
/restaurants.txt:
--------------------------------------------------------------------------------
1 | # identifier Name URL Menu URL Open Streetmap
2 | # KI
3 | glada Den Glada Restaurangen http://www.dengladarestaurangen.se/ http://www.dengladarestaurangen.se/#!meny/c30g http://www.openstreetmap.org/#map=19/59.35123/18.03006
4 | haga Haga gatukök http://orenib.se/haga_gk2.pdf http://orenib.se/haga_gk2.pdf https://www.openstreetmap.org/#map=19/59.34931/18.02095
5 | hjulet Restaurang Hjulet http://gastrogate.com/restaurang/restauranghjulet/ http://gastrogate.com/restaurang/restauranghjulet/page/3/ https://www.openstreetmap.org/#map=19/59.34508/18.02423
6 | jons Jöns Jacob http://gastrogate.com/restaurang/jonsjacob/ https://jonsjacob.gastrogate.com/lunch/ https://www.openstreetmap.org/#map=19/59.34673/18.02465
7 | jorpes Café Erik Jorpes http://restaurang-ns.com/cafe-erik-jorpes/ http://restaurang-ns.com/cafe-erik-jorpes/ https://www.openstreetmap.org/#map=19/59.34851/18.02721
8 | karolina Restaurang Karolina http://gastrogate.com/restaurang/ksrestaurangen/ https://ksrestaurangen.gastrogate.com/lunch/ https://www.openstreetmap.org/#map=19/59.35224/18.03103
9 | livet Livet [Restaurant] https://www.livetbrand.com/livet-restaurant/ https://www.livetbrand.com/livet-restaurant/ https://www.openstreetmap.org/#map=19/59.34853/18.02989
10 | mollan Mollan Asian kök http://mollanasiankok.se/ http://mollanasiankok.se/vecka%20meny.html https://www.openstreetmap.org/#map=19/59.34836/18.02650
11 | svarta Svarta Räfven http://restaurang-ns.com/svarta-rafven/ http://restaurang-ns.com/svarta-rafven/ https://www.openstreetmap.org/#map=19/59.34851/18.02804
12 | subway Subway http://subway.se/sv/hem/ http://subway.se/sv/hem/ https://www.openstreetmap.org/#map=19/59.35084/18.02433
13 | nanna Restaurang Nanna Svartz http://restaurang-ns.com/restaurang-nanna-svartz/ http://restaurang-ns.com/restaurang-nanna-svartz/ https://www.openstreetmap.org/#map=19/59.34848/18.02807
14 | # UU
15 | bikupan Restaurang Bikupan http://www.hors.se/restaurang/restaurang-bikupan/ http://www.hors.se/restaurang/restaurang-bikupan/ https://www.openstreetmap.org/#map=18/59.84186/17.63407
16 | dufva Sven Dufva http://svendufva.se/ http://svendufva.se/#lunch https://www.openstreetmap.org/#map=19/59.84298/17.64096
17 | hubben Restaurang Hubben https://vasakronan.foodbycoor.se/hubben https://vasakronan.foodbycoor.se/hubben/restaurangen/restaurangens-meny https://www.openstreetmap.org/#map=18/59.84334/17.64074
18 | rudbeck Bistro Rudbeck http://www.compass-group.se/restauranger/Bistro-Rudbeck-Uppsala-/ https://eurest.mashie.com/public/menu/restaurang+kannan/cb061efe?country=se https://www.openstreetmap.org/#map=19/59.84518/17.63968
19 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Copyright (c) 2014-2018, Linus Östberg
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions are met:
8 | #
9 | # * Redistributions of source code must retain the above copyright notice, this
10 | # list of conditions and the following disclaimer.
11 | #
12 | # * Redistributions in binary form must reproduce the above copyright notice,
13 | # this list of conditions and the following disclaimer in the documentation
14 | # and/or other materials provided with the distribution.
15 | #
16 | # * Neither the name of kimenu nor the names of its
17 | # contributors may be used to endorse or promote products derived from
18 | # this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | '''
31 | Main script for choosing what restaurant parsers to use
32 | '''
33 |
34 | import os
35 | import sys
36 |
37 | import parser as ps
38 |
39 | __location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
40 | REST_FILENAME = os.path.join(__location__, 'restaurants.txt')
41 |
42 |
43 | # works as ordered dict as well, but must be _ordered_
44 | MAPPER = (('jorpes', ps.parse_jorpes), ('glada', ps.parse_glada),
45 | ('haga', ps.parse_haga), ('hjulet', ps.parse_hjulet),
46 | ('jons', ps.parse_jons), ('karolina', ps.parse_karolina),
47 | ('livet', ps.parse_livet), ('mollan', ps.parse_mollan),
48 | ('nanna', ps.parse_nanna), ('svarta', ps.parse_svarta),
49 | ('subway', ps.parse_subway), ('bikupan', ps.parse_bikupan),
50 | ('dufva', ps.parse_dufva), ('hubben', ps.parse_hubben),
51 | ('rudbeck', ps.parse_rudbeck))
52 |
53 |
54 | def activate_parsers(restaurants, restaurant_data):
55 | '''
56 | Run the wanted parsers
57 | '''
58 | output = []
59 | for i in range(len(MAPPER)):
60 | if MAPPER[i][0] in restaurants:
61 | try:
62 | to_use = restaurant_data[[x[0] for x in restaurant_data].index(
63 | [x[0] for x in MAPPER][i])]
64 | output.append('\n'.join(MAPPER[i][1](to_use)))
65 | except Exception as err:
66 | sys.stderr.write('E in {}: {}\n'.format(MAPPER[i][0], err))
67 | return '\n'.join(output)
68 |
69 |
70 | def gen_ki_menu():
71 | '''
72 | Generate a menu for restaurants at KI
73 | '''
74 | restaurant_data = read_restaurants(open(REST_FILENAME).read())
75 | rest_names = [x[0] for x in MAPPER[:11]]
76 |
77 | output = ''
78 | output += '\n'.join(page_start(ps.get_weekday(), str(ps.get_day()), ps.get_month()))
79 | output += activate_parsers(rest_names, restaurant_data)
80 | output += '\n'.join(page_end())
81 | return output
82 |
83 |
84 | def gen_uu_menu():
85 | '''
86 | Generate a menu for restaurants at UU
87 | '''
88 | restaurant_data = read_restaurants(open(REST_FILENAME).read())
89 | rest_names = [x[0] for x in MAPPER[11:]]
90 |
91 | output = ''
92 | output += '\n'.join(page_start(ps.get_weekday(), str(ps.get_day()), ps.get_month()))
93 | output += activate_parsers(rest_names, restaurant_data)
94 | output += '\n'.join(page_end())
95 |
96 | sys.stderr.write(output)
97 | return output
98 |
99 |
100 | def page_end():
101 | '''
102 | Print the closure of tags etc
103 | '''
104 | lines = list()
105 | lines.append('')
108 | lines.append('