What is the simplest way to output values of two specific fields from an HTML file?

Viewed 60

I'm fetching the HTML from this url. I'm interested in these are two lines:

<meta name="SAC:price" content="444000"> <meta name="SAC:published" content="2020-03-28 11:06:22">

I want to extract the content value of those two lines. In this example my desired output is

[444000, 2020-03-28 11:06:22]

What is the simplest way to do this? This is what I've tried so far:

function myFunction() {
  var url = "https://asunnot.oikotie.fi/myytavat-asunnot/helsinki/15597485"
  var str = UrlFetchApp.fetch(url).getContentText();
  let r = /ce" content="(\d{6})">|hed" content="(.*)">/g,out=[];     
  let arr = [...str.matchAll(r)]; //[[ce" content="444000">, 444000, null], [hed" content="2020-03-28 11:06:22">, null, 2020-03-28 11:06:22]]
  for(a of arr){
    a.shift();
    (a[0])?out.push(a[0]):out.push(a[1]);
    } 
  Logger.log(out); //[444000, 2020-03-28 11:06:22]
}

This seems excessively cumbersome, any better options? I don't mind how it's done (regex or some other way, as long as I can consistently get the content of those two fields in the simplest way possible)

Final solution thanks to Wiktor Stribiżew's contribution:

function myFunction() {
  var url = "https://asunnot.oikotie.fi/myytavat-asunnot/helsinki/15597485"
  var str = UrlFetchApp.fetch(url).getContentText();
  let r = /(?<=ce" content=")\d{6}(?=">)|(?<=hed" content=").*(?=">)/g;     
  let arr = str.match(r);
  Logger.log(arr); //[444000, 2020-03-28 11:06:22]
}
3 Answers

If you want to get rid of nulls and only keep the match values, make sure you only consume what you want to fetch:

let r = /(?<=ce" content=")\d{6}(?=">)|(?<=hed" content=")[^"]*(?=">)/g;

Here, (?<=ce" content=") and (?<=hed" content=") are positive lookbehinds that match a position in the string that is immediately preceded with some (here, fixed) text and (?=">) is a positive lookahead that match a position in the string that is immediately followed with some text.

See the regex demo

Then, all you need to get the result array is to call the regex with String#match:

let arr = str.match(r);

See more about lookarounds here.

There is one hack to do it, You can use replace with function to grab the value. Please check.

const data = `<meta name="SAC:habitationType" content="1">
 <meta name="SAC:price" content="444000">
<meta name="SAC:published" content="2020-03-28 11:06:22">
<meta name="SAC:listingType" content="1">`
let matches = []
data.replace(/content="(\d{6}|\d\d\d\d-.+)">/g, (_,m) => {
  matches.push(m)
})
console.log(matches)
.as-console-row {color: blue!important}

You've got a | operator. Only one side will match, and thus the capturing group on the other side will be null. The .matchAll() operation always includes the values of all capturing groups in the regular expression, including those that matched nothing.

The linked example page has its own code apparently that figures out which alternative matched. It's not simply using .matchAll() in other words, or it's post-processing the results.

Related