recipe_scrapers 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (434) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE +20 -0
  4. data/README.md +54 -0
  5. data/lib/recipe_scrapers/configuration.rb +119 -0
  6. data/lib/recipe_scrapers/declaration.rb +85 -0
  7. data/lib/recipe_scrapers/error_tracker.rb +14 -0
  8. data/lib/recipe_scrapers/errors.rb +16 -0
  9. data/lib/recipe_scrapers/http/adapter.rb +50 -0
  10. data/lib/recipe_scrapers/http/address_guard.rb +90 -0
  11. data/lib/recipe_scrapers/http/body_limit.rb +45 -0
  12. data/lib/recipe_scrapers/http/encoding.rb +48 -0
  13. data/lib/recipe_scrapers/http/follow_redirects.rb +75 -0
  14. data/lib/recipe_scrapers/models/ingredient.rb +20 -0
  15. data/lib/recipe_scrapers/models/ingredient_group.rb +20 -0
  16. data/lib/recipe_scrapers/models/nutrient.rb +19 -0
  17. data/lib/recipe_scrapers/models/recipe.rb +125 -0
  18. data/lib/recipe_scrapers/parsers/chain.rb +52 -0
  19. data/lib/recipe_scrapers/parsers/durations.rb +70 -0
  20. data/lib/recipe_scrapers/parsers/ingredients.rb +144 -0
  21. data/lib/recipe_scrapers/parsers/nutrients.rb +47 -0
  22. data/lib/recipe_scrapers/parsers/quantity.rb +46 -0
  23. data/lib/recipe_scrapers/parsers/ratings.rb +26 -0
  24. data/lib/recipe_scrapers/parsers/vocabulary/common.yml +7 -0
  25. data/lib/recipe_scrapers/parsers/vocabulary/de.yml +5 -0
  26. data/lib/recipe_scrapers/parsers/vocabulary/en.yml +26 -0
  27. data/lib/recipe_scrapers/parsers/vocabulary/es.yml +4 -0
  28. data/lib/recipe_scrapers/parsers/vocabulary/fr.yml +5 -0
  29. data/lib/recipe_scrapers/parsers/vocabulary/hu.yml +3 -0
  30. data/lib/recipe_scrapers/parsers/vocabulary/it.yml +4 -0
  31. data/lib/recipe_scrapers/parsers/vocabulary/ja.yml +2 -0
  32. data/lib/recipe_scrapers/parsers/vocabulary/nl.yml +4 -0
  33. data/lib/recipe_scrapers/parsers/vocabulary/pt.yml +8 -0
  34. data/lib/recipe_scrapers/parsers/vocabulary/ru.yml +7 -0
  35. data/lib/recipe_scrapers/parsers/vocabulary/scandinavian.yml +3 -0
  36. data/lib/recipe_scrapers/parsers/vocabulary/sk.yml +3 -0
  37. data/lib/recipe_scrapers/parsers/vocabulary/tr.yml +2 -0
  38. data/lib/recipe_scrapers/parsers/vocabulary.rb +120 -0
  39. data/lib/recipe_scrapers/parsers/yields.rb +30 -0
  40. data/lib/recipe_scrapers/registry.rb +88 -0
  41. data/lib/recipe_scrapers/scraper/parsed_fields.rb +69 -0
  42. data/lib/recipe_scrapers/scraper.rb +199 -0
  43. data/lib/recipe_scrapers/site_path.rb +21 -0
  44. data/lib/recipe_scrapers/sites/au/bestrecipes.rb +3 -0
  45. data/lib/recipe_scrapers/sites/be/15gram.rb +3 -0
  46. data/lib/recipe_scrapers/sites/br/panelinha.rb +3 -0
  47. data/lib/recipe_scrapers/sites/br/receitasnestle.rb +3 -0
  48. data/lib/recipe_scrapers/sites/br/receiteria.rb +3 -0
  49. data/lib/recipe_scrapers/sites/br/tudogostoso.rb +3 -0
  50. data/lib/recipe_scrapers/sites/ch/bettybossi.rb +3 -0
  51. data/lib/recipe_scrapers/sites/ch/migusto.rb +3 -0
  52. data/lib/recipe_scrapers/sites/ch/swissmilk.rb +3 -0
  53. data/lib/recipe_scrapers/sites/co/tasty.rb +3 -0
  54. data/lib/recipe_scrapers/sites/com/365daysofbakingandmore.rb +3 -0
  55. data/lib/recipe_scrapers/sites/com/40aprons.rb +3 -0
  56. data/lib/recipe_scrapers/sites/com/750g.rb +3 -0
  57. data/lib/recipe_scrapers/sites/com/abeautifulmess.rb +3 -0
  58. data/lib/recipe_scrapers/sites/com/abuelascounter.rb +3 -0
  59. data/lib/recipe_scrapers/sites/com/acozykitchen.rb +3 -0
  60. data/lib/recipe_scrapers/sites/com/addapinch.rb +3 -0
  61. data/lib/recipe_scrapers/sites/com/adozensundays.rb +3 -0
  62. data/lib/recipe_scrapers/sites/com/aflavorjournal.rb +3 -0
  63. data/lib/recipe_scrapers/sites/com/afullliving.rb +3 -0
  64. data/lib/recipe_scrapers/sites/com/ahealthysliceoflife.rb +5 -0
  65. data/lib/recipe_scrapers/sites/com/alexandracooks.rb +3 -0
  66. data/lib/recipe_scrapers/sites/com/allnutritious.rb +3 -0
  67. data/lib/recipe_scrapers/sites/com/allthehealthythings.rb +3 -0
  68. data/lib/recipe_scrapers/sites/com/altonbrown.rb +3 -0
  69. data/lib/recipe_scrapers/sites/com/amazingribs.rb +3 -0
  70. data/lib/recipe_scrapers/sites/com/amberskitchencooks.rb +3 -0
  71. data/lib/recipe_scrapers/sites/com/andy_cooks.rb +3 -0
  72. data/lib/recipe_scrapers/sites/com/anitalianinmykitchen.rb +3 -0
  73. data/lib/recipe_scrapers/sites/com/app.rb +27 -0
  74. data/lib/recipe_scrapers/sites/com/asweetpeachef.rb +3 -0
  75. data/lib/recipe_scrapers/sites/com/aubreyskitchen.rb +3 -0
  76. data/lib/recipe_scrapers/sites/com/averiecooks.rb +3 -0
  77. data/lib/recipe_scrapers/sites/com/bake_eat_repeat.rb +3 -0
  78. data/lib/recipe_scrapers/sites/com/bakerbynature.rb +3 -0
  79. data/lib/recipe_scrapers/sites/com/bakewithzoha.rb +3 -0
  80. data/lib/recipe_scrapers/sites/com/baking_sense.rb +3 -0
  81. data/lib/recipe_scrapers/sites/com/bakingmischief.rb +3 -0
  82. data/lib/recipe_scrapers/sites/com/barefeetinthekitchen.rb +3 -0
  83. data/lib/recipe_scrapers/sites/com/barefootinthepines.rb +3 -0
  84. data/lib/recipe_scrapers/sites/com/bbcgoodfood.rb +3 -0
  85. data/lib/recipe_scrapers/sites/com/belleofthekitchen.rb +3 -0
  86. data/lib/recipe_scrapers/sites/com/betterfoodguru.rb +3 -0
  87. data/lib/recipe_scrapers/sites/com/bettycrocker.rb +3 -0
  88. data/lib/recipe_scrapers/sites/com/beyondfrosting.rb +3 -0
  89. data/lib/recipe_scrapers/sites/com/biancazapatka.rb +3 -0
  90. data/lib/recipe_scrapers/sites/com/biggerbolderbaking.rb +3 -0
  91. data/lib/recipe_scrapers/sites/com/billyparisi.rb +3 -0
  92. data/lib/recipe_scrapers/sites/com/bitsofcarey.rb +3 -0
  93. data/lib/recipe_scrapers/sites/com/blogghetti.rb +3 -0
  94. data/lib/recipe_scrapers/sites/com/bluejeanchef.rb +3 -0
  95. data/lib/recipe_scrapers/sites/com/bonappetit.rb +3 -0
  96. data/lib/recipe_scrapers/sites/com/bonviveur.rb +3 -0
  97. data/lib/recipe_scrapers/sites/com/bowlofdelicious.rb +3 -0
  98. data/lib/recipe_scrapers/sites/com/breadtopia.rb +3 -0
  99. data/lib/recipe_scrapers/sites/com/brokenovenbaking.rb +3 -0
  100. data/lib/recipe_scrapers/sites/com/budgetbytes.rb +3 -0
  101. data/lib/recipe_scrapers/sites/com/cafedelites.rb +3 -0
  102. data/lib/recipe_scrapers/sites/com/cakemehometonight.rb +3 -0
  103. data/lib/recipe_scrapers/sites/com/cakewhiz.rb +3 -0
  104. data/lib/recipe_scrapers/sites/com/cambreabakes.rb +3 -0
  105. data/lib/recipe_scrapers/sites/com/carlsbadcravings.rb +3 -0
  106. data/lib/recipe_scrapers/sites/com/castironskilletcooking.rb +3 -0
  107. data/lib/recipe_scrapers/sites/com/celebratingsweets.rb +3 -0
  108. data/lib/recipe_scrapers/sites/com/chefjackovens.rb +3 -0
  109. data/lib/recipe_scrapers/sites/com/chefsavvy.rb +3 -0
  110. data/lib/recipe_scrapers/sites/com/chewoutloud.rb +3 -0
  111. data/lib/recipe_scrapers/sites/com/chocolatewithgrace.rb +3 -0
  112. data/lib/recipe_scrapers/sites/com/ciaoflorentina.rb +3 -0
  113. data/lib/recipe_scrapers/sites/com/closetcooking.rb +3 -0
  114. data/lib/recipe_scrapers/sites/com/cloudykitchen.rb +3 -0
  115. data/lib/recipe_scrapers/sites/com/coleycooks.rb +3 -0
  116. data/lib/recipe_scrapers/sites/com/cookedandloved.rb +3 -0
  117. data/lib/recipe_scrapers/sites/com/cookfastrecipes.rb +3 -0
  118. data/lib/recipe_scrapers/sites/com/cookieandkate.rb +3 -0
  119. data/lib/recipe_scrapers/sites/com/cookiesandcups.rb +3 -0
  120. data/lib/recipe_scrapers/sites/com/cooking.rb +3 -0
  121. data/lib/recipe_scrapers/sites/com/cookingclassy.rb +3 -0
  122. data/lib/recipe_scrapers/sites/com/cookinglsl.rb +3 -0
  123. data/lib/recipe_scrapers/sites/com/cookingwithjanica.rb +3 -0
  124. data/lib/recipe_scrapers/sites/com/cookpad.rb +3 -0
  125. data/lib/recipe_scrapers/sites/com/cookwell.rb +3 -0
  126. data/lib/recipe_scrapers/sites/com/cookwithdana.rb +3 -0
  127. data/lib/recipe_scrapers/sites/com/copykat.rb +3 -0
  128. data/lib/recipe_scrapers/sites/com/countryliving.rb +3 -0
  129. data/lib/recipe_scrapers/sites/com/crazyforcrust.rb +3 -0
  130. data/lib/recipe_scrapers/sites/com/creativecanning.rb +3 -0
  131. data/lib/recipe_scrapers/sites/com/cuisineaz.rb +3 -0
  132. data/lib/recipe_scrapers/sites/com/daringgourmet.rb +3 -0
  133. data/lib/recipe_scrapers/sites/com/dashfordinner.rb +3 -0
  134. data/lib/recipe_scrapers/sites/com/davidlebovitz.rb +3 -0
  135. data/lib/recipe_scrapers/sites/com/deliciouslyella.rb +3 -0
  136. data/lib/recipe_scrapers/sites/com/deliciouslysprinkled.rb +3 -0
  137. data/lib/recipe_scrapers/sites/com/delish.rb +3 -0
  138. data/lib/recipe_scrapers/sites/com/delscookingtwist.rb +3 -0
  139. data/lib/recipe_scrapers/sites/com/dinneratthezoo.rb +3 -0
  140. data/lib/recipe_scrapers/sites/com/directoalpaladar.rb +3 -0
  141. data/lib/recipe_scrapers/sites/com/domesticate_me.rb +3 -0
  142. data/lib/recipe_scrapers/sites/com/downshiftology.rb +3 -0
  143. data/lib/recipe_scrapers/sites/com/eatingbirdfood.rb +3 -0
  144. data/lib/recipe_scrapers/sites/com/eatingeuropean.rb +3 -0
  145. data/lib/recipe_scrapers/sites/com/eatingonadime.rb +3 -0
  146. data/lib/recipe_scrapers/sites/com/eatliverun.rb +3 -0
  147. data/lib/recipe_scrapers/sites/com/eatthismuch.rb +3 -0
  148. data/lib/recipe_scrapers/sites/com/elavegan.rb +3 -0
  149. data/lib/recipe_scrapers/sites/com/emilybites.rb +3 -0
  150. data/lib/recipe_scrapers/sites/com/erinliveswhole.rb +3 -0
  151. data/lib/recipe_scrapers/sites/com/erinscozykitchen.rb +3 -0
  152. data/lib/recipe_scrapers/sites/com/errenskitchen.rb +3 -0
  153. data/lib/recipe_scrapers/sites/com/everyday_delicious.rb +3 -0
  154. data/lib/recipe_scrapers/sites/com/everydaypie.rb +3 -0
  155. data/lib/recipe_scrapers/sites/com/evolvingtable.rb +3 -0
  156. data/lib/recipe_scrapers/sites/com/familyfoodonthetable.rb +3 -0
  157. data/lib/recipe_scrapers/sites/com/familyspice.rb +3 -0
  158. data/lib/recipe_scrapers/sites/com/fantabulosity.rb +3 -0
  159. data/lib/recipe_scrapers/sites/com/farmhouseonboone.rb +3 -0
  160. data/lib/recipe_scrapers/sites/com/farmtojar.rb +3 -0
  161. data/lib/recipe_scrapers/sites/com/feastingathome.rb +3 -0
  162. data/lib/recipe_scrapers/sites/com/fifteenspatulas.rb +3 -0
  163. data/lib/recipe_scrapers/sites/com/figjar.rb +3 -0
  164. data/lib/recipe_scrapers/sites/com/finedininglovers.rb +3 -0
  165. data/lib/recipe_scrapers/sites/com/fithealthymacros.rb +3 -0
  166. data/lib/recipe_scrapers/sites/com/fitslowcookerqueen.rb +3 -0
  167. data/lib/recipe_scrapers/sites/com/food.rb +3 -0
  168. data/lib/recipe_scrapers/sites/com/foodbymaria.rb +3 -0
  169. data/lib/recipe_scrapers/sites/com/foodfidelity.rb +3 -0
  170. data/lib/recipe_scrapers/sites/com/foodrepublic.rb +3 -0
  171. data/lib/recipe_scrapers/sites/com/forksoverknives.rb +3 -0
  172. data/lib/recipe_scrapers/sites/com/garlicandzest.rb +3 -0
  173. data/lib/recipe_scrapers/sites/com/garnishandglaze.rb +3 -0
  174. data/lib/recipe_scrapers/sites/com/gimmesomeoven.rb +3 -0
  175. data/lib/recipe_scrapers/sites/com/girlgonegourmet.rb +3 -0
  176. data/lib/recipe_scrapers/sites/com/girlversusdough.rb +3 -0
  177. data/lib/recipe_scrapers/sites/com/gloriousrecipes.rb +3 -0
  178. data/lib/recipe_scrapers/sites/com/glutenfreeonashoestring.rb +3 -0
  179. data/lib/recipe_scrapers/sites/com/gonnawantseconds.rb +3 -0
  180. data/lib/recipe_scrapers/sites/com/goodfooddiscoveries.rb +3 -0
  181. data/lib/recipe_scrapers/sites/com/goodhousekeeping.rb +3 -0
  182. data/lib/recipe_scrapers/sites/com/grandbaby_cakes.rb +3 -0
  183. data/lib/recipe_scrapers/sites/com/greatbritishchefs.rb +3 -0
  184. data/lib/recipe_scrapers/sites/com/halfbakedharvest.rb +3 -0
  185. data/lib/recipe_scrapers/sites/com/hassanchef.rb +3 -0
  186. data/lib/recipe_scrapers/sites/com/headbangerskitchen.rb +3 -0
  187. data/lib/recipe_scrapers/sites/com/healthywithachanceofsprinkles.rb +3 -0
  188. data/lib/recipe_scrapers/sites/com/heatherchristo.rb +3 -0
  189. data/lib/recipe_scrapers/sites/com/hilahcooking.rb +3 -0
  190. data/lib/recipe_scrapers/sites/com/hogarmania.rb +3 -0
  191. data/lib/recipe_scrapers/sites/com/homeandplate.rb +3 -0
  192. data/lib/recipe_scrapers/sites/com/hostthetoast.rb +3 -0
  193. data/lib/recipe_scrapers/sites/com/houseofnasheats.rb +3 -0
  194. data/lib/recipe_scrapers/sites/com/houseofyumm.rb +3 -0
  195. data/lib/recipe_scrapers/sites/com/iamafoodblog.rb +3 -0
  196. data/lib/recipe_scrapers/sites/com/im_worthy.rb +3 -0
  197. data/lib/recipe_scrapers/sites/com/inbloombakery.rb +3 -0
  198. data/lib/recipe_scrapers/sites/com/indianhealthyrecipes.rb +3 -0
  199. data/lib/recipe_scrapers/sites/com/ingoodflavor.rb +3 -0
  200. data/lib/recipe_scrapers/sites/com/inspiralized.rb +3 -0
  201. data/lib/recipe_scrapers/sites/com/itdoesnttastelikechicken.rb +3 -0
  202. data/lib/recipe_scrapers/sites/com/itsnotaboutnutrition.rb +3 -0
  203. data/lib/recipe_scrapers/sites/com/izzycooking.rb +3 -0
  204. data/lib/recipe_scrapers/sites/com/jennycancook.rb +3 -0
  205. data/lib/recipe_scrapers/sites/com/jimcooksfoodgood.rb +3 -0
  206. data/lib/recipe_scrapers/sites/com/jocooks.rb +3 -0
  207. data/lib/recipe_scrapers/sites/com/joyfullymad.rb +3 -0
  208. data/lib/recipe_scrapers/sites/com/joythebaker.rb +3 -0
  209. data/lib/recipe_scrapers/sites/com/juliasalbum.rb +3 -0
  210. data/lib/recipe_scrapers/sites/com/justataste.rb +3 -0
  211. data/lib/recipe_scrapers/sites/com/justinesnacks.rb +3 -0
  212. data/lib/recipe_scrapers/sites/com/kennethtemple.rb +3 -0
  213. data/lib/recipe_scrapers/sites/com/keytomylime.rb +3 -0
  214. data/lib/recipe_scrapers/sites/com/kitchendreaming.rb +3 -0
  215. data/lib/recipe_scrapers/sites/com/kitchenstories.rb +3 -0
  216. data/lib/recipe_scrapers/sites/com/kristineskitchenblog.rb +3 -0
  217. data/lib/recipe_scrapers/sites/com/krollskorner.rb +3 -0
  218. data/lib/recipe_scrapers/sites/com/lanascooking.rb +3 -0
  219. data/lib/recipe_scrapers/sites/com/laurenslatest.rb +3 -0
  220. data/lib/recipe_scrapers/sites/com/lazycatkitchen.rb +3 -0
  221. data/lib/recipe_scrapers/sites/com/lecremedelacrumb.rb +3 -0
  222. data/lib/recipe_scrapers/sites/com/leitesculinaria.rb +3 -0
  223. data/lib/recipe_scrapers/sites/com/lekkerensimpel.rb +3 -0
  224. data/lib/recipe_scrapers/sites/com/letscampsmore.rb +3 -0
  225. data/lib/recipe_scrapers/sites/com/lifestyleofafoodie.rb +3 -0
  226. data/lib/recipe_scrapers/sites/com/littleferrarokitchen.rb +3 -0
  227. data/lib/recipe_scrapers/sites/com/littlespicejar.rb +3 -0
  228. data/lib/recipe_scrapers/sites/com/littlespoonfarm.rb +3 -0
  229. data/lib/recipe_scrapers/sites/com/littlesunnykitchen.rb +3 -0
  230. data/lib/recipe_scrapers/sites/com/livelytable.rb +3 -0
  231. data/lib/recipe_scrapers/sites/com/lolascocina.rb +3 -0
  232. data/lib/recipe_scrapers/sites/com/lovingitvegan.rb +3 -0
  233. data/lib/recipe_scrapers/sites/com/madsvin.rb +3 -0
  234. data/lib/recipe_scrapers/sites/com/makeitdairyfree.rb +3 -0
  235. data/lib/recipe_scrapers/sites/com/mealprepmanual.rb +3 -0
  236. data/lib/recipe_scrapers/sites/com/meganvskitchen.rb +3 -0
  237. data/lib/recipe_scrapers/sites/com/melissaknorris.rb +3 -0
  238. data/lib/recipe_scrapers/sites/com/melskitchencafe.rb +3 -0
  239. data/lib/recipe_scrapers/sites/com/mexicanplease.rb +3 -0
  240. data/lib/recipe_scrapers/sites/com/minimalistbaker.rb +3 -0
  241. data/lib/recipe_scrapers/sites/com/ministryofcurry.rb +3 -0
  242. data/lib/recipe_scrapers/sites/com/modernhoney.rb +3 -0
  243. data/lib/recipe_scrapers/sites/com/momontimeout.rb +3 -0
  244. data/lib/recipe_scrapers/sites/com/momswithcrockpots.rb +3 -0
  245. data/lib/recipe_scrapers/sites/com/motherthyme.rb +3 -0
  246. data/lib/recipe_scrapers/sites/com/mybakingaddiction.rb +3 -0
  247. data/lib/recipe_scrapers/sites/com/myjewishlearning.rb +3 -0
  248. data/lib/recipe_scrapers/sites/com/mykidslickthebowl.rb +3 -0
  249. data/lib/recipe_scrapers/sites/com/mykoreankitchen.rb +3 -0
  250. data/lib/recipe_scrapers/sites/com/myriadrecipes.rb +3 -0
  251. data/lib/recipe_scrapers/sites/com/myvegetarianroots.rb +3 -0
  252. data/lib/recipe_scrapers/sites/com/natashaskitchen.rb +3 -0
  253. data/lib/recipe_scrapers/sites/com/naturallyella.rb +3 -0
  254. data/lib/recipe_scrapers/sites/com/noracooks.rb +3 -0
  255. data/lib/recipe_scrapers/sites/com/norecipes.rb +3 -0
  256. data/lib/recipe_scrapers/sites/com/notenoughcinnamon.rb +3 -0
  257. data/lib/recipe_scrapers/sites/com/nourishedbynutrition.rb +3 -0
  258. data/lib/recipe_scrapers/sites/com/number_2_pencil.rb +3 -0
  259. data/lib/recipe_scrapers/sites/com/onceuponachef.rb +3 -0
  260. data/lib/recipe_scrapers/sites/com/onesweetappetite.rb +3 -0
  261. data/lib/recipe_scrapers/sites/com/organicallyaddison.rb +3 -0
  262. data/lib/recipe_scrapers/sites/com/ourbestbites.rb +3 -0
  263. data/lib/recipe_scrapers/sites/com/paleorunningmomma.rb +3 -0
  264. data/lib/recipe_scrapers/sites/com/panlasangpinoy.rb +3 -0
  265. data/lib/recipe_scrapers/sites/com/peelwithzeal.rb +3 -0
  266. data/lib/recipe_scrapers/sites/com/pequerecetas.rb +3 -0
  267. data/lib/recipe_scrapers/sites/com/pilipinasrecipes.rb +3 -0
  268. data/lib/recipe_scrapers/sites/com/pinkowlkitchen.rb +3 -0
  269. data/lib/recipe_scrapers/sites/com/plantyou.rb +3 -0
  270. data/lib/recipe_scrapers/sites/com/platingpixels.rb +3 -0
  271. data/lib/recipe_scrapers/sites/com/platingsandpairings.rb +3 -0
  272. data/lib/recipe_scrapers/sites/com/plowingthroughlife.rb +3 -0
  273. data/lib/recipe_scrapers/sites/com/polishfoodies.rb +3 -0
  274. data/lib/recipe_scrapers/sites/com/practicalselfreliance.rb +3 -0
  275. data/lib/recipe_scrapers/sites/com/preppykitchen.rb +3 -0
  276. data/lib/recipe_scrapers/sites/com/pressureluckcooking.rb +3 -0
  277. data/lib/recipe_scrapers/sites/com/purelypope.rb +3 -0
  278. data/lib/recipe_scrapers/sites/com/rachlmansfield.rb +3 -0
  279. data/lib/recipe_scrapers/sites/com/rainbowplantlife.rb +3 -0
  280. data/lib/recipe_scrapers/sites/com/realfoodwell.rb +3 -0
  281. data/lib/recipe_scrapers/sites/com/realmomnutrition.rb +3 -0
  282. data/lib/recipe_scrapers/sites/com/receitas.rb +3 -0
  283. data/lib/recipe_scrapers/sites/com/recipeforperfection.rb +3 -0
  284. data/lib/recipe_scrapers/sites/com/recipegirl.rb +3 -0
  285. data/lib/recipe_scrapers/sites/com/reciperunner.rb +3 -0
  286. data/lib/recipe_scrapers/sites/com/recipetineats.rb +3 -0
  287. data/lib/recipe_scrapers/sites/com/redhousespice.rb +3 -0
  288. data/lib/recipe_scrapers/sites/com/ricardocuisine.rb +3 -0
  289. data/lib/recipe_scrapers/sites/com/sallysbakingaddiction.rb +3 -0
  290. data/lib/recipe_scrapers/sites/com/saltpepperskillet.rb +3 -0
  291. data/lib/recipe_scrapers/sites/com/sandwichtribunal.rb +3 -0
  292. data/lib/recipe_scrapers/sites/com/savoringthegood.rb +3 -0
  293. data/lib/recipe_scrapers/sites/com/savorynothings.rb +3 -0
  294. data/lib/recipe_scrapers/sites/com/savorythoughts.rb +3 -0
  295. data/lib/recipe_scrapers/sites/com/scrummylane.rb +3 -0
  296. data/lib/recipe_scrapers/sites/com/shelikesfood.rb +3 -0
  297. data/lib/recipe_scrapers/sites/com/simple_veganista.rb +3 -0
  298. data/lib/recipe_scrapers/sites/com/simplehomeedit.rb +3 -0
  299. data/lib/recipe_scrapers/sites/com/simplyquinoa.rb +3 -0
  300. data/lib/recipe_scrapers/sites/com/simplywhisked.rb +3 -0
  301. data/lib/recipe_scrapers/sites/com/sipandfeast.rb +3 -0
  302. data/lib/recipe_scrapers/sites/com/sizzlefish.rb +3 -0
  303. data/lib/recipe_scrapers/sites/com/skinnytaste.rb +3 -0
  304. data/lib/recipe_scrapers/sites/com/smalltownwoman.rb +3 -0
  305. data/lib/recipe_scrapers/sites/com/somuchfoodblog.rb +3 -0
  306. data/lib/recipe_scrapers/sites/com/southernbite.rb +3 -0
  307. data/lib/recipe_scrapers/sites/com/spainonafork.rb +3 -0
  308. data/lib/recipe_scrapers/sites/com/spendwithpennies.rb +3 -0
  309. data/lib/recipe_scrapers/sites/com/spicysouthernkitchen.rb +3 -0
  310. data/lib/recipe_scrapers/sites/com/stacyling.rb +3 -0
  311. data/lib/recipe_scrapers/sites/com/staysnatched.rb +3 -0
  312. data/lib/recipe_scrapers/sites/com/steamykitchen.rb +3 -0
  313. data/lib/recipe_scrapers/sites/com/strongrfastr.rb +3 -0
  314. data/lib/recipe_scrapers/sites/com/sudachirecipes.rb +3 -0
  315. data/lib/recipe_scrapers/sites/com/sugarhero.rb +3 -0
  316. data/lib/recipe_scrapers/sites/com/sugarmaplefarmhouse.rb +3 -0
  317. data/lib/recipe_scrapers/sites/com/sugarspunrun.rb +3 -0
  318. data/lib/recipe_scrapers/sites/com/sunset.rb +3 -0
  319. data/lib/recipe_scrapers/sites/com/sweetcsdesigns.rb +3 -0
  320. data/lib/recipe_scrapers/sites/com/tableanddish.rb +3 -0
  321. data/lib/recipe_scrapers/sites/com/tasteandtellblog.rb +3 -0
  322. data/lib/recipe_scrapers/sites/com/tasteofhome.rb +3 -0
  323. data/lib/recipe_scrapers/sites/com/tastesbetterfromscratch.rb +3 -0
  324. data/lib/recipe_scrapers/sites/com/tastesoflizzyt.rb +3 -0
  325. data/lib/recipe_scrapers/sites/com/tastyoven.rb +3 -0
  326. data/lib/recipe_scrapers/sites/com/tatyanaseverydayfood.rb +3 -0
  327. data/lib/recipe_scrapers/sites/com/teakandthyme.rb +3 -0
  328. data/lib/recipe_scrapers/sites/com/thealmondeater.rb +3 -0
  329. data/lib/recipe_scrapers/sites/com/thebigmansworld.rb +3 -0
  330. data/lib/recipe_scrapers/sites/com/theclevercarrot.rb +3 -0
  331. data/lib/recipe_scrapers/sites/com/thecookierookie.rb +3 -0
  332. data/lib/recipe_scrapers/sites/com/thefoodcharlatan.rb +3 -0
  333. data/lib/recipe_scrapers/sites/com/thefoodietakesflight.rb +3 -0
  334. data/lib/recipe_scrapers/sites/com/theglutenfreeaustrian.rb +3 -0
  335. data/lib/recipe_scrapers/sites/com/theguardian.rb +3 -0
  336. data/lib/recipe_scrapers/sites/com/theicecreamconfectionals.rb +3 -0
  337. data/lib/recipe_scrapers/sites/com/thekitchenmagpie.rb +3 -0
  338. data/lib/recipe_scrapers/sites/com/themagicalslowcooker.rb +3 -0
  339. data/lib/recipe_scrapers/sites/com/themediterraneandish.rb +3 -0
  340. data/lib/recipe_scrapers/sites/com/themodernproper.rb +3 -0
  341. data/lib/recipe_scrapers/sites/com/thepalatablelife.rb +3 -0
  342. data/lib/recipe_scrapers/sites/com/thepioneerwoman.rb +3 -0
  343. data/lib/recipe_scrapers/sites/com/theppk.rb +3 -0
  344. data/lib/recipe_scrapers/sites/com/therecipecritic.rb +3 -0
  345. data/lib/recipe_scrapers/sites/com/thesaltymarshmallow.rb +3 -0
  346. data/lib/recipe_scrapers/sites/com/thespicetrain.rb +3 -0
  347. data/lib/recipe_scrapers/sites/com/thesuburbansoapbox.rb +3 -0
  348. data/lib/recipe_scrapers/sites/com/thevintagemixer.rb +3 -0
  349. data/lib/recipe_scrapers/sites/com/thewoodenskillet.rb +3 -0
  350. data/lib/recipe_scrapers/sites/com/thinlicious.rb +3 -0
  351. data/lib/recipe_scrapers/sites/com/thishealthytable.rb +3 -0
  352. data/lib/recipe_scrapers/sites/com/toriavey.rb +3 -0
  353. data/lib/recipe_scrapers/sites/com/twopeasandtheirpod.rb +3 -0
  354. data/lib/recipe_scrapers/sites/com/unsophisticook.rb +3 -0
  355. data/lib/recipe_scrapers/sites/com/valentinascorner.rb +3 -0
  356. data/lib/recipe_scrapers/sites/com/vanillaandbean.rb +3 -0
  357. data/lib/recipe_scrapers/sites/com/veganricha.rb +3 -0
  358. data/lib/recipe_scrapers/sites/com/vegrecipesofindia.rb +3 -0
  359. data/lib/recipe_scrapers/sites/com/wearenotmartha.rb +3 -0
  360. data/lib/recipe_scrapers/sites/com/wedishitup.rb +3 -0
  361. data/lib/recipe_scrapers/sites/com/wellplated.rb +3 -0
  362. data/lib/recipe_scrapers/sites/com/whatsgabycooking.rb +3 -0
  363. data/lib/recipe_scrapers/sites/com/wyseguide.rb +3 -0
  364. data/lib/recipe_scrapers/sites/com/yemek.rb +3 -0
  365. data/lib/recipe_scrapers/sites/com/zenbelly.rb +3 -0
  366. data/lib/recipe_scrapers/sites/com/zestfulkitchen.rb +3 -0
  367. data/lib/recipe_scrapers/sites/de/bofrost.rb +3 -0
  368. data/lib/recipe_scrapers/sites/de/chefkoch.rb +26 -0
  369. data/lib/recipe_scrapers/sites/de/eattolerant.rb +3 -0
  370. data/lib/recipe_scrapers/sites/de/emmikochteinfach.rb +3 -0
  371. data/lib/recipe_scrapers/sites/de/kochbar.rb +3 -0
  372. data/lib/recipe_scrapers/sites/de/springlane.rb +3 -0
  373. data/lib/recipe_scrapers/sites/dk/madensverden.rb +3 -0
  374. data/lib/recipe_scrapers/sites/dk/sundpaabudget.rb +3 -0
  375. data/lib/recipe_scrapers/sites/fr/jow.rb +3 -0
  376. data/lib/recipe_scrapers/sites/fr/madame.rb +35 -0
  377. data/lib/recipe_scrapers/sites/hu/nosalty.rb +3 -0
  378. data/lib/recipe_scrapers/sites/hu/sobors.rb +3 -0
  379. data/lib/recipe_scrapers/sites/info/misya.rb +3 -0
  380. data/lib/recipe_scrapers/sites/it/cucchiaio.rb +3 -0
  381. data/lib/recipe_scrapers/sites/it/ricette.rb +3 -0
  382. data/lib/recipe_scrapers/sites/it/ricetteperbimby.rb +3 -0
  383. data/lib/recipe_scrapers/sites/me/leckerschmecker.rb +3 -0
  384. data/lib/recipe_scrapers/sites/menu/1000.rb +3 -0
  385. data/lib/recipe_scrapers/sites/mx/cocinafacil.rb +3 -0
  386. data/lib/recipe_scrapers/sites/mx/directoalpaladar.rb +3 -0
  387. data/lib/recipe_scrapers/sites/mx/recetasnestle.rb +3 -0
  388. data/lib/recipe_scrapers/sites/net/bellyfull.rb +3 -0
  389. data/lib/recipe_scrapers/sites/net/castironketo.rb +3 -0
  390. data/lib/recipe_scrapers/sites/net/feelgoodfoodie.rb +3 -0
  391. data/lib/recipe_scrapers/sites/net/hungryhappens.rb +3 -0
  392. data/lib/recipe_scrapers/sites/net/iambaker.rb +3 -0
  393. data/lib/recipe_scrapers/sites/net/inspiredtaste.rb +3 -0
  394. data/lib/recipe_scrapers/sites/net/piesandplots.rb +3 -0
  395. data/lib/recipe_scrapers/sites/net/tidymom.rb +3 -0
  396. data/lib/recipe_scrapers/sites/nl/leukerecepten.rb +3 -0
  397. data/lib/recipe_scrapers/sites/nl/projectgezond.rb +3 -0
  398. data/lib/recipe_scrapers/sites/no/godt.rb +3 -0
  399. data/lib/recipe_scrapers/sites/no/matprat.rb +3 -0
  400. data/lib/recipe_scrapers/sites/no/nrk.rb +3 -0
  401. data/lib/recipe_scrapers/sites/no/tine.rb +3 -0
  402. data/lib/recipe_scrapers/sites/org/lmld.rb +3 -0
  403. data/lib/recipe_scrapers/sites/org/marmiton.rb +3 -0
  404. data/lib/recipe_scrapers/sites/org/nutritionfacts.rb +3 -0
  405. data/lib/recipe_scrapers/sites/org/thekitchencommunity.rb +3 -0
  406. data/lib/recipe_scrapers/sites/plus/recette.rb +3 -0
  407. data/lib/recipe_scrapers/sites/pt/pingodoce.rb +3 -0
  408. data/lib/recipe_scrapers/sites/pt/teleculinaria.rb +3 -0
  409. data/lib/recipe_scrapers/sites/recipes/goodstuff.rb +3 -0
  410. data/lib/recipe_scrapers/sites/recipes/howtocook.rb +3 -0
  411. data/lib/recipe_scrapers/sites/ru/eda.rb +3 -0
  412. data/lib/recipe_scrapers/sites/ru/edimdoma.rb +3 -0
  413. data/lib/recipe_scrapers/sites/ru/gastronom.rb +3 -0
  414. data/lib/recipe_scrapers/sites/ru/iamcook.rb +6 -0
  415. data/lib/recipe_scrapers/sites/ru/povar.rb +3 -0
  416. data/lib/recipe_scrapers/sites/ru/russianfood.rb +8 -0
  417. data/lib/recipe_scrapers/sites/se/alltommat.rb +3 -0
  418. data/lib/recipe_scrapers/sites/se/ica.rb +3 -0
  419. data/lib/recipe_scrapers/sites/se/kiddokitchen.rb +3 -0
  420. data/lib/recipe_scrapers/sites/se/koket.rb +3 -0
  421. data/lib/recipe_scrapers/sites/se/recept.rb +3 -0
  422. data/lib/recipe_scrapers/sites/sk/receptyprevas.rb +3 -0
  423. data/lib/recipe_scrapers/sources/declared.rb +38 -0
  424. data/lib/recipe_scrapers/sources/ingredient_groups.rb +74 -0
  425. data/lib/recipe_scrapers/sources/json_ld.rb +93 -0
  426. data/lib/recipe_scrapers/sources/microdata.rb +113 -0
  427. data/lib/recipe_scrapers/sources/open_graph.rb +26 -0
  428. data/lib/recipe_scrapers/sources/schema_org/ingredient_list.rb +36 -0
  429. data/lib/recipe_scrapers/sources/schema_org/nutrition_facts.rb +21 -0
  430. data/lib/recipe_scrapers/sources/schema_org.rb +160 -0
  431. data/lib/recipe_scrapers/text.rb +59 -0
  432. data/lib/recipe_scrapers/version.rb +6 -0
  433. data/lib/recipe_scrapers.rb +137 -0
  434. metadata +560 -0
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "nokogiri"
4
+
5
+ module RecipeScrapers
6
+ module Text
7
+ MARKUP = /[&<]/
8
+ WHITESPACE = /[[:space:]]+/
9
+ DROPPED = ["​", "‎", "‏"].freeze
10
+ TEXTLESS = %w[script style template noscript].freeze
11
+
12
+ class << self
13
+ def content(node)
14
+ return nil if node.nil? || TEXTLESS.include?(node.name)
15
+ return node.text if node.text? || node.cdata?
16
+ return nil unless node.element?
17
+
18
+ node.children.filter_map { |child| content(child) }.join
19
+ end
20
+
21
+ def normalize(value)
22
+ return nil if value.nil?
23
+
24
+ cleaned = collapse_parentheses(strip_markup(value.to_s))
25
+ cleaned = DROPPED.reduce(cleaned) { |text, dropped| text.delete(dropped) }
26
+ cleaned = cleaned.gsub(WHITESPACE, " ").strip
27
+ cleaned.empty? ? nil : cleaned
28
+ end
29
+
30
+ def recode(html, encoding_name)
31
+ return html if encoding_name.nil?
32
+ return html if html.encoding == ::Encoding::UTF_8 && html.valid_encoding?
33
+
34
+ bytes = html.dup.force_encoding(encoding_name)
35
+ bytes.encode(::Encoding::UTF_8, invalid: :replace, undef: :replace)
36
+ rescue ArgumentError
37
+ html
38
+ end
39
+
40
+ private
41
+
42
+ def strip_markup(value)
43
+ previous = nil
44
+ current = value
45
+ while previous != current && current.match?(MARKUP)
46
+ previous = current
47
+ current = Nokogiri::HTML5.fragment(current).text
48
+ end
49
+ current
50
+ end
51
+
52
+ def collapse_parentheses(value)
53
+ return value unless value.include?("((") && value.include?("))")
54
+
55
+ value.gsub("((", "(").gsub("))", ")")
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RecipeScrapers
4
+ # The version of the gem.
5
+ VERSION = "0.1.0"
6
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "recipe_scrapers/version"
4
+ require_relative "recipe_scrapers/errors"
5
+ require_relative "recipe_scrapers/error_tracker"
6
+ require_relative "recipe_scrapers/text"
7
+ require_relative "recipe_scrapers/models/ingredient"
8
+ require_relative "recipe_scrapers/models/nutrient"
9
+ require_relative "recipe_scrapers/models/ingredient_group"
10
+ require_relative "recipe_scrapers/models/recipe"
11
+ require_relative "recipe_scrapers/parsers/quantity"
12
+ require_relative "recipe_scrapers/parsers/vocabulary"
13
+ require_relative "recipe_scrapers/parsers/ingredients"
14
+ require_relative "recipe_scrapers/parsers/nutrients"
15
+ require_relative "recipe_scrapers/parsers/chain"
16
+ require_relative "recipe_scrapers/parsers/durations"
17
+ require_relative "recipe_scrapers/parsers/yields"
18
+ require_relative "recipe_scrapers/parsers/ratings"
19
+ require_relative "recipe_scrapers/sources/json_ld"
20
+ require_relative "recipe_scrapers/sources/microdata"
21
+ require_relative "recipe_scrapers/sources/open_graph"
22
+ require_relative "recipe_scrapers/sources/declared"
23
+ require_relative "recipe_scrapers/sources/ingredient_groups"
24
+ require_relative "recipe_scrapers/sources/schema_org"
25
+ require_relative "recipe_scrapers/sources/schema_org/ingredient_list"
26
+ require_relative "recipe_scrapers/sources/schema_org/nutrition_facts"
27
+ require_relative "recipe_scrapers/scraper/parsed_fields"
28
+ require_relative "recipe_scrapers/scraper"
29
+ require_relative "recipe_scrapers/declaration"
30
+ require_relative "recipe_scrapers/registry"
31
+ require_relative "recipe_scrapers/site_path"
32
+ require_relative "recipe_scrapers/http/address_guard"
33
+ require_relative "recipe_scrapers/http/adapter"
34
+ require_relative "recipe_scrapers/http/follow_redirects"
35
+ require_relative "recipe_scrapers/http/body_limit"
36
+ require_relative "recipe_scrapers/http/encoding"
37
+ require_relative "recipe_scrapers/configuration"
38
+
39
+ # Reads structured recipes from cooking websites.
40
+ #
41
+ # The gem reads the schema.org JSON-LD or microdata a page publishes, falls back to OpenGraph, and
42
+ # takes a site declaration where a site publishes neither. {scrape} fetches a page, {parse} reads
43
+ # HTML you already have, and both return a {Models::Recipe}.
44
+ #
45
+ # @example Fetch and read a recipe
46
+ # recipe = RecipeScrapers.scrape("https://www.recipetineats.com/crispy-potato-straws-pommes-paille/")
47
+ # recipe.title # => "Crispy potato straws (Pommes Paille)"
48
+ # recipe.ingredients # => ["1 potato (Aus: Sebago, US: russet, UK: Maris Piper), ...", ...]
49
+ module RecipeScrapers
50
+ class << self
51
+ # Reads a recipe from HTML that is already fetched.
52
+ #
53
+ # @param html [String] the page source
54
+ # @param url [String] the address of the page, used to pick the site and to resolve relative links
55
+ # @param supported_only [Boolean] raise for a host the gem does not support. Pass false to read
56
+ # any page that publishes schema.org or OpenGraph markup
57
+ # @return [Models::Recipe]
58
+ # @raise [UnsupportedSite] when the host is not registered and supported_only is true
59
+ # @raise [RecipeNotFound] when the page has no title or no ingredients
60
+ def parse(html, url:, supported_only: true)
61
+ entry = Registry.for(url)
62
+ raise UnsupportedSite, "no scraper registered for #{url}" if entry.nil? && supported_only
63
+
64
+ scraper = build_scraper(entry, html, url)
65
+ raise RecipeNotFound, "no recipe found at #{url}" unless scraper.recipe?
66
+
67
+ scraper.to_recipe
68
+ end
69
+
70
+ # Fetches a page and reads its recipe.
71
+ #
72
+ # The page is fetched through {Configuration#connection}, which follows redirects, refuses private
73
+ # addresses and caps the body size, unless you pass your own connection.
74
+ #
75
+ # @param url [String] the address of the recipe page
76
+ # @param connection [Faraday::Connection, nil] the connection to fetch with
77
+ # @param supported_only [Boolean] see {parse}
78
+ # @return [Models::Recipe]
79
+ # @raise [UnsupportedSite] see {parse}
80
+ # @raise [RecipeNotFound] see {parse}
81
+ # @raise [BlockedAddress, TooManyRedirects, ResponseTooLarge] when the fetch is refused
82
+ # @raise [Faraday::Error] when the fetch fails after the configured retries
83
+ def scrape(url, connection: nil, supported_only: true)
84
+ response = (connection || config.connection).get(url)
85
+ parse(response.body, url: url, supported_only: supported_only)
86
+ end
87
+
88
+ # Registers a site by declaration. A shortcut for {Registry.register}.
89
+ #
90
+ # @example
91
+ # RecipeScrapers.register "example.com" do
92
+ # title "h1.recipe-title"
93
+ # ingredients rows: "ul.ingredients li"
94
+ # end
95
+ # @return [Declaration]
96
+ def register(...)
97
+ Registry.register(...)
98
+ end
99
+
100
+ # The settings every fetch and parse uses.
101
+ #
102
+ # @return [Configuration]
103
+ def config
104
+ @config ||= Configuration.new
105
+ end
106
+
107
+ # Changes the settings in a block.
108
+ #
109
+ # @example
110
+ # RecipeScrapers.configure do |config|
111
+ # config.timeout = 30
112
+ # end
113
+ # @yieldparam config [Configuration]
114
+ # @return [Configuration]
115
+ def configure
116
+ yield(config)
117
+ config
118
+ end
119
+
120
+ # Throws the settings away, so the next {config} call starts from the defaults.
121
+ #
122
+ # @return [void]
123
+ def reset_config!
124
+ @config = nil
125
+ end
126
+
127
+ private
128
+
129
+ def build_scraper(entry, html, url)
130
+ return entry.new(html, url: url) if entry.is_a?(Class)
131
+
132
+ Scraper.new(html, url: url, declaration: entry)
133
+ end
134
+ end
135
+ end
136
+
137
+ Dir[File.expand_path("recipe_scrapers/sites/**/*.rb", __dir__)].each { |file| require file }