Not the best script in the world but it works for my purposes. Based off https://github.com/dsshafer/cacti-sb6121/blob/master/sb6121.pl

#!/usr/bin/perl
#use strict;

my %data;
my $body;
my $hostname;
my %opts;

my $hostname = '192.168.100.1';
my $URL = 'http://' . $hostname . '/cmSignalData.htm';
$body = `curl $URL 2>/dev/null`;

# Parse Downstream data
if ($body =~ /<CENTER>.*<FONT color=#ffffff>Downstream <\/FONT>(.*?)<\/CENTER>/s) {
  my $downstream = $1;

  # Downstream Signal to Noise Ratios
  if ($downstream =~ /<TR><TD>Signal to Noise Ratio<\/TD>(.*?)<\/TR>/s) {
    my $downstream_snr = $1;

    my $i = 0;
    while ($downstream_snr =~ /<TD>([0-9]+) dB&nbsp;<\/TD>/g) {
      $i++;
      $data{'down_snr_' . $i} = $1;
    }
    die "Didn't find at least one channel" unless ($i > 0);
  }
  else {
    die "Didn't find downstream signal to noise ratios";
  }

  # Downstream Power Levels
  if ($downstream =~ /<TR><TD>Power Level.*?<\/TR>(.*?)<\/TR>/s) {
    my $downstream_power = $1;
    my $i = 0;
    while ($downstream_power =~ /<TD>(-?[0-9]+) dBmV\n&nbsp;<\/TD>/gs) {
      $i++;
      $data{'down_power_' . $i} = $1;
    }
    die "Didn't find at least one channel" unless ($i > 0);
  }
  else {
    die "Didn't find downstream power levels";
  }

}
else {
  die "Didn't find downstream data";
}


# Parse Upstream data
if ($body =~ /<CENTER>.*<FONT color=#ffffff>Upstream <\/FONT>(.*?)<\/CENTER>/s) {
  my $upstream = $1;

  # Upstream Power Levels
  if ($upstream =~ /<TR><TD>Power Level(.*?)<\/TR>/s) {
    my $upstream_power = $1;
    my $i = 0;
    while ($upstream_power =~ /<TD>([0-9]+) dBmV&nbsp;<\/TD>/gs) {
      $i++;
      $data{'up_power_' . $i} = $1;
    }
    die "Didn't find at least one channel" unless ($i > 0);
  }
  else {
    die "Didn't find upstream power levels";
  }

}
else {
  die "Didn't find upstream data";
}

# Parse Signal Stats (Codewords)
if ($body =~ /<CENTER>.*<FONT color=#ffffff>Signal Status \(Codewords\)<\/FONT>(.*?)<\/CENTER>/s) {

  my $signal_stats = $1;

  # Total Unerrored Codewords
  if ($signal_stats =~ /<TR><TD>Total Unerrored Codewords<\/TD>(.*?)<\/TR>/s) {
    my $unerrored_codewords = $1;
    my $i = 0;
    while ($unerrored_codewords =~ /<TD>([0-9]+)&nbsp;<\/TD>/gs) {
      $i++;
      $data{'unerrored_codewords_' . $i} = $1;
    }
    die "Didn't find at least one channel" unless ($i > 0);
  }
  else {
    die "Didn't find unerrored codeword counters";
  }

  # Total Correctable Codewords
  if ($signal_stats =~ /<TR><TD>Total Correctable Codewords<\/TD>(.*?)<\/TR>/s) {
    my $correctable_codewords = $1;
    my $i = 0;
    while ($correctable_codewords =~ /<TD>([0-9]+)&nbsp;<\/TD>/gs) {
      $i++;
      $data{'correctable_codewords_' . $i} = $1;
    }
    die "Didn't find at least one channel" unless ($i > 0);
  }
  else {
    die "Didn't find correctable codeword counters";
  }

  # Total Uncorrectable Codewords
  if ($signal_stats =~ /<TR><TD>Total Uncorrectable Codewords<\/TD>(.*?)<\/TR>/s) {
    my $uncorrectable_codewords = $1;
    my $i = 0;
    while ($uncorrectable_codewords =~ /<TD>([0-9]+)&nbsp;<\/TD>/gs) {
      $i++;
      $data{'uncorrectable_codewords_' . $i} = $1;
    }
    die "Didn't find at least one channel" unless ($i > 0);
  }
  else {
    die "Didn't find uncorrectable codeword counters";
  }
}
else {
  print $body;
  die "Didn't find signal stats";
}


# Output to prometheus

my @pairs;
foreach my $key (sort keys %data)
{
  push @pairs, "$key:$data{$key}";
  my $base = $key;
  $base =~ s/_\d+//g;
  system("echo \"$key $data{$key}\" | curl --data-binary \@- http://192.168.50.203:9091/metrics/job/modem/instance/$base")
}

print join "\n", @pairs;
print "\n";