|
@@ -1,5 +1,6 @@
|
|
|
import { Recipe, RecipeDetails, Ingredient, ComposedIngredients, Author } from '../../model';
|
|
import { Recipe, RecipeDetails, Ingredient, ComposedIngredients, Author } from '../../model';
|
|
|
import { parse as parseIngredient } from "recipe-ingredient-parser";
|
|
import { parse as parseIngredient } from "recipe-ingredient-parser";
|
|
|
|
|
+import { getText, getTextList, getAttr } from "./../service";
|
|
|
|
|
|
|
|
const LITK_AUTHOR_DATA: Author = {
|
|
const LITK_AUTHOR_DATA: Author = {
|
|
|
name: 'Laura Vitale',
|
|
name: 'Laura Vitale',
|
|
@@ -8,66 +9,20 @@ const LITK_AUTHOR_DATA: Author = {
|
|
|
|
|
|
|
|
const SELECTORS = {
|
|
const SELECTORS = {
|
|
|
TITLE: '.cs-page-title > h1',
|
|
TITLE: '.cs-page-title > h1',
|
|
|
- DETAILS: '.cs-recipe-details > div',
|
|
|
|
|
|
|
+ DETAILS: 'script[type="application/ld+json"]',
|
|
|
INGREDIENTS: '.cs-ingredients-check-list > ul',
|
|
INGREDIENTS: '.cs-ingredients-check-list > ul',
|
|
|
INSTRUCTIONS: '#recipe-process > ul',
|
|
INSTRUCTIONS: '#recipe-process > ul',
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function getRecipeName($: CheerioSelector): string {
|
|
|
|
|
- return $(SELECTORS.TITLE).text().trim();
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
function getRecipeDetails($: CheerioSelector): RecipeDetails {
|
|
function getRecipeDetails($: CheerioSelector): RecipeDetails {
|
|
|
- const matchInt = (data: string, reg: RegExp, logic?: (s: RegExpMatchArray) => number): number => {
|
|
|
|
|
- let result = data.match(reg);
|
|
|
|
|
- return logic ?
|
|
|
|
|
- (result ? logic(result) : 0) :
|
|
|
|
|
- (result ? parseInt(result[0]) : 0)
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const parseTime = (data: string) => {
|
|
|
|
|
- let parsedHoursAsMin = matchInt(data, /(\d+) hours?/, result => parseInt(result[0])*60);
|
|
|
|
|
- let parsedMinutes = matchInt(data, /(\d+) minutes?/);
|
|
|
|
|
- return parsedHoursAsMin + parsedMinutes;
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ const x = $(SELECTORS.DETAILS);
|
|
|
|
|
+ let parsedScript = JSON.parse(($(x).html()||'').replace(/(\n|\t|\s{2,})/g, ' ').trim())
|
|
|
|
|
|
|
|
- const LAURA_MAP: {
|
|
|
|
|
- [index:string] : {
|
|
|
|
|
- key: string,
|
|
|
|
|
- transform: (data: string) => number,
|
|
|
|
|
- }
|
|
|
|
|
- } = {
|
|
|
|
|
- preparationTime: {
|
|
|
|
|
- key: 'Preparation',
|
|
|
|
|
- transform: parseTime,
|
|
|
|
|
- },
|
|
|
|
|
- cookingTime: {
|
|
|
|
|
- key: 'Cook time',
|
|
|
|
|
- transform: parseTime,
|
|
|
|
|
- },
|
|
|
|
|
- servings: {
|
|
|
|
|
- key: 'Servings',
|
|
|
|
|
- transform: (data: string) => matchInt(data, /\d+/),
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- let details = new RecipeDetails();
|
|
|
|
|
- const detailsKey = Object.keys(details);
|
|
|
|
|
- const data = $(SELECTORS.DETAILS);
|
|
|
|
|
- let _rawData: any = {};
|
|
|
|
|
-
|
|
|
|
|
- data.each((i, el) => {
|
|
|
|
|
- let key: string = $(el).find('span').text();
|
|
|
|
|
- _rawData[key] = $(el).contents().last().text();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- return detailsKey.reduce((recipeDetails, key) => {
|
|
|
|
|
- let _key = LAURA_MAP[key];
|
|
|
|
|
- return {
|
|
|
|
|
- ...recipeDetails,
|
|
|
|
|
- [key]: _key.transform(_rawData[_key.key])
|
|
|
|
|
- }
|
|
|
|
|
- }, details);
|
|
|
|
|
|
|
+ return new RecipeDetails(
|
|
|
|
|
+ parsedScript.prepTime,
|
|
|
|
|
+ parsedScript.cookTime,
|
|
|
|
|
+ parsedScript.recipeYield.match(/\d/)[0],
|
|
|
|
|
+ );
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function getIngredients($: CheerioSelector): ComposedIngredients[] {
|
|
function getIngredients($: CheerioSelector): ComposedIngredients[] {
|
|
@@ -98,7 +53,7 @@ function getIngredients($: CheerioSelector): ComposedIngredients[] {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function getInstructions($: CheerioSelector): string[] {
|
|
function getInstructions($: CheerioSelector): string[] {
|
|
|
- const data = $(SELECTORS.INSTRUCTIONS).text();
|
|
|
|
|
|
|
+ const data = getText($)(SELECTORS.INSTRUCTIONS);
|
|
|
return data.split('\n').filter(s => s !== '').map(s => s.trim().replace(/^\d\)\s*/, ''));
|
|
return data.split('\n').filter(s => s !== '').map(s => s.trim().replace(/^\d\)\s*/, ''));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -107,7 +62,7 @@ const LITK_CONFIG = {
|
|
|
domain: 'laurainthekitchen',
|
|
domain: 'laurainthekitchen',
|
|
|
website: LITK_AUTHOR_DATA.website,
|
|
website: LITK_AUTHOR_DATA.website,
|
|
|
scrapeRecipe: ($: CheerioSelector): Recipe => ({
|
|
scrapeRecipe: ($: CheerioSelector): Recipe => ({
|
|
|
- name: getRecipeName($),
|
|
|
|
|
|
|
+ name: getText($)(SELECTORS.TITLE),
|
|
|
author: LITK_AUTHOR_DATA,
|
|
author: LITK_AUTHOR_DATA,
|
|
|
details: getRecipeDetails($),
|
|
details: getRecipeDetails($),
|
|
|
ingredients: getIngredients($),
|
|
ingredients: getIngredients($),
|