Explorar el Código

Start working on JoB scraping service. TG-3

Tati hace 7 años
padre
commit
ec5aa79252

+ 12 - 0
ktchn/src/recipes/scrape/index.ts

@@ -2,6 +2,8 @@ import RequestPromise from "request-promise";
 import Cheerio from "cheerio";
 import Sources from './sources';
 import { ScrapingSource } from './sources/index';
+import { Ingredient } from '../index';
+import { parse as parseIngredient } from 'recipe-ingredient-parser';
 
 function selectSource(url: string): ScrapingSource|void {
   return Sources.find((source) => {
@@ -9,6 +11,16 @@ function selectSource(url: string): ScrapingSource|void {
   });
 }
 
+export const parseIngredients = (rawIngredient: string): Ingredient => {
+  let parsed = parseIngredient(rawIngredient);
+  return {
+    name: parsed.ingredient,
+    quantity: Number(parsed.quantity) || 0,
+    unit: parsed.unit || '',
+    _original: rawIngredient,
+  };
+};
+
 function scrape(url:string) {
   const options = {
     uri: url,

+ 2 - 0
ktchn/src/recipes/scrape/sources/index.ts

@@ -1,4 +1,5 @@
 import LITK from "./laura-in-the-kitchen";
+import JOB from './joy-of-baking';
 import { Recipe } from '../../index';
 
 export interface ScrapingSource {
@@ -10,6 +11,7 @@ export interface ScrapingSource {
 
 const Sources: ScrapingSource[] = [
   LITK,
+  JOB,
 ];
 
 export default Sources;

+ 55 - 0
ktchn/src/recipes/scrape/sources/joy-of-baking.ts

@@ -0,0 +1,55 @@
+import { Recipe, Author, RecipeDetails, ComposedIngredients } from '../../index';
+import { parseIngredients } from '../index';
+
+const JOB_AUTHOR_DATA: Author = {
+  name: 'Stephanie Jaworski',
+  website: 'https://joyofbaking.com',
+};
+
+const SELECTORS = {
+  TITLE: 'h1 > span.Heading',
+}
+
+function getRecipeName($: CheerioSelector): string {
+  return $(SELECTORS.TITLE).text().replace(/(.\n)?.Recipe.*/, '').trim();
+}
+
+function getIngredients($: CheerioSelector): ComposedIngredients[] {
+  const rawData = $('td [width="249"] p').toArray();
+  const isIngredient = (element: CheerioElement): boolean => $(element).hasClass('ingredient');
+  const removeEquivalence = (str: string): string => str.replace(/\([0-9.]+ \w+\) ?/, '');
+
+  let ingredients: ComposedIngredients[] = [];
+  return rawData.reduce((list:any, element, index) => {
+    let rawIngredient = $(element).text();
+    rawIngredient = rawIngredient.replace(/(\n|\t|\s{2,})/g, ' ').trim();
+    let last = list.length - 1;
+    if(isIngredient(element)) {
+      let ingredient = parseIngredients(rawIngredient);
+      list[last].ingredients = list[last].ingredients.concat([{
+        ...ingredient,
+        name: removeEquivalence(ingredient.name)
+      }]);
+      return list;
+    } else {
+      return rawIngredient === '' ? list : list.concat([{name: rawIngredient, ingredients: []}]);
+    }
+  }, ingredients);
+}
+
+
+const JOB_CONFIG = {
+  name: 'Joy of Baking',
+  domain: 'joyofbaking',
+  website: JOB_AUTHOR_DATA.website,
+  scrapeRecipe: ($: CheerioSelector): Recipe => {
+    return new Recipe(
+      getRecipeName($),
+      JOB_AUTHOR_DATA,
+      new RecipeDetails(), // There is no way to scrape this data from JOB
+      getIngredients($),
+    ); 
+  }
+}
+
+export default JOB_CONFIG;