av-ld-json-extractor 0.1.0__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,82 @@
1
+ Metadata-Version: 2.3
2
+ Name: av-ld-json-extractor
3
+ Version: 0.1.0
4
+ Summary: Extract ld+json from HTML
5
+ Author: Avazart
6
+ Author-email: Avazart <avazart.fl@gmail.com>
7
+ Requires-Dist: selectolax>=0.4.11
8
+ Requires-Python: >=3.12
9
+ Description-Content-Type: text/markdown
10
+
11
+ # av-ld_json_extractor
12
+
13
+ A lightweight Python library designed to extract ld+json from `<script>` tags within HTML documents
14
+
15
+ ## Installation
16
+
17
+ Using [`uv`](https://github.com/astral-sh/uv):
18
+
19
+ ```bash
20
+ uv add av-ld_json_extractor
21
+ ```
22
+
23
+ ### Quick Start
24
+
25
+ #### 1. Extract JSON-LD Data from HTML
26
+
27
+ ```python
28
+ from selectolax.lexbor import LexborHTMLParser
29
+ from av_ld_json_extractor import ld_json_iter
30
+
31
+ html_content = """
32
+ <!DOCTYPE html>
33
+ <html>
34
+ <head>
35
+ <script type="application/ld+json">
36
+ {"@context": "[https://schema.org](https://schema.org)", "@type": "Organization", "name": "Example Corp"}
37
+ </script>
38
+ <script type="application/ld+json">
39
+ {"@type": "Product", "name": "Gaming Laptop", "price": 1200}
40
+ </script>
41
+ </head>
42
+ </html>
43
+ """
44
+
45
+ parser = LexborHTMLParser(html_content)
46
+
47
+ for data in ld_json_iter(parser):
48
+ print(data)
49
+ ```
50
+
51
+ ```
52
+ # Output:
53
+ # {'@context': '[https://schema.org](https://schema.org)', '@type': 'Organization', 'name': 'Example Corp'}
54
+ # {'@type': 'Product', 'name': 'Gaming Laptop', 'price': 1200}
55
+ ```
56
+
57
+ #### 2. Find Specific @type (Objects & Lists)
58
+
59
+ ```python
60
+ from selectolax.lexbor import LexborHTMLParser
61
+ from av_ld_json_extractor import find_ld_json
62
+
63
+ html_content = """
64
+ <script type="application/ld+json">
65
+ [
66
+ {"@type": "BreadcrumbList", "itemListElement": []},
67
+ {"@type": "Product", "name": "Wireless Mouse", "price": 25}
68
+ ]
69
+ </script>
70
+ """
71
+
72
+ parser = LexborHTMLParser(html_content)
73
+
74
+ # Automatically searches inside both single JSON objects and array lists
75
+ product = find_ld_json("Product", parser)
76
+ print(product)
77
+ ```
78
+
79
+ ```
80
+ # Output:
81
+ # {'@type': 'Product', 'name': 'Wireless Mouse', 'price': 25}
82
+ ```
@@ -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 = "av-ld-json-extractor"
3
+ version = "0.1.0"
4
+ description = "Extract ld+json from HTML"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Avazart", email = "avazart.fl@gmail.com" }
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,44 @@
1
+ import json
2
+ from collections.abc import Iterator
3
+
4
+ from selectolax.lexbor import LexborHTMLParser
5
+
6
+
7
+ def _fix_unescaped_newlines(content: str) -> str:
8
+ result: list[str] = []
9
+ in_string = False
10
+ escape = False
11
+
12
+ for ch in content:
13
+ if ch == '"' and not escape:
14
+ in_string = not in_string
15
+ if ch == "\n" and in_string:
16
+ result.append("\\n")
17
+ continue
18
+ result.append(ch)
19
+ escape = ch == "\\" and not escape
20
+
21
+ return "".join(result)
22
+
23
+
24
+ def ld_json_iter(parser: LexborHTMLParser) -> Iterator[dict | list]:
25
+ for script_el in parser.css("script[type='application/ld+json']"):
26
+ text = script_el.text()
27
+ try:
28
+ yield json.loads(text)
29
+ except json.JSONDecodeError:
30
+ try:
31
+ yield json.loads(_fix_unescaped_newlines(text))
32
+ except json.JSONDecodeError:
33
+ continue
34
+
35
+
36
+ def find_ld_json(type_: str, parser: LexborHTMLParser) -> dict | None:
37
+ for data in ld_json_iter(parser):
38
+ if isinstance(data, list):
39
+ for item in data:
40
+ if isinstance(item, dict) and item.get("@type") == type_:
41
+ return item
42
+ elif isinstance(data, dict) and data.get("@type") == type_:
43
+ return data
44
+ return None