From opengraph¶
opengraph (the opengraph_py3 Python 3 fork of erikriver’s
opengraph) reads a page’s Open Graph card. OpenGraph(html=...) builds a BeautifulSoup tree over html5lib, scans
the head for og:-prefixed <meta> tags, and returns a dict subclass keyed by the property name minus its
og: prefix, with is_valid() reporting whether the required tags are present. OpenGraph(url=...) fetches the
page first; a scrape=True mode falls back to the <title> and body <img> when the og tags are missing.
It is a small, single-purpose scraping helper for lifting share-card metadata off a page. turbohtml serves that same
shape from turbohtml.extract.opengraph(), a string entry point over turbohtml.Document.opengraph(): the
og: <meta> tags are gathered in one C walk of the already parsed WHATWG tree, and the result is a frozen, fully
typed OpenGraph mapping with the same prefix-stripped keys and the same is_valid check.
turbohtml vs opengraph¶
Dimension |
turbohtml |
opengraph |
|---|---|---|
Scope |
Full WHATWG parser; Open Graph extraction is one feature of many |
Single-purpose Open Graph card reader |
Feature breadth |
|
|
Performance |
One C walk of the parsed tree; 94-133x faster on a social card |
BeautifulSoup tree over html5lib, scanned in Python |
Typing |
Frozen, fully typed read-only |
Plain |
Dependencies |
Zero runtime deps (self-contained C extension) |
BeautifulSoup and html5lib, plus an HTTP client for |
Maintenance |
Actively developed single extension |
Small community fork, low cadence |
Feature overlap¶
The shared surface you can port one-to-one:
OpenGraph(html=html)->turbohtml.extract.opengraph(), one call returning theog:card.og["title"]/og.get("title")-> the same prefix-stripped keys onOpenGraph;og:titlereads asog["title"].og.is_valid()->turbohtml.extract.OpenGraph.is_valid(), the four-property presence check."title" in og, iteration, and equality against a plaindictall work, sinceOpenGraphis a fullMapping.
What turbohtml adds¶
The
twitter:card, whichopengraphnever reads:turbohtml.Document.opengraph()returns theog:andtwitter:tags together (with prefixes kept) off the same walk.Every other structured-data format on the same tree:
json_ld(),microdata(), andstructured_data()for the whole set at once.A read-only mapping that holds no reference back into the tree, so it outlives the document it came from.
One C walk under the per-tree critical section, 94-133x faster than the BeautifulSoup scan.
Zero third-party runtime dependencies: no BeautifulSoup, no html5lib to install or pin.
Full type coverage:
OpenGraphis annotated and shipped withpy.typed.
What opengraph has that turbohtml does not¶
URL fetching (
OpenGraph(url=...)): no equivalent. turbohtml does not fetch; run your own HTTP client and pass the response body toopengraph().Scrape fallback (
scrape=True, which falls back to<title>and body<img>when the og tags are missing): no equivalent. Select those elements yourself withturbohtml.Node.find()when the card is incomplete.``to_json()`` / ``to_html()`` serializers: no equivalent. Build them from
dict(og)yourself withjsonor your own markup.
Performance¶
Both libraries start from the raw HTML string, so each parses before it reads the tags: opengraph builds a
BeautifulSoup tree over html5lib and scans the head in Python, where opengraph() parses to the
WHATWG tree and gathers the og: tags in one C walk. On a social-card head, and on an 8 KiB article carrying that
head, the walk runs 94 to 133 times faster:
social-card extraction |
turbohtml |
opengraph |
|---|---|---|
head |
1.9 µs |
192 µs (101x) |
article 8 KiB |
25.3 µs |
4.14 ms (164x) |
Across hand-built cards covering the protocol’s basic, structured-image, and required-tag shapes, the two libraries return byte-identical mappings.
How to migrate¶
Swap the import and the constructor for a single function call on the HTML you already have.
turbohtml |
|
|---|---|
|
|
|
|
|
the same keys on |
|
|
|
build these from |
Before, with opengraph, the constructor parses and the dict subclass carries the prefix-stripped keys:
from opengraph import OpenGraph
og = OpenGraph(
html="<head>"
'<meta property="og:title" content="The Rock">'
'<meta property="og:type" content="video.movie">'
'<meta property="og:image" content="https://x/rock.jpg">'
'<meta property="og:url" content="https://x/tt0117500/">'
'<meta name="twitter:card" content="summary">'
"</head>"
)
print(og["title"])
print(dict(og))
print(og.is_valid())
After, opengraph() returns the same shape from one C walk, as a read-only mapping that keeps no
reference into the tree:
from turbohtml.extract import opengraph
og = opengraph(
"<head>"
'<meta property="og:title" content="The Rock">'
'<meta property="og:type" content="video.movie">'
'<meta property="og:image" content="https://x/rock.jpg">'
'<meta property="og:url" content="https://x/tt0117500/">'
'<meta name="twitter:card" content="summary">'
"</head>"
)
print(og["title"])
print(dict(og))
print(og.is_valid())
The Rock
{'title': 'The Rock', 'type': 'video.movie', 'image': 'https://x/rock.jpg', 'url': 'https://x/tt0117500/'}
True
turbohtml does not fetch URLs; OpenGraph(url=...) becomes your HTTP client plus opengraph()
on the response body. A card missing a required property reads back fine but fails the validity check:
og = opengraph('<head><meta property="og:title" content="Only a title"></head>')
print(og.get("title"), og.is_valid())
Only a title False
Gotchas and pitfalls¶
Keys drop the
og:prefix (og["title"], notog["og:title"]), matchingopengraphand diverging from the prefixed keysturbohtml.Document.opengraph()returns. Structured sub-properties keep their tail, soog:image:widthreads asog["image:width"].opengraph()drops thetwitter:tags thatturbohtml.Document.opengraph()also returns, becauseopengraphonly readsog:-prefixed properties. Callopengraph()when you want the Twitter card too.is_valid()requires the Open Graph protocol’s four basic properties (og:title,og:type,og:image,og:url). Theopengraph_py3fork additionally requiresog:description, so a card with the four but no description is valid here and invalid there.The mapping is read-only.
opengraphreturns a mutabledictsubclass you can assign into;OpenGraphsupports only the read surface, so copy intodict(og)first if you need to edit.turbohtml takes an already-decoded
strand applies the WHATWG encoding rules;opengraphinurl=mode decodes the fetched bytes itself. Decode the response body tostrbefore handing it over rather than passing raw bytes.