Extracting structured data from web page using JSOUP and Coldfusion

Viewed 121

I need to extract structured data for recipes from a website using JSOUP (or any other effective method) using Coldfusion.

The data is structure as follows: https://developers.google.com/search/docs/advanced/structured-data/recipe

I need to get the JSON from the page and parse it into useable variables.

I have tried a number of different options without success. I do not know JSOUP and will appreciate your help.

The data looks like this:

<script type="application/ld+json">
{
  "@context": "https://schema.org/",
  "@type": "Recipe",
  "name": "Party Coffee Cake",
  "image": [
    "https://example.com/photos/1x1/photo.jpg",
    "https://example.com/photos/4x3/photo.jpg",
    "https://example.com/photos/16x9/photo.jpg"
  ],
  "author": {
    "@type": "Person",
    "name": "Mary Stone"
  },
  "datePublished": "2018-03-10",
  "description": "This coffee cake is awesome and perfect for parties.",
  "prepTime": "PT20M",
  "cookTime": "PT30M",
  "totalTime": "PT50M",
  "keywords": "cake for a party, coffee",
  "recipeYield": "10",
  "recipeCategory": "Dessert",
  "recipeCuisine": "American",
  "nutrition": {
    "@type": "NutritionInformation",
    "calories": "270 calories"
  },
  "recipeIngredient": [
    "2 cups of flour",
    "3/4 cup white sugar",
    "2 teaspoons baking powder",
    "1/2 teaspoon salt",
    "1/2 cup butter",
    "2 eggs",
    "3/4 cup milk"
    ],
  "recipeInstructions": [
    {
      "@type": "HowToStep",
      "name": "Preheat",
      "text": "Preheat the oven to 350 degrees F. Grease and flour a 9x9 inch pan.",
      "url": "https://example.com/party-coffee-cake#step1",
      "image": "https://example.com/photos/party-coffee-cake/step1.jpg"
    },
    {
      "@type": "HowToStep",
      "name": "Mix dry ingredients",
      "text": "In a large bowl, combine flour, sugar, baking powder, and salt.",
      "url": "https://example.com/party-coffee-cake#step2",
      "image": "https://example.com/photos/party-coffee-cake/step2.jpg"
    },
    {
      "@type": "HowToStep",
      "name": "Add wet ingredients",
      "text": "Mix in the butter, eggs, and milk.",
      "url": "https://example.com/party-coffee-cake#step3",
      "image": "https://example.com/photos/party-coffee-cake/step3.jpg"
    },
    {
      "@type": "HowToStep",
      "name": "Spread into pan",
      "text": "Spread into the prepared pan.",
      "url": "https://example.com/party-coffee-cake#step4",
      "image": "https://example.com/photos/party-coffee-cake/step4.jpg"
    },
    {
      "@type": "HowToStep",
      "name": "Bake",
      "text": "Bake for 30 to 35 minutes, or until firm.",
      "url": "https://example.com/party-coffee-cake#step5",
      "image": "https://example.com/photos/party-coffee-cake/step5.jpg"
    },
    {
      "@type": "HowToStep",
      "name": "Enjoy",
      "text": "Allow to cool and enjoy.",
      "url": "https://example.com/party-coffee-cake#step6",
      "image": "https://example.com/photos/party-coffee-cake/step6.jpg"
    }
  ],
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "5",
    "ratingCount": "18"
  },
  "video": {
    "@type": "VideoObject",
    "name": "How to make a Party Coffee Cake",
    "description": "This is how you make a Party Coffee Cake.",
    "thumbnailUrl": [
      "https://example.com/photos/1x1/photo.jpg",
      "https://example.com/photos/4x3/photo.jpg",
      "https://example.com/photos/16x9/photo.jpg"
     ],
    "contentUrl": "http://www.example.com/video123.mp4",
    "embedUrl": "http://www.example.com/videoplayer?video=123",
    "uploadDate": "2018-02-05T08:00:00+08:00",
    "duration": "PT1M33S",
    "interactionStatistic": {
      "@type": "InteractionCounter",
      "interactionType": { "@type": "WatchAction" },
      "userInteractionCount": 2347
    },
    "expires": "2019-02-05T08:00:00+08:00"
  }
}
</script>

I have tried the following:

<cfset source = "https://www.allrecipes.com/recipe/216319/homemade-sweet-italian-sausage-mild-or-hot/">

<cfhttp method="get" url="#source#" result="theresult" useragent="Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/533.7 (KHTML, like Gecko) Chrome/5.0.391.0 Safari/533.7"> 
<cfhttpparam type="header" name="Accept-Encoding" value="gzip,deflate,sdch" >
<cfhttpparam type="header" name="Proxy-Connection" value="keep-alive" >
<cfhttpparam type="header" name="Accept" value="application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5">
<cfhttpparam type="header" name="Accept-Language" value="en-US,en;q=0.8">
<cfhttpparam type="header" name="Accept-Charset" value="ISO-8859-1,utf-8;q=0.7,*;q=0.3">
<cfhttpparam type="cookie" name="some-cookie" value="1">
</cfhttp>

With he above I get the web page.

I then try to extract the JSON:

<cfscript>
// Create the jsoup object
Jsoup = createObject("java", "org.jsoup.Jsoup");
// HTML string
html = "#theresult.filecontent#";
// Parse the string
document = Jsoup.parse(html);
// Extract content
title = document.title();
tags = document.select("script[type=application/ld+json]"); 
</cfscript>
<cfdump var="#tags#">
<cfloop index="e" array="#tags#">
<cfoutput>
    #e.attr("content")#<br>
</cfoutput>
</cfloop>

But I get nothing returned.

1 Answers
<script type="application/ld+json">[
    {
      "@context": "http://schema.org",
      "@type": "BreadcrumbList",
       ...
    }
</script>

The <script> tag doesn't have an attribute named "content" (only one named "type"). To retrieve the tag contents (or its inner html) use the Element.html() method. Then deserialize the returned contents as json:

<cfscript>
   Jsoup = createObject("java", "org.jsoup.Jsoup");
   document = Jsoup.parse( theResult.fileContent );
   tag = document.select("script[type=application/ld+json]").first(); 
   if (isJSON(tag.html())) {
       contents = deserializeJSON( tag.html() );
       writeDump(contents);
   }
</cfscript>
Related