just-one-cookbook.ts 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import { Recipe, IIngredient } from "../../model";
  2. import { RecipeDetails, ISubRecipe } from '../../model';
  3. import { parseIngredients } from '../index';
  4. import { getText, getTextList, rmEquivalence } from './../service';
  5. import R from 'ramda';
  6. const SELECTORS = {
  7. TITLE: 'div.wprm-recipe-name',
  8. PREP_TIME: 'span.wprm-recipe-prep_time-minutes',
  9. COOK_TIME: 'span.wprm-recipe-cook_time-minutes',
  10. SERVINGS: 'span.wprm-recipe-servings',
  11. INGREDIENTS: 'div.wprm-recipe-ingredient-group',
  12. ING: {
  13. AMOUNT: 'span.wprm-recipe-ingredient-amount',
  14. UNIT: 'span.wprm-recipe-ingredient-unit',
  15. NAME: 'span.wprm-recipe-ingredient-name',
  16. NOTE: 'span.wprm-recipe-ingredient-notes'
  17. },
  18. SUB_RECIPE: 'div.wprm-recipe-ingredient-group-name',
  19. SUB_INGREDIENTS: 'li.wprm-recipe-ingredient',
  20. INSTRUCTIONS: 'div.wprm-recipe-instruction-text',
  21. TAGS: 'span.wprm-recipe-keyword',
  22. SUMMARY: 'div.wprm-recipe-summary',
  23. COURSE: 'span.wprm-recipe-course',
  24. IMAGE: 'div.wprm-recipe-image img',
  25. VIDEO: 'div.video-container'
  26. }
  27. const getRecipeName = ($: CheerioSelector): string => {
  28. return $(SELECTORS.TITLE).text();
  29. }
  30. const getRecipeDetails = ($: CheerioSelector): RecipeDetails => {
  31. return {
  32. preparationTime: $(SELECTORS.PREP_TIME).text(),
  33. cookingTime: $(SELECTORS.COOK_TIME).text(),
  34. servings: Number($(SELECTORS.SERVINGS).text()),
  35. video: $(SELECTORS.VIDEO).children()[0].attribs['data-l-src'] || ''
  36. }
  37. };
  38. const getIngredients = ($: CheerioSelector): ISubRecipe[] => {
  39. let ingredients: ISubRecipe[] = [{name: '', ingredients: []}];
  40. const rawData = $(SELECTORS.INGREDIENTS);
  41. const cleanName = (element: CheerioElement, not: string): string => $(element).children().not(not).toArray().map(x => $(x).text()).join(' ');
  42. rawData.each((i, element) => {
  43. const last = ingredients.length - 1;
  44. const getIngredients = (li: Cheerio): IIngredient[] => li.toArray().map(el => ({
  45. ...parseIngredients(cleanName(el, SELECTORS.ING.NOTE)),
  46. note: $(el).find(SELECTORS.ING.NOTE).text(),
  47. _original: $(el).text().trim(),
  48. }));
  49. let subRecipe = $(element).find(SELECTORS.SUB_RECIPE);
  50. let subIngredients = $(element).find(SELECTORS.SUB_INGREDIENTS);
  51. if (subRecipe.contents().length) {
  52. ingredients.push({
  53. name: subRecipe.text(),
  54. ingredients: getIngredients(subIngredients),
  55. })
  56. } else {
  57. ingredients[last].ingredients = getIngredients(subIngredients);
  58. }
  59. })
  60. return ingredients;
  61. }
  62. const JOC_CONFIG = {
  63. name: 'Just One Cookbook',
  64. domain: 'justonecookbook',
  65. website: 'https://www.justonecookbook.com',
  66. scrapeRecipe: ($: CheerioSelector): Recipe => ({
  67. name: getText($)(SELECTORS.TITLE),
  68. author: { name: 'Nami' },
  69. details: getRecipeDetails($),
  70. ingredients: getIngredients($),
  71. instructions: getTextList($)(SELECTORS.INSTRUCTIONS),
  72. tags: (getText($)(SELECTORS.TAGS)).split(',').map(R.trim),
  73. course: [getText($)(SELECTORS.COURSE)],
  74. summary: getText($)(SELECTORS.SUMMARY),
  75. image: $(SELECTORS.IMAGE).attr('nitro-lazy-src')
  76. })
  77. }
  78. export default JOC_CONFIG;