diff options
-rw-r--r-- | README.md | 37 | ||||
-rw-r--r-- | assets/ss1.png | bin | 0 -> 268128 bytes | |||
-rw-r--r-- | assets/ss2.png | bin | 0 -> 2365698 bytes | |||
-rw-r--r-- | assets/ss3.png | bin | 0 -> 980807 bytes | |||
-rw-r--r-- | html/template.html | 296 | ||||
-rw-r--r-- | requirements.txt | 2 | ||||
-rw-r--r-- | simple.html | 55 | ||||
-rw-r--r-- | stylized.html | 296 | ||||
-rw-r--r-- | web2recipe.py | 92 |
9 files changed, 778 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..45a6ced --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# Web2Recipe + +This is a simple Python script to scrap recipes from websites and then generate stylized/non-stylized (no-extra-crap) single page HTML pages + +``` +usage: web2recipe.py [-h] [-S] [-V] [-U URL] + +This program takes the URL of a website with the target recipe, scraps it and +stylises it. If the stylized argument is not passed, then it generates a +vanilla HTML file + +optional arguments: + -h, --help show this help message and exit + -S, --stylized generate stylized html + -V, --version show program version + -U URL, --url URL input url +``` + +### Screenshots + +#### Simple + +![non-stylized](./assets/ss1.png, "Non-Stylised") + +![stylized](./assets/ss2.png, "Stylised") + +![stylized-mobile](./assets/ss3.png, "Stylised (Mobile)") + +### Requirements + +* BeutifulSoup4 +* Markdown2 + +### Acknowledgemnts + +* Zack Schollz Github: schollz - Ingredients API +* CodePen: oliviale - Recipe Layout CSS
\ No newline at end of file diff --git a/assets/ss1.png b/assets/ss1.png Binary files differnew file mode 100644 index 0000000..8c7295e --- /dev/null +++ b/assets/ss1.png diff --git a/assets/ss2.png b/assets/ss2.png Binary files differnew file mode 100644 index 0000000..2b011d0 --- /dev/null +++ b/assets/ss2.png diff --git a/assets/ss3.png b/assets/ss3.png Binary files differnew file mode 100644 index 0000000..60690fa --- /dev/null +++ b/assets/ss3.png diff --git a/html/template.html b/html/template.html new file mode 100644 index 0000000..0ea8a81 --- /dev/null +++ b/html/template.html @@ -0,0 +1,296 @@ +<!DOCTYPE html> +<html lang="en" > +<head> + <meta charset="UTF-8"> + <title>Recipe (Web2Recipe)</title> + <link href="https://fonts.googleapis.com/css?family=Raleway:400,400i,700,900|Playfair+Display:700i,700" rel="stylesheet"> +<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css"> +<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/simple-line-icons/2.4.1/css/simple-line-icons.min.css'> +<style> +body { + background: #bfb1ac; + font-family: "Raleway", sans-serif; +} + +aside.context { + text-align: left; + text-transform: none; + padding-right: 20px; + color: #333; +} +aside.context a { + text-decoration: none; + color: #333; + padding: 3px 0; + border-bottom: 1px dashed; +} +aside.context a:hover { + border-bottom: 1px solid; +} + +footer { + text-align: center; + width: 100%; +} +footer a { + text-decoration: none; + display: inline-block; + width: 30px; + height: 30px; + border-radius: 50%; + background: transparent; + border: 1px dashed #333; + color: #333; + margin: 0 3px; +} +footer a:hover { + background: rgba(0, 0, 0, 0.05); +} +footer a .icons { + margin-top: 8px; + display: inline-block; + font-size: 14px; +} + +.main-content { + display: grid; + grid-template-areas: "navigation recipe-recipe recipe-image" "context context recipe-image"; + grid-template-columns: min-content auto 35%; + grid-template-rows: auto min-content; + margin: auto; + min-height: 100vh; + max-height: calc(100vh - 4em); + background: #fff; + box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07); +} + +.context__wrapper { + grid-area: context; + background: #f7f7f7; + color: #333; + padding: 15px 20px; + font: 400 12px/1.2 "Raleway", sans-serif; + display: grid; + align-items: center; + grid-template-columns: auto max-content; +} + +.navigation { + grid-area: navigation; + border-right: 1px solid #eee; + writing-mode: vertical-rl; + text-orientation: mixed; + color: #dbc7b1; + text-transform: uppercase; + letter-spacing: 1px; + padding: 20px; + font: 16px "Playfair Display", serif; + text-align: center; +} + +.recipe-image { + grid-area: recipe-image; + background: url("REPLACE-IMG") no-repeat left center/cover; +} + +.recipe-name { + font: 900 45px Raleway; + text-transform: uppercase; + margin: 20px 0 5px; + letter-spacing: 2px; + color: #916953; + position: relative; +} + +.recipe-serving { + font: 400 16px Raleway; + color: #916953; + margin: 20px 0; + max-width: 300px; +} +.recipe-serving svg { + width: 40px; +} +.recipe-serving svg path { + fill: #916953; +} +.recipe-serving p { + display: inline-block; + vertical-align: top; + margin: 12px 6px 6px; +} + +::-webkit-scrollbar { + width: 10px; +} + +::-webkit-scrollbar-track { + background: #f1f1f1; +} + +::-webkit-scrollbar-thumb { + background: #dbc7b1; +} + +::-webkit-scrollbar-thumb:hover { + background: #d69762; +} + +.recipe-recipe { + grid-area: recipe-recipe; + color: #999; + overflow-y: auto; + overflow-x: hidden; + margin: 5px; + max-height: 100%; + padding: 50px 60px; + display: grid; + grid-gap: 20px; + grid-template-columns: 30px auto; + grid-template-rows: repeat(4, max-content); + line-height: 1.6; +} +.recipe-recipe__title { + grid-column: span 2; +} +.recipe-recipe__ingredients { + grid-column: span 2; + display: flex; + flex-wrap: wrap; +} +.recipe-recipe__ingredients__item { + flex: 1; + padding: 0 40px 0 0; +} +.recipe-recipe__ingredients__item h4 { + font: italic 20px/1.1 "Playfair Display", serif; + color: #d69762; + margin: 0 0 10px; + margin-top: 30px; +} +.recipe-recipe__ingredients__item ul { + margin: 0; + padding: 0; + list-style: none; +} +.recipe-recipe__ingredients__item ul li { + padding: 5px 0; +} +.recipe-recipe__number { + font: italic 30px/1 "Playfair Display", serif; + color: #d69762; + place-self: center; + margin-top: -15px; +} +.recipe-recipe__steps { + padding-right: 35px; +} +.recipe-recipe__subtitle { + font: italic 30px/1 "Playfair Display", serif; + color: #916953; + margin: 45px 0 10px; + grid-column: span 2; +} +.recipe-recipe__tips { + grid-column: span 2; + margin-top: 65px; + position: relative; + border: 2px solid #916953; + box-shadow: inset 0 0 0 2px #fff, inset 0 0 0 4px #916953; + text-align: center; + padding: 35px; +} +.recipe-recipe__tips svg { + display: inline-block; + padding: 10px; + position: absolute; + margin: auto; + left: 0; + right: 0; + top: -40px; + width: auto; + background: #fff; + width: 60px; + fill: #916953; +} +.recipe-recipe__tips h4 { + font: 900 24px Raleway; + text-transform: uppercase; + margin: 10px 0 15px; + color: #543b2e; +} +@media screen and (max-width: 768px) { + .main-content { + margin: 0; + max-height: none; + grid-template-areas: + "recipe-image" + "recipe-recipe" + "context"; + grid-template-columns: auto; + grid-template-rows: 300px auto max-content; + } + .navigation { + display: none; + } + .recipe-image { + height: 300px; + width: 100%; + } + +} +/* +@media screen and (max-width: 768px) { + .main-content { + margin: 0; + max-height: none; + grid-template-areas: + "recipe-image" + "recipe-recipe" + "context"; + grid-template-columns: auto; + grid-template-rows: 300px auto max-content; + } + .navigation { + display: none; + } + .recipe-image { + height: 300px; + width: 100%; + } + .recipe-recipe { + padding: 25px; + &__title { + margin: 0; + text-align: center; + } + .recipe-serving { + margin: 20px auto; + } + } +} +*/ +</style> +</head> +<body> +<!-- partial:index.partial.html --> +<div class="main-content"> + <div class="navigation">Generated by Web2Recipe</div> + <div class="recipe-image"></div> + <div class="recipe-recipe"> + <div class="recipe-recipe__title"> + <div class="recipe-name">REPLACE-RECIPE-TITLE</div> + <div class="recipe-recipe__ingredients"> + <div class="recipe-recipe__ingredients__item"> + <h4>Ingredients</h4> + REPLACE-INGREDIENTS + </div> + </div> + <div class="recipe-recipe__subtitle">Instructions</div> + REPLACE-INSTRUCTIONS + </div> +</div> +<!-- partial --> + <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script> +</body> +</html>
\ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..bb7a149 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +bs4 +markdown2
\ No newline at end of file diff --git a/simple.html b/simple.html new file mode 100644 index 0000000..046e0b9 --- /dev/null +++ b/simple.html @@ -0,0 +1,55 @@ +<h1>Masala Dosa</h1> +<h2>Ingredients</h2> +<ul> +<li>20 whole seeds </li> +</ul> +<ul> +<li>1 cup water </li> +</ul> +<ul> +<li>2 cups water </li> +</ul> +<ul> +<li>1 cup water </li> +</ul> +<ul> +<li>0.5 cup water </li> +</ul> +<ul> +<li>0.5 teaspoon salt (rock) </li> +</ul> +<ul> +<li>2 tablespoons oil </li> +</ul> +<ul> +<li>0.5 teaspoon mustard seeds </li> +</ul> +<ul> +<li>1 whole inch ginger </li> +</ul> +<ul> +<li>18 whole curry </li> +</ul> +<ul> +<li>3 whole green </li> +</ul> +<ul> +<li>0.25 teaspoon turmeric </li> +</ul> +<ul> +<li>1 whole asafoetida </li> +</ul> +<ul> +<li>0.5 cup water </li> +</ul> +<ul> +<li>3 tablespoons coriander (chopped) </li> +</ul> +<ul> +<li>18 whole cashews </li> +</ul> +<ul> +<li>0.25 teaspoon sugar </li> +</ul> +<h2>Instructions</h2> +<ol><li> soak 3 to 4 dry kashmiri red chilies (kashmiri lal mirch) in warm water for 30 to 40 minutes - add the number of chilies as per your taste preferences and depending on the type of chilies - whether they are less hot or too pungent.</li><li> for a spicy taste in the chutney add 4 to 5 dry kashmiri red chilies. later drain all the water. break the chilies and add in a small grinder jar.</li><li> also add 2 tablespoons roasted chana dal (roasted bengal gram or bhuna chana dal), 4 to 5 garlic cloves, 1 teaspoon seedlees tamarind and ¼ cup chopped onions. also add salt as required.</li><li> if you do not like the raw taste of onions or garlic, then just sauté both in some oil for a few minutes and then add before grinding.</li><li> now add water as required and grind all the ingredients till smooth. grind the chutney to a slightly thick or medium consistency and not to a thin consistency.</li><li> remove the red dosa chutney in a bowl.</li><li> spread this red chutney after dosa becomes golden and crisp. then spread the potato masala. fold and serve mysore masala dosa.</li><li> this red chutney stays well in the refrigerator for 1 to 2 days. this red chutney recipe yields a small bowl of chutney which can be spread on 8 to 9 dosas.</li></ol>
\ No newline at end of file diff --git a/stylized.html b/stylized.html new file mode 100644 index 0000000..f816bed --- /dev/null +++ b/stylized.html @@ -0,0 +1,296 @@ +<!DOCTYPE html> +<html lang="en" > +<head> + <meta charset="UTF-8"> + <title>Recipe (Web2Recipe)</title> + <link href="https://fonts.googleapis.com/css?family=Raleway:400,400i,700,900|Playfair+Display:700i,700" rel="stylesheet"> +<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css"> +<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/simple-line-icons/2.4.1/css/simple-line-icons.min.css'> +<style> +body { + background: #bfb1ac; + font-family: "Raleway", sans-serif; +} + +aside.context { + text-align: left; + text-transform: none; + padding-right: 20px; + color: #333; +} +aside.context a { + text-decoration: none; + color: #333; + padding: 3px 0; + border-bottom: 1px dashed; +} +aside.context a:hover { + border-bottom: 1px solid; +} + +footer { + text-align: center; + width: 100%; +} +footer a { + text-decoration: none; + display: inline-block; + width: 30px; + height: 30px; + border-radius: 50%; + background: transparent; + border: 1px dashed #333; + color: #333; + margin: 0 3px; +} +footer a:hover { + background: rgba(0, 0, 0, 0.05); +} +footer a .icons { + margin-top: 8px; + display: inline-block; + font-size: 14px; +} + +.main-content { + display: grid; + grid-template-areas: "navigation recipe-recipe recipe-image" "context context recipe-image"; + grid-template-columns: min-content auto 35%; + grid-template-rows: auto min-content; + margin: auto; + min-height: 100vh; + max-height: calc(100vh - 4em); + background: #fff; + box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07); +} + +.context__wrapper { + grid-area: context; + background: #f7f7f7; + color: #333; + padding: 15px 20px; + font: 400 12px/1.2 "Raleway", sans-serif; + display: grid; + align-items: center; + grid-template-columns: auto max-content; +} + +.navigation { + grid-area: navigation; + border-right: 1px solid #eee; + writing-mode: vertical-rl; + text-orientation: mixed; + color: #dbc7b1; + text-transform: uppercase; + letter-spacing: 1px; + padding: 20px; + font: 16px "Playfair Display", serif; + text-align: center; +} + +.recipe-image { + grid-area: recipe-image; + background: url("https://i2.wp.com/www.vegrecipesofindia.com/wp-content/uploads/2010/01/masala-dosa-recipe-restaurant-style.jpg") no-repeat left center/cover; +} + +.recipe-name { + font: 900 45px Raleway; + text-transform: uppercase; + margin: 20px 0 5px; + letter-spacing: 2px; + color: #916953; + position: relative; +} + +.recipe-serving { + font: 400 16px Raleway; + color: #916953; + margin: 20px 0; + max-width: 300px; +} +.recipe-serving svg { + width: 40px; +} +.recipe-serving svg path { + fill: #916953; +} +.recipe-serving p { + display: inline-block; + vertical-align: top; + margin: 12px 6px 6px; +} + +::-webkit-scrollbar { + width: 10px; +} + +::-webkit-scrollbar-track { + background: #f1f1f1; +} + +::-webkit-scrollbar-thumb { + background: #dbc7b1; +} + +::-webkit-scrollbar-thumb:hover { + background: #d69762; +} + +.recipe-recipe { + grid-area: recipe-recipe; + color: #999; + overflow-y: auto; + overflow-x: hidden; + margin: 5px; + max-height: 100%; + padding: 50px 60px; + display: grid; + grid-gap: 20px; + grid-template-columns: 30px auto; + grid-template-rows: repeat(4, max-content); + line-height: 1.6; +} +.recipe-recipe__title { + grid-column: span 2; +} +.recipe-recipe__ingredients { + grid-column: span 2; + display: flex; + flex-wrap: wrap; +} +.recipe-recipe__ingredients__item { + flex: 1; + padding: 0 40px 0 0; +} +.recipe-recipe__ingredients__item h4 { + font: italic 20px/1.1 "Playfair Display", serif; + color: #d69762; + margin: 0 0 10px; + margin-top: 30px; +} +.recipe-recipe__ingredients__item ul { + margin: 0; + padding: 0; + list-style: none; +} +.recipe-recipe__ingredients__item ul li { + padding: 5px 0; +} +.recipe-recipe__number { + font: italic 30px/1 "Playfair Display", serif; + color: #d69762; + place-self: center; + margin-top: -15px; +} +.recipe-recipe__steps { + padding-right: 35px; +} +.recipe-recipe__subtitle { + font: italic 30px/1 "Playfair Display", serif; + color: #916953; + margin: 45px 0 10px; + grid-column: span 2; +} +.recipe-recipe__tips { + grid-column: span 2; + margin-top: 65px; + position: relative; + border: 2px solid #916953; + box-shadow: inset 0 0 0 2px #fff, inset 0 0 0 4px #916953; + text-align: center; + padding: 35px; +} +.recipe-recipe__tips svg { + display: inline-block; + padding: 10px; + position: absolute; + margin: auto; + left: 0; + right: 0; + top: -40px; + width: auto; + background: #fff; + width: 60px; + fill: #916953; +} +.recipe-recipe__tips h4 { + font: 900 24px Raleway; + text-transform: uppercase; + margin: 10px 0 15px; + color: #543b2e; +} +@media screen and (max-width: 768px) { + .main-content { + margin: 0; + max-height: none; + grid-template-areas: + "recipe-image" + "recipe-recipe" + "context"; + grid-template-columns: auto; + grid-template-rows: 300px auto max-content; + } + .navigation { + display: none; + } + .recipe-image { + height: 300px; + width: 100%; + } + +} +/* +@media screen and (max-width: 768px) { + .main-content { + margin: 0; + max-height: none; + grid-template-areas: + "recipe-image" + "recipe-recipe" + "context"; + grid-template-columns: auto; + grid-template-rows: 300px auto max-content; + } + .navigation { + display: none; + } + .recipe-image { + height: 300px; + width: 100%; + } + .recipe-recipe { + padding: 25px; + &__title { + margin: 0; + text-align: center; + } + .recipe-serving { + margin: 20px auto; + } + } +} +*/ +</style> +</head> +<body> +<!-- partial:index.partial.html --> +<div class="main-content"> + <div class="navigation">Generated by Web2Recipe</div> + <div class="recipe-image"></div> + <div class="recipe-recipe"> + <div class="recipe-recipe__title"> + <div class="recipe-name">Masala Dosa</div> + <div class="recipe-recipe__ingredients"> + <div class="recipe-recipe__ingredients__item"> + <h4>Ingredients</h4> + <ul><li>20 whole seeds <li>1 cup water <li>2 cups water <li>1 cup water <li>0.5 cup water <li>0.5 teaspoon salt (rock) <li>2 tablespoons oil <li>0.5 teaspoon mustard seeds <li>1 whole inch ginger <li>18 whole curry <li>3 whole green <li>0.25 teaspoon turmeric <li>1 whole asafoetida <li>0.5 cup water <li>3 tablespoons coriander (chopped) <li>18 whole cashews <li>0.25 teaspoon sugar </li> + </div> + </div> + <div class="recipe-recipe__subtitle">Instructions</div> + <div class="recipe-recipe__steps"> soak 3 to 4 dry kashmiri red chilies (kashmiri lal mirch) in warm water for 30 to 40 minutes - add the number of chilies as per your taste preferences and depending on the type of chilies - whether they are less hot or too pungent.</div> <br><div class="recipe-recipe__steps"> for a spicy taste in the chutney add 4 to 5 dry kashmiri red chilies. later drain all the water. break the chilies and add in a small grinder jar.</div> <br><div class="recipe-recipe__steps"> also add 2 tablespoons roasted chana dal (roasted bengal gram or bhuna chana dal), 4 to 5 garlic cloves, 1 teaspoon seedlees tamarind and ¼ cup chopped onions. also add salt as required.</div> <br><div class="recipe-recipe__steps"> if you do not like the raw taste of onions or garlic, then just sauté both in some oil for a few minutes and then add before grinding.</div> <br><div class="recipe-recipe__steps"> now add water as required and grind all the ingredients till smooth. grind the chutney to a slightly thick or medium consistency and not to a thin consistency.</div> <br><div class="recipe-recipe__steps"> remove the red dosa chutney in a bowl.</div> <br><div class="recipe-recipe__steps"> spread this red chutney after dosa becomes golden and crisp. then spread the potato masala. fold and serve mysore masala dosa.</div> <br><div class="recipe-recipe__steps"> this red chutney stays well in the refrigerator for 1 to 2 days. this red chutney recipe yields a small bowl of chutney which can be spread on 8 to 9 dosas.</div> <br> + </div> +</div> +<!-- partial --> + <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script> +</body> +</html>
\ No newline at end of file diff --git a/web2recipe.py b/web2recipe.py new file mode 100644 index 0000000..26dbcd3 --- /dev/null +++ b/web2recipe.py @@ -0,0 +1,92 @@ +import argparse + +import requests +from bs4 import BeautifulSoup as Soup +from markdown2 import Markdown + +version = 1.0 +style = False + +text = 'This program takes the URL of a website with the target recipe, scraps it and stylises it. If the stylized argument is not passed, then it generates a vanilla HTML file' + +parser = argparse.ArgumentParser(description = text) +parser.add_argument("-S", "--stylized", help="generate stylized html", action="store_true") +parser.add_argument("-V", "--version", help="show program version", action="store_true") +parser.add_argument("-U", "--url", help="input url") + +args = parser.parse_args() + +if args.version: + print("Web2Recipe Version", version) + exit +if args.stylized: + style = True +if args.url: + url = args.url +else: + url = input("Enter Recipe Website URL: ") + + +markdowner = Markdown() + +params = (('url', url),) +response = requests.get('https://ingredients.schollz.now.sh/', params=params) + +json = response.json() +title = json["title"] +ingredients = [] + +def comment(x): + try: + c = "(" + str(x["comment"]) + ")" + return c + except: + return "" + +for x in json["ingredients"]: + i = x["measure"]["amount"], x["measure"]["name"], x["name"], comment(x) + ingredients.append(i) + +def genSimpleHTML(): + html = markdowner.convert("#" + title) + markdowner.convert("## Ingredients") + for x in ingredients: + s = "* " + for i in x: + s = s + str(i) + " " + html = html + markdowner.convert(s) + html = html + markdowner.convert('## Instructions') + html = html + "<ol>" + for x in json["instructions"]: + html = html + "<li> " + x + "</li>" + html = html + "</ol>" + f = open("./simple.html", "w") + f.write(html) + f.close() + print("Succesfuly generated file for the recipe: ", title) + +def stylized(): + ing = "<ul>" + for x in ingredients: + s = "<li>" + for i in x: + s = s + str(i) + " " + ing = ing + s + ing = ing + "</li>" + ins = "" + for x in json["instructions"]: + ins = ins + "<div class=\"recipe-recipe__steps\"> " + x + "</div> <br>" + f = open("html/template.html", "r") + template = str(f.read()) + template = template.replace("REPLACE-RECIPE-TITLE",title) + template = template.replace("REPLACE-INGREDIENTS",ing) + template = template.replace("REPLACE-INSTRUCTIONS",ins) + template = template.replace("REPLACE-IMG", json["image"]) + f = open("./stylized.html", "w") + f.write(template) + f.close() + print("Succesfuly generated stylized file for the recipe: ", title) + +if style: + stylized() +else: + genSimpleHTML() |