Floki parse and group by heading

This is brittle as all get-out because it makes some serious assumptions about the shape of the data, but:

def extract_topic_maps(html) do
  nodes = Floki.find(html, "section.body-copy > *")

  {_, topic_maps} =
    Enum.reduce(nodes, {nil, []}, fn
      {"p", _, _}, {nil, _} -> raise "Invalid state: no topic"
      # New topic, set in accumulator
      {"h2", _, [topic]}, {_, topic_maps} -> {topic, topic_maps}
      # New value in topic, add appropriate topic_map to topic_maps in accumulator
      {"p", _, [data]}, {topic, topic_maps} -> {topic, [%{topic: topic, data: data} | topic_maps]}
      node, _ -> raise "Invalid state: unexpected node #{inspect(node)}"
    end)

  Enum.reverse(topic_maps)
end

With your input that returns something like

[
  %{data: "data-a", topic: "Topic 1"},
  %{data: "data-b", topic: "Topic 1"}, 
  %{data: "data-c", topic: "Topic 1"},
  %{data: "data-d", topic: "Topic 2"},
  ...
]