Nodes¶
A parsed tree is made of nodes. Node carries the navigation, query, mutation, and serialization surface every
node shares; the concrete types below add their own data. Text is a real Text child node (the WHATWG DOM
shape), so there is no text/tail split.
- class turbohtml.Node¶
Common navigation shared by every node in a parsed tree. Text appears as real child nodes (the WHATWG DOM shape), so there is no text/tail split.
- article() Article¶
Return an Article record for the dominant content under this node: the scored content body (element), its layout-aware plain text (text, as main_text()), and the page metadata harvested from the document – title, byline, date, description, lang, canonical, site_name, tags and image. element is None and text is empty when nothing reads as content; each single-valued metadata field is None when absent and tags is an empty tuple. Title comes from <h1>, then og:title, then <title>; byline from a rel=author link, then a meta author, then article:author; date from <time>, then article:published_time, then a common date meta; description from og:description, then a meta description; lang from <html lang>; canonical from <link rel=canonical>, then og:url; site_name from og:site_name, then a meta application-name; tags from every <meta name=keywords> (comma-split) and article:tag; image from og:image, then twitter:image. Pure C.
- closest(selector: str, /) Element | None¶
Find the nearest Element matching a CSS selector, testing this node then each ancestor.
- Parameters:
selector – the CSS selector.
- Returns:
the nearest matching Element, or None.
- Raises:
ValueError – the selector is not valid CSS; the message names the reason and the source offset.
- encode(encoding: str = 'utf-8', options: Html | None = None) bytes¶
Serialize this node and its subtree to bytes, with the same formatting controls as serialize().
- Parameters:
encoding – the codec to encode the markup with.
options – an Html configuration object, or None for the defaults.
- Returns:
the serialized markup encoded as bytes.
- Raises:
TypeError – if options is not an Html configuration object.
LookupError – if encoding names a codec Python does not know.
UnicodeEncodeError – if the markup has characters the encoding cannot represent.
- equals(other: Node, /) bool¶
Test whether this node and other are structurally equal: the same node type, and for an element the same tag (namespace-aware) and attributes (names and values, order-independent per the DOM) with the same children compared in order; for a Text/Comment/other leaf the same data. The two nodes may come from different documents. This is the BeautifulSoup notion of tree equality.
Distinct from
==, which is node identity: two separate parses of the same markup are==-unequal butequals()-equal.- Parameters:
other – the node to compare against.
- Returns:
whether the two subtrees are structurally equal.
- Raises:
TypeError – if other is not a node.
- extract() Node¶
Detach this node from its parent, leaving a standalone node the caller can reinsert elsewhere.
- Returns:
this node, detached.
- find(tag: _Filter | None = None, /, *, axis: Axis = ..., attrs: Mapping[str, _Filter] | None = ..., class_: _Filter | None = ..., text: _Filter | None = ..., **filters: _Filter) Element | None¶
Find the first Element along axis matching the tag filter and every attribute filter. A filter is a str, bool, compiled regex, callable, or a list of those.
- Parameters:
tag – filter on the tag name.
axis – which nodes to walk relative to this one.
attrs – a mapping of attribute name to filter.
class_ – filter on a token of the class attribute.
text – match the element’s collected text (an exact str, a regex search, or a callable predicate); filter a literal text attribute through attrs={‘text’: …}.
filters – further attribute filters given as keyword arguments.
- Returns:
the first matching Element, or None.
- Raises:
TypeError – if axis is not an Axis, or a filter is not a str, bool, regex, callable, or a list of those.
- find_all(tag: _Filter | None = None, /, *, axis: Axis = ..., attrs: Mapping[str, _Filter] | None = ..., class_: _Filter | None = ..., text: _Filter | None = ..., limit: int | None = ..., **filters: _Filter) list[Element]¶
Find every Element along axis matching the tag filter and every attribute filter, with the same filter forms as find().
- Parameters:
tag – filter on the tag name.
axis – which nodes to walk relative to this one.
attrs – a mapping of attribute name to filter.
class_ – filter on a token of the class attribute.
text – match each element’s collected text (an exact str, a regex search, or a callable predicate).
limit – stop after this many matches; None collects them all.
filters – further attribute filters given as keyword arguments.
- Returns:
the matching Elements in document order.
- Raises:
TypeError – if axis is not an Axis, limit is not an int or None, or a filter is not a str, bool, regex, callable, or a list of those.
ValueError – if limit is negative.
- following: Iterator[Node]¶
an iterator over nodes after this one in document order, excluding its descendants
- insert_after(*nodes: Node) None¶
Insert each node into this node’s parent right after this node, in order, with the same move-or-adopt rule as insert_before().
- Parameters:
nodes – the nodes to insert.
- Raises:
TypeError – if an argument is not a node, or is a Document.
ValueError – if this node has no parent, or a node is an ancestor of the insertion point (which would form a cycle).
- insert_before(*nodes: Node) None¶
Insert each node into this node’s parent right before this node, in order. A node already in a tree is moved; a node from another tree is adopted by copy.
- Parameters:
nodes – the nodes to insert.
- Raises:
TypeError – if an argument is not a node, or is a Document.
ValueError – if this node has no parent, or a node is an ancestor of the insertion point (which would form a cycle).
- links() list[Link]¶
Find every link in this node and its subtree. Beyond <a href>, this finds the URLs hidden in srcset/ping/archive lists, a <meta http-equiv=refresh> redirect, and CSS url()/@import in a style attribute or a <style> sheet.
- Returns:
the Link records in document order.
- main_content() Element | None¶
Find the dominant content element under this node, the article body with navigation, sidebars, ads, comments and other boilerplate scored out. Scores the tree by content density (text length, comma count, tag and class/id weight, discounted by link density), the readability heuristic, in C.
- Returns:
the winning content Element, or None when nothing reads as content.
- main_text() str¶
Render the main content under this node as layout-aware plain text, as to_text() renders main_content().
- Returns:
the main content’s text, or an empty string when there is none.
- matches(selector: str, /) bool¶
Test this node against a CSS selector, evaluated with its own ancestors and siblings as context.
- Parameters:
selector – the CSS selector.
- Returns:
whether this node is an Element that matches.
- Raises:
ValueError – the selector is not valid CSS; the message names the reason and the source offset.
- position: tuple[int, int] | None¶
the (source_line, source_col) of this element’s start tag, or None if unavailable
- preceding: Iterator[Node]¶
an iterator over nodes before this one in document order, nearest first, excluding its ancestors
- prune(selector: str, /) Node¶
Keep only the descendants matching a CSS selector, together with their ancestors up to this node and the whole subtree under each match, and remove every other descendant in place. With no match the subtree is emptied. This trims a parsed document to the parts of interest after a normal WHATWG parse, the way BeautifulSoup’s SoupStrainer filters a document while parsing it.
- Parameters:
selector – the CSS selector the kept descendants must match.
- Returns:
this node.
- Raises:
ValueError – the selector is not valid CSS; the message names the reason and the source offset.
- re(pattern: str | Pattern[str], /, *, attr: str | None = None) list[str]¶
Run a regex over this node’s text. Each match yields its one capturing group when the pattern has exactly one, otherwise the whole match.
- Parameters:
pattern – a str or compiled re.Pattern to search for.
attr – search this attribute’s value instead of the node text; an absent attribute yields [].
- Returns:
every match as a list of str.
- re_first(pattern: str | Pattern[str], /, default: str | None = None, *, attr: str | None = None) str | None¶
Run a regex over this node’s text and return the first match, with the same group rule as re().
- Parameters:
pattern – a str or compiled re.Pattern to search for.
default – value returned when nothing matches.
attr – search this attribute’s value instead of the node text.
- Returns:
the first match as a str, or default when nothing matches.
- remove(selector: str, /) Node¶
Drop every descendant Element matching the CSS selector, each with its whole subtree, and return this node. The bulk inverse of prune (which keeps the matches): the destructive counterpart of selectolax’s strip_tags and w3lib’s remove_tags_with_content, and of jQuery’s .remove().
- Parameters:
selector – the CSS selector the dropped descendants must match.
- Returns:
this node.
- Raises:
ValueError – the selector is not valid CSS; the message names the reason and the source offset.
- replace_with(*nodes: Node) None¶
Put nodes where this node is, in order, and detach this node, which becomes a standalone root the caller still holds. With no nodes this just removes this node.
- Parameters:
nodes – the nodes to put in this node’s place.
- Raises:
TypeError – if an argument is not a node, or is a Document.
ValueError – if this node has no parent, or a node is an ancestor of this node (which would form a cycle).
- resolve_links(base_url: str, /) None¶
Rewrite every link in this node and its subtree to an absolute URL, in place, using stdlib urllib.parse.urljoin.
- Parameters:
base_url – the base each relative URL is resolved against.
- rewrite_links(replace: Callable[[str], str | None], /) None¶
Rewrite every link in this node and its subtree in place.
- Parameters:
replace – called with each URL; return a str to substitute it or None to leave it unchanged.
- select(selector: str, /) list[Element]¶
Find the descendant Elements matching a CSS selector. The grammar covers type, #id, .class, and attribute selectors, the four combinators, the structural pseudo-classes (including :nth-child(An+B of S)), the :is(), :where(), :has(), and :not() functional pseudo-classes, and the :scope, form/UI, :lang() and :dir() pseudo-classes a static tree can determine; live-state pseudo-classes (:hover, :focus, …) match nothing. :is() and :where() take a forgiving list, so a bad arm is dropped.
- Parameters:
selector – the CSS selector.
- Returns:
the matching descendant Elements in document order.
- Raises:
ValueError – the selector is not valid CSS; the message names the reason and the source offset.
- select_one(selector: str, /) Element | None¶
Find the first descendant Element matching a CSS selector.
- Parameters:
selector – the CSS selector.
- Returns:
the first matching Element, or None.
- Raises:
ValueError – the selector is not valid CSS; the message names the reason and the source offset.
- serialize(options: Html | None = None) str¶
Serialize this node and its subtree to a str.
- Parameters:
options – an Html configuration object (formatter, layout, attribute ordering, and meta-charset handling), or None for the defaults.
- Returns:
the serialized markup.
- Raises:
TypeError – if options is not an Html configuration object.
- serialize_iter(options: Html | None = None) Iterator[str]¶
Serialize this node and its subtree lazily, yielding the markup in bounded str chunks so a large document can stream to a socket or file without a full-size output string.
''.join(node.serialize_iter(options))equalsnode.serialize(options)for every options the stream supports.The tree must not be mutated while the iterator is live, the same rule as the other node iterators.
- Parameters:
options – an Html configuration object, or None for the defaults. A Minify layout is rejected: minification needs the whole tree at once.
- Returns:
an iterator of str chunks whose concatenation is the markup.
- Raises:
TypeError – if options is not an Html configuration object.
ValueError – if options selects a Minify layout, which cannot stream.
- source_col: int | None¶
the 0-based source column of this element’s start tag, or None if unavailable
- source_line: int | None¶
the 1-based source line of this element’s start tag, or None if unavailable
- strip_tags(selector: str, /) Node¶
Unwrap every descendant Element matching the CSS selector, replacing each match with its children in place while keeping that content, and return this node. The bulk form of unwrap, matching selectolax’s unwrap_tags, w3lib’s remove_tags, and jQuery’s .unwrap().
- Parameters:
selector – the CSS selector the unwrapped descendants must match.
- Returns:
this node.
- Raises:
ValueError – the selector is not valid CSS; the message names the reason and the source offset.
- tables() list[list[list[str]]]¶
Return every table in this node and its subtree, in document order, each as the list of rows that Element.rows() produces. A nested table appears as its own entry. The result is a list[list[list[str]]] of plain strings, with no pandas dependency; pass one table to pandas.DataFrame for a frame.
- to_annotated_text(annotation_rules: Mapping[str, Sequence[str]], options: PlainText | None = None) tuple[str, list[tuple[int, int, str]]]¶
Render layout-aware text and, for every element matching a rule in annotation_rules, record a labeled span over its text. Spans inside table cells are not recorded.
- Parameters:
annotation_rules – maps a selector (‘tag’, ‘tag#attr’, ‘tag#attr=value’, or ‘#attr’) to the list of labels to attach to each matching element.
options – a PlainText configuration object, or None for the defaults.
- Returns:
a (text, spans) pair, where spans is a list of (start, end, label).
- to_markdown(options: Markdown | None = None) str¶
Render this node and its subtree as Markdown. The defaults emit opinionated GitHub-Flavored Markdown.
- Parameters:
options – a Markdown configuration object, or None for the defaults. Its grouped knobs (headings, links, tables, …) cover the markdownify and html2text configuration surface.
- Returns:
the Markdown rendering of this node’s subtree.
- to_text(options: PlainText | None = None) str¶
Render this node and its subtree as layout-aware plain text: blocks separated by blank lines, lists indented under their bullets, and tables laid out as a column-aligned grid. The inscriptis role, in C.
- Parameters:
options – a PlainText configuration object, or None for the defaults.
- Returns:
the plain-text rendering of this node’s subtree.
- unwrap() Node¶
Replace this node with its children, the inverse of wrap().
- Returns:
this node, detached.
- Raises:
ValueError – if this node has no parent.
- wrap(wrapper: Element, /) Element¶
Put this node inside wrapper, in this node’s place.
- Parameters:
wrapper – the element to wrap this node in.
- Returns:
wrapper, now holding this node.
- Raises:
TypeError – if wrapper is not an element.
- wrap_siblings(wrapper: Element, /, *, until: Node | None = None) Element¶
Wrap this node and the siblings that follow it in wrapper in one move; the bulk form of wrap() for a contiguous run. wrapper lands where this node was.
- Parameters:
wrapper – the element to wrap the run in.
until – the last sibling to include (this node or a later one); None reaches to the last sibling.
- Returns:
wrapper, now holding the run.
- Raises:
TypeError – if wrapper is not an element, or until is not a node.
ValueError – if this node has no parent, or until is not this node or a following sibling.
- xpath(expression: str, /, *, namespaces: dict[str, str] | None = ..., smart_strings: bool = ..., extensions: dict[tuple[str | None, str], Callable[..., str | float | bool | Element | Iterable[Element]]] | None = ..., **variables: str | float | bool | Element | Iterable[Element]) list[Element | str]¶
Evaluate an XPath expression relative to this node. A node-set returns a list of Elements (with attribute/text values as str) in document order; absolute paths start at the document root.
- Parameters:
expression – the XPath expression.
smart_strings – return each string result as a value that remembers the Element it came from.
extensions – maps an (namespace, name) pair to a callable, registering a custom XPath function; the callable may return a scalar, an Element, or an iterable of Elements (a node-set that feeds later steps).
variables – values bound to the $name variables used in the expression; a str, int, float, or bool binds a scalar, and an Element or an iterable of Elements binds a node-set. A node from a different document raises ValueError.
- Returns:
the result list, of Elements and str values in document order.
- Raises:
TypeError – expression is not a str, a variable binding is of an unsupported type, or a value is used where the grammar requires a node-set.
ValueError – the expression is not valid XPath (with the offending token and its offset), nests past the depth limit, calls an unknown function or one with the wrong number of arguments, references an unbound variable or prefix, or binds a node from a different document.
- xpath_iter(expression: str, /, *, namespaces: dict[str, str] | None = ..., smart_strings: bool = ..., extensions: dict[tuple[str | None, str], Callable[..., str | float | bool | Element | Iterable[Element]]] | None = ..., **variables: str | float | bool | Element | Iterable[Element]) Iterator[Element | str]¶
Like xpath(), but stream the results instead of building a list.
- Parameters:
expression – the XPath expression.
smart_strings – return each string result as a value that remembers the Element it came from.
extensions – maps an (namespace, name) pair to a custom XPath function.
variables – values bound to the $name variables in the expression.
- Returns:
an iterator over the results in document order.
- Raises:
TypeError – expression is not a str, a variable binding is of an unsupported type, or a value is used where a node-set is required.
ValueError – the expression is invalid XPath, nests too deeply, calls an unknown or wrong-arity function, or references an unbound variable or prefix.
- xpath_one(expression: str, /, *, namespaces: dict[str, str] | None = ..., smart_strings: bool = ..., extensions: dict[tuple[str | None, str], Callable[..., str | float | bool | Element | Iterable[Element]]] | None = ..., **variables: str | float | bool | Element | Iterable[Element]) Element | str | None¶
Like xpath(), but return only the first result.
- Parameters:
expression – the XPath expression.
smart_strings – return a string result as a value that remembers the Element it came from.
extensions – maps an (namespace, name) pair to a custom XPath function.
variables – values bound to the $name variables in the expression.
- Returns:
the first result in document order, or None when there is none.
- Raises:
TypeError – expression is not a str, a variable binding is of an unsupported type, or a value is used where a node-set is required.
ValueError – the expression is invalid XPath, nests too deeply, calls an unknown or wrong-arity function, or references an unbound variable or prefix.
- class turbohtml.Element(tag: str, attrs: Mapping[str, str | list[str] | None] | None = None, children: Iterable[Node] | None = None)¶
An element node: a tag, a namespace, attributes, and child nodes.
- Parameters:
tag – the tag name.
attrs – initial attributes; a list value sets a token-list attribute and None a valueless one.
children – initial child nodes, appended in order.
- Raises:
TypeError – if tag or an attribute name is not a str, an attribute value is not a str, a list of str, or None, or a child is not a node.
ValueError – if the tag or an attribute name carries a character HTML forbids there, or if children are given for a void element.
- add_class(name: str, /) Element¶
Add name to this element’s class tokens when absent and return the element. Existing tokens keep their order; on a change the class value is rewritten with single-space separators.
- Raises:
TypeError – if name is not a str.
ValueError – if name is empty or contains whitespace.
- append(child: Node, /) None¶
Add child as the last child of this element. A node already in a tree is moved; a node from another tree is adopted by copy.
- Parameters:
child – the node to append.
- Raises:
TypeError – if child is not a node, or is a Document.
ValueError – if child is an ancestor of this element (which would form a cycle).
- attr(name: str, /, default: str | None = None) str | None¶
Read one attribute as a single str. The raw value is returned, so a token-list attribute like class reads back as “a b c” rather than a list, and a valueless attribute reads back as the empty string.
- Parameters:
name – the attribute name.
default – value returned when the attribute is absent.
- Returns:
the attribute value, or default when it is absent.
- attrs: MutableMapping[str, str | list[str] | None]¶
the live mutable attribute mapping; token-list attributes (class, rel, …) map to a list[str], a valueless attribute maps to None
- checked: bool¶
whether a checkbox or radio input is checked. Assigning requires a checkbox or radio; setting a radio to True clears the other same-name radios in the owning form (or document), the radio-group exclusivity rule.
- css_path() str¶
Return a CSS selector that uniquely locates this element from the document root, the way browser devtools “copy selector” does. The path is anchored at the nearest ancestor (or the element itself) carrying a document-unique id (“#main > …”), otherwise it descends from the root with positional :nth-of-type() steps (“html > body > div > p:nth-of-type(3)”). Feeding the result back to select() on the document returns exactly this element.
- extend(children: Iterable[Node], /) None¶
Append every node from the iterable in order, each one moved or adopted like append().
- Parameters:
children – the nodes to append.
- Raises:
TypeError – if children is not iterable, or a member is not a node or is a Document.
ValueError – if a member is an ancestor of this element (which would form a cycle).
- field_value: str | list[str] | None¶
the form control’s value, with form semantics. Reading returns the value attribute (defaulting to “on” for a checkbox/radio), a textarea’s text, an option’s value (its stripped text when it has no value attribute), or the selected option value(s) of a select (a list[str] when it is multiple, None when nothing is selected); non-controls read None. Assigning a str writes the value (selecting the matching option of a select), a list[str] selects a multiple select, and None clears it. The checked state lives in Element.checked, not here.
- form_data() list[tuple[str, str]]¶
Collect this form’s successful controls, following the WHATWG form-submission entry-list rules. Controls without a non-empty name, disabled controls (their own disabled or a disabled ancestor fieldset), buttons, and file/submit/reset/image inputs are skipped; a checkbox or radio contributes only when checked, a select one pair per selected non-disabled option (the default first option only when its display size is 1). Controls inside a template’s contents have no form owner and are excluded. Controls are matched by containment in the form.
- Returns:
the (name, value) pairs in document order.
- has_class(name: str, /) bool¶
Return whether name is one of this element’s space-separated class tokens.
- insert(index: int, child: Node, /) None¶
Insert child among this element’s children, counted and clamped like list.insert.
- Parameters:
index – position among the existing children.
child – the node to insert.
- Raises:
TypeError – if index is not an int, or child is not a node or is a Document.
ValueError – if child is an ancestor of this element (which would form a cycle).
- insert_adjacent_html(position: str, html: str, /) None¶
Parse html as a fragment and insert it relative to this element at position, one of ‘beforebegin’, ‘afterbegin’, ‘beforeend’, or ‘afterend’ (the DOM insertAdjacentHTML, matched case-insensitively). ‘beforebegin’ and ‘afterend’ place the nodes among this element’s siblings, so they require an element parent; ‘afterbegin’ and ‘beforeend’ add them as the first or last children. The fragment parses in the context of the element that will hold it.
- Raises:
TypeError – if position or html is not a str.
ValueError – if position is not one of the four keywords, or a sibling-relative position is used on a node without an element parent.
- normalize() None¶
Merge each run of adjacent Text descendants into one node and drop empty Text nodes, throughout this element’s subtree.
- records() list[dict[str, str]]¶
Return the table’s data rows as a list of dicts, keyed by the first row (the header, typically the thead row) over each later row, with rowspan and colspan resolved as in rows(). A table with no rows or only a header yields an empty list; a duplicated header keeps the rightmost column’s value. Pass the result to pandas.DataFrame for a frame. Raises TypeError on a non-table element.
- remove_class(name: str, /) Element¶
Remove every occurrence of name from this element’s class tokens and return the element. Removing the last token leaves an empty class attribute.
- Raises:
TypeError – if name is not a str.
ValueError – if name is empty or contains whitespace.
- rows() list[list[str]]¶
Return the table’s cells as a list of rows, each a list[str], with rowspan and colspan resolved by filling every spanned slot with a copy of the cell text. Rows are padded to a rectangular width; a nested table’s rows belong to that table, not this one. Cell text is the cell’s text content with surrounding whitespace stripped. Raises TypeError on a non-table element.
- set_inner_html(html: str, /) None¶
Replace this element’s children with the nodes parsed from html, a fragment parsed in this element’s own context (the DOM innerHTML= setter). The string is run through the same HTML parser as parse(), so malformed markup is repaired the same way.
- Raises:
TypeError – if html is not a str.
- set_text(text: str, /) None¶
Replace this element’s children with a single Text node holding text verbatim (the DOM textContent= setter). text is never parsed, so any markup in it is escaped on serialization. The Element.text= setter is equivalent.
- Raises:
TypeError – if text is not a str.
- toggle_class(name: str, /) Element¶
Remove name from this element’s class tokens when present, add it when absent, and return the element.
- Raises:
TypeError – if name is not a str.
ValueError – if name is empty or contains whitespace.
- wrap_children(wrapper: Element, /) Element¶
Move every child of this element into wrapper, make wrapper the sole child, and return it. The bulk form of wrap() for a container’s whole content; an empty element gains an empty wrapper.
- Parameters:
wrapper – the element to move the children into.
- Returns:
wrapper, now holding the moved children.
- Raises:
TypeError – if wrapper is not an element.
- xpath_path() str¶
Return the positional XPath that locates this element from the document root, like lxml’s getroottree().getpath(). Each step is the tag name with a 1-based [n] index among same-name siblings when more than one exists (“/html/body/div[2]/p[3]”). Feeding the result back to xpath() on the document returns exactly this element.
- class turbohtml.Namespace(*values)¶
The XML namespace an Element belongs to, as reported by Element.namespace.
HTML is the ordinary HTML namespace; SVG is inline <svg> content; MATHML is inline <math> content. Each member’s value is the namespace short name (“html”, “svg”, “math”).
- class turbohtml.Comment(data: str)¶
An HTML comment.
- Parameters:
data – the comment text, without the <!– –> delimiters.
- class turbohtml.CData(data: str)¶
A CDATA section.
- Parameters:
data – the section text, without the <![CDATA[ ]]> delimiters.
- class turbohtml.ProcessingInstruction(target: str, data: str)¶
A processing instruction.
- Parameters:
target – the instruction target (the name right after <?).
data – the instruction data (everything after the target).
- class turbohtml.Doctype¶
A document type declaration.
Node.links() yields one Link per link it finds.
- class turbohtml.Link(element: Element, attribute: str | None, url: str)¶
One link found in a document.
- Parameters:
Node.article() returns an Article record: the scored content body and the page metadata harvested beside
it.
- class turbohtml.Article(element: Element | None, text: str, title: str | None, byline: str | None, date: str | None, description: str | None, lang: str | None, canonical: str | None, site_name: str | None, tags: tuple[str, ...], image: str | None)¶
The dominant content of a document and the metadata harvested beside it.
elementis the scored content body (Nonewhen nothing reads as content) andtextits layout-aware plain text (empty then).title,byline,date,description,lang,canonical(the<link rel=canonical>URL orog:url),site_name(og:site_nameor<meta name=application-name>) andimage(theog:imageortwitter:imagelead image) are single-valued page metadata, each whitespace-normalized orNonewhen the source is absent.tagscollects every<meta name=keywords>value (comma-split) andarticle:tagin document order, an empty tuple when none appear. This makesarticle()a one-call replacement for trafilatura and newspaper3k.- Parameters: