ld-json-extractor 0.1.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,81 @@
1
+ Metadata-Version: 2.3
2
+ Name: ld-json-extractor
3
+ Version: 0.1.5
4
+ Summary: Extract ld+json from HTML
5
+ Author: Avazart
6
+ Requires-Dist: selectolax>=0.4.11
7
+ Requires-Python: >=3.12
8
+ Description-Content-Type: text/markdown
9
+
10
+ # av-ld_json_extractor
11
+
12
+ A lightweight Python library designed to extract ld+json from `<script>` tags within HTML documents
13
+
14
+ ## Installation
15
+
16
+ Using [`uv`](https://github.com/astral-sh/uv):
17
+
18
+ ```bash
19
+ uv add av-ld_json_extractor
20
+ ```
21
+
22
+ ### Quick Start
23
+
24
+ #### 1. Extract JSON-LD Data from HTML
25
+
26
+ ```python
27
+ from selectolax.lexbor import LexborHTMLParser
28
+ from av_ld_json_extractor import ld_json_iter
29
+
30
+ html_content = """
31
+ <!DOCTYPE html>
32
+ <html>
33
+ <head>
34
+ <script type="application/ld+json">
35
+ {"@context": "[https://schema.org](https://schema.org)", "@type": "Organization", "name": "Example Corp"}
36
+ </script>
37
+ <script type="application/ld+json">
38
+ {"@type": "Product", "name": "Gaming Laptop", "price": 1200}
39
+ </script>
40
+ </head>
41
+ </html>
42
+ """
43
+
44
+ parser = LexborHTMLParser(html_content)
45
+
46
+ for data in ld_json_iter(parser):
47
+ print(data)
48
+ ```
49
+
50
+ ```
51
+ # Output:
52
+ # {'@context': '[https://schema.org](https://schema.org)', '@type': 'Organization', 'name': 'Example Corp'}
53
+ # {'@type': 'Product', 'name': 'Gaming Laptop', 'price': 1200}
54
+ ```
55
+
56
+ #### 2. Find Specific @type (Objects & Lists)
57
+
58
+ ```python
59
+ from selectolax.lexbor import LexborHTMLParser
60
+ from av_ld_json_extractor import find_ld_json
61
+
62
+ html_content = """
63
+ <script type="application/ld+json">
64
+ [
65
+ {"@type": "BreadcrumbList", "itemListElement": []},
66
+ {"@type": "Product", "name": "Wireless Mouse", "price": 25}
67
+ ]
68
+ </script>
69
+ """
70
+
71
+ parser = LexborHTMLParser(html_content)
72
+
73
+ # Automatically searches inside both single JSON objects and array lists
74
+ product = find_ld_json("Product", parser)
75
+ print(product)
76
+ ```
77
+
78
+ ```
79
+ # Output:
80
+ # {'@type': 'Product', 'name': 'Wireless Mouse', 'price': 25}
81
+ ```
@@ -0,0 +1,72 @@
1
+ # av-ld_json_extractor
2
+
3
+ A lightweight Python library designed to extract ld+json from `<script>` tags within HTML documents
4
+
5
+ ## Installation
6
+
7
+ Using [`uv`](https://github.com/astral-sh/uv):
8
+
9
+ ```bash
10
+ uv add av-ld_json_extractor
11
+ ```
12
+
13
+ ### Quick Start
14
+
15
+ #### 1. Extract JSON-LD Data from HTML
16
+
17
+ ```python
18
+ from selectolax.lexbor import LexborHTMLParser
19
+ from av_ld_json_extractor import ld_json_iter
20
+
21
+ html_content = """
22
+ <!DOCTYPE html>
23
+ <html>
24
+ <head>
25
+ <script type="application/ld+json">
26
+ {"@context": "[https://schema.org](https://schema.org)", "@type": "Organization", "name": "Example Corp"}
27
+ </script>
28
+ <script type="application/ld+json">
29
+ {"@type": "Product", "name": "Gaming Laptop", "price": 1200}
30
+ </script>
31
+ </head>
32
+ </html>
33
+ """
34
+
35
+ parser = LexborHTMLParser(html_content)
36
+
37
+ for data in ld_json_iter(parser):
38
+ print(data)
39
+ ```
40
+
41
+ ```
42
+ # Output:
43
+ # {'@context': '[https://schema.org](https://schema.org)', '@type': 'Organization', 'name': 'Example Corp'}
44
+ # {'@type': 'Product', 'name': 'Gaming Laptop', 'price': 1200}
45
+ ```
46
+
47
+ #### 2. Find Specific @type (Objects & Lists)
48
+
49
+ ```python
50
+ from selectolax.lexbor import LexborHTMLParser
51
+ from av_ld_json_extractor import find_ld_json
52
+
53
+ html_content = """
54
+ <script type="application/ld+json">
55
+ [
56
+ {"@type": "BreadcrumbList", "itemListElement": []},
57
+ {"@type": "Product", "name": "Wireless Mouse", "price": 25}
58
+ ]
59
+ </script>
60
+ """
61
+
62
+ parser = LexborHTMLParser(html_content)
63
+
64
+ # Automatically searches inside both single JSON objects and array lists
65
+ product = find_ld_json("Product", parser)
66
+ print(product)
67
+ ```
68
+
69
+ ```
70
+ # Output:
71
+ # {'@type': 'Product', 'name': 'Wireless Mouse', 'price': 25}
72
+ ```
@@ -0,0 +1,108 @@
1
+ [project]
2
+ name = "ld_json_extractor"
3
+ version = "0.1.5"
4
+ description = "Extract ld+json from HTML"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Avazart" }
8
+ ]
9
+ requires-python = ">=3.12"
10
+ dependencies = [
11
+ "selectolax>=0.4.11",
12
+ ]
13
+
14
+ [build-system]
15
+ requires = ["uv_build>=0.8.21,<0.9.0"]
16
+ build-backend = "uv_build"
17
+
18
+ [dependency-groups]
19
+ dev = [
20
+ "mypy>=2.3.1",
21
+ "pre-commit>=4.6.2",
22
+ "pytest>=9.1.1",
23
+ "ruff>=0.16.6",
24
+ "vulture>=2.16",
25
+ ]
26
+ [tool.ruff]
27
+ exclude = [
28
+ ".git",
29
+ "__pycache__",
30
+ ".pytest_cache",
31
+ ".mypy_cache",
32
+ ".ruff_cache",
33
+ "venv",
34
+ ".venv",
35
+ ".env",
36
+ ".idea",
37
+ ".vscode",
38
+ ]
39
+ line-length = 79
40
+ target-version = "py311"
41
+
42
+ [tool.ruff.format]
43
+ quote-style = "double"
44
+ skip-magic-trailing-comma = false
45
+
46
+ [tool.ruff.lint]
47
+ select = [
48
+ # pycodestyle
49
+ #"E",
50
+ # Pyflakes
51
+ "F",
52
+ # pyupgrade
53
+ "UP",
54
+ # flake8-bugbear
55
+ "B",
56
+ # flake8-simplify
57
+ #"SIM",
58
+ # isort
59
+ "I",
60
+ ]
61
+ ignore = []
62
+
63
+ [tool.ruff.lint.extend-per-file-ignores]
64
+ "__init__.py" = ["F401"]
65
+
66
+
67
+ [tool.mypy]
68
+ strict = false
69
+ exclude = [
70
+ "^venv/.*$",
71
+ "^migrations/.*$",
72
+ "^tests/.*$",
73
+ "^scripts/.*$",
74
+ "^research/.*$",
75
+ ]
76
+ plugins = []
77
+
78
+ #[[tool.mypy.overrides]]
79
+ # module = "aiogram.*,apscheduler.*,gspread.*,oauth2client.*"
80
+ # ignore_missing_imports = true
81
+
82
+ [tool.pytest.ini_options]
83
+ testpaths = [
84
+ "tests",
85
+ ]
86
+ python_files = "test_*.py"
87
+ pythonpath = ["."]
88
+ log_cli = true
89
+ log_cli_level = "DEBUG"
90
+
91
+
92
+ [tool.pylint.messages_control]
93
+ disable = [
94
+ "C0114",
95
+ "C0115",
96
+ "C0116",
97
+ "R0903",
98
+ "R0913",
99
+ "R0914",
100
+ "R0917",
101
+ ]
102
+ [tool.pylint.master]
103
+ ignore = [
104
+ ".venv",
105
+ "migrations",
106
+ "tests",
107
+ "scripts",
108
+ ]
@@ -0,0 +1 @@
1
+ from ._ld_json import find_ld_json, ld_json_iter
@@ -0,0 +1,48 @@
1
+ import json
2
+ import logging
3
+ from collections.abc import Iterator
4
+ from pathlib import Path
5
+
6
+ from selectolax.lexbor import LexborHTMLParser
7
+
8
+ logger = logging.getLogger(Path(__name__).parent.name)
9
+
10
+ def _fix_unescaped_newlines(content: str) -> str:
11
+ result: list[str] = []
12
+ in_string = False
13
+ escape = False
14
+
15
+ for ch in content:
16
+ if ch == '"' and not escape:
17
+ in_string = not in_string
18
+ if ch == "\n" and in_string:
19
+ result.append("\\n")
20
+ continue
21
+ result.append(ch)
22
+ escape = ch == "\\" and not escape
23
+
24
+ return "".join(result)
25
+
26
+
27
+ def ld_json_iter(parser: LexborHTMLParser) -> Iterator[dict | list]:
28
+ for script_el in parser.css("script[type='application/ld+json']"):
29
+ text = script_el.text()
30
+ try:
31
+ yield json.loads(text)
32
+ except json.JSONDecodeError:
33
+ try:
34
+ yield json.loads(_fix_unescaped_newlines(text))
35
+ except json.JSONDecodeError as e:
36
+ logger.debug("%s %s", type(e), e)
37
+ continue
38
+
39
+
40
+ def find_ld_json(type_: str, parser: LexborHTMLParser) -> dict | None:
41
+ for data in ld_json_iter(parser):
42
+ if isinstance(data, list):
43
+ for item in data:
44
+ if isinstance(item, dict) and item.get("@type") == type_:
45
+ return item
46
+ elif isinstance(data, dict) and data.get("@type") == type_:
47
+ return data
48
+ return None
File without changes