crewai-webmetadata-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,6 @@
1
+ .venv/
2
+ dist/
3
+ build/
4
+ *.egg-info/
5
+ __pycache__/
6
+ .pytest_cache/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 JosejuX
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,81 @@
1
+ Metadata-Version: 2.5
2
+ Name: crewai-webmetadata-extractor
3
+ Version: 0.1.0
4
+ Summary: CrewAI tools for the Web Metadata, OpenGraph & Contact Extractor API — give your crew URL-to-structured-data extraction, AI-ready Markdown, contact discovery, and SEO auditing.
5
+ Project-URL: Homepage, https://github.com/JosejuX/rapidapi-metadata-extractor
6
+ Project-URL: RapidAPI Listing, https://rapidapi.com/josejuanjocoding/api/web-metadata-and-contact-extractor
7
+ Project-URL: PyPI SDK, https://pypi.org/project/webmetadata-extractor/
8
+ Author-email: Juanjo <josejuanjo.coding@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,crewai,crewai-tool,metadata-extractor,rag,seo,web-scraping
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Requires-Python: >=3.10
18
+ Requires-Dist: crewai>=0.80.0
19
+ Requires-Dist: pydantic>=2
20
+ Requires-Dist: webmetadata-extractor>=0.1.0
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=7.0; extra == 'dev'
23
+ Requires-Dist: responses>=0.23; extra == 'dev'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # crewai-webmetadata-extractor
27
+
28
+ CrewAI tools for the [Web Metadata, OpenGraph & Contact Extractor API](https://rapidapi.com/josejuanjocoding/api/web-metadata-and-contact-extractor) — give a crew the ability to turn any URL into structured web intelligence, clean Markdown for RAG, contact signals for lead-gen, or a graded SEO audit.
29
+
30
+ ```bash
31
+ pip install crewai-webmetadata-extractor
32
+ ```
33
+
34
+ ## Quick start
35
+
36
+ Get a free API key on [RapidAPI](https://rapidapi.com/josejuanjocoding/api/web-metadata-and-contact-extractor) (1,000 requests/month, no credit card required).
37
+
38
+ ```python
39
+ from crewai import Agent
40
+ from crewai_webmetadata_extractor import get_tools
41
+
42
+ tools = get_tools(api_key="YOUR_RAPIDAPI_KEY")
43
+ # or leave api_key out and set the WEBMETADATA_API_KEY environment variable instead
44
+
45
+ researcher = Agent(
46
+ role="Web Researcher",
47
+ goal="Extract structured intelligence from URLs",
48
+ tools=tools,
49
+ ...
50
+ )
51
+ ```
52
+
53
+ ## Tools included
54
+
55
+ | Tool | Use it when the agent needs to... |
56
+ |---|---|
57
+ | `WebMetadataExtractTool` | Get a broad, all-in-one picture of a page (SEO, contacts, tech stack, security, links) |
58
+ | `WebMarkdownTool` | Ingest a page's actual content into a RAG pipeline as clean Markdown |
59
+ | `WebContactsTool` | Find public emails/phones/social links for outreach or lead-gen workflows |
60
+ | `WebSEOAuditTool` | Grade a page's SEO with a score, warnings, and readability metrics |
61
+
62
+ Every tool returns a JSON string — API errors come back as `{"error": true, "status_code": ..., "detail": ...}` instead of raising, so a crew can react to them without crashing.
63
+
64
+ ## Configuration
65
+
66
+ Pass `api_key` explicitly per tool, or set it once via the `WEBMETADATA_API_KEY` environment variable and omit it everywhere:
67
+
68
+ ```bash
69
+ export WEBMETADATA_API_KEY=your-rapidapi-key
70
+ ```
71
+
72
+ ## Links
73
+
74
+ - [Python SDK this wraps](https://pypi.org/project/webmetadata-extractor/) (`webmetadata-extractor`)
75
+ - [Also available for LangChain](https://pypi.org/project/langchain-webmetadata-extractor/) (`langchain-webmetadata-extractor`)
76
+ - [Full API documentation](https://github.com/JosejuX/rapidapi-metadata-extractor)
77
+ - [Live interactive demo](https://rapidapi-metadata-extractor.onrender.com) — no signup needed
78
+
79
+ ## License
80
+
81
+ MIT
@@ -0,0 +1,56 @@
1
+ # crewai-webmetadata-extractor
2
+
3
+ CrewAI tools for the [Web Metadata, OpenGraph & Contact Extractor API](https://rapidapi.com/josejuanjocoding/api/web-metadata-and-contact-extractor) — give a crew the ability to turn any URL into structured web intelligence, clean Markdown for RAG, contact signals for lead-gen, or a graded SEO audit.
4
+
5
+ ```bash
6
+ pip install crewai-webmetadata-extractor
7
+ ```
8
+
9
+ ## Quick start
10
+
11
+ Get a free API key on [RapidAPI](https://rapidapi.com/josejuanjocoding/api/web-metadata-and-contact-extractor) (1,000 requests/month, no credit card required).
12
+
13
+ ```python
14
+ from crewai import Agent
15
+ from crewai_webmetadata_extractor import get_tools
16
+
17
+ tools = get_tools(api_key="YOUR_RAPIDAPI_KEY")
18
+ # or leave api_key out and set the WEBMETADATA_API_KEY environment variable instead
19
+
20
+ researcher = Agent(
21
+ role="Web Researcher",
22
+ goal="Extract structured intelligence from URLs",
23
+ tools=tools,
24
+ ...
25
+ )
26
+ ```
27
+
28
+ ## Tools included
29
+
30
+ | Tool | Use it when the agent needs to... |
31
+ |---|---|
32
+ | `WebMetadataExtractTool` | Get a broad, all-in-one picture of a page (SEO, contacts, tech stack, security, links) |
33
+ | `WebMarkdownTool` | Ingest a page's actual content into a RAG pipeline as clean Markdown |
34
+ | `WebContactsTool` | Find public emails/phones/social links for outreach or lead-gen workflows |
35
+ | `WebSEOAuditTool` | Grade a page's SEO with a score, warnings, and readability metrics |
36
+
37
+ Every tool returns a JSON string — API errors come back as `{"error": true, "status_code": ..., "detail": ...}` instead of raising, so a crew can react to them without crashing.
38
+
39
+ ## Configuration
40
+
41
+ Pass `api_key` explicitly per tool, or set it once via the `WEBMETADATA_API_KEY` environment variable and omit it everywhere:
42
+
43
+ ```bash
44
+ export WEBMETADATA_API_KEY=your-rapidapi-key
45
+ ```
46
+
47
+ ## Links
48
+
49
+ - [Python SDK this wraps](https://pypi.org/project/webmetadata-extractor/) (`webmetadata-extractor`)
50
+ - [Also available for LangChain](https://pypi.org/project/langchain-webmetadata-extractor/) (`langchain-webmetadata-extractor`)
51
+ - [Full API documentation](https://github.com/JosejuX/rapidapi-metadata-extractor)
52
+ - [Live interactive demo](https://rapidapi-metadata-extractor.onrender.com) — no signup needed
53
+
54
+ ## License
55
+
56
+ MIT
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "crewai-webmetadata-extractor"
7
+ version = "0.1.0"
8
+ description = "CrewAI tools for the Web Metadata, OpenGraph & Contact Extractor API — give your crew URL-to-structured-data extraction, AI-ready Markdown, contact discovery, and SEO auditing."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ authors = [{ name = "Juanjo", email = "josejuanjo.coding@gmail.com" }]
12
+ requires-python = ">=3.10"
13
+ keywords = ["crewai", "crewai-tool", "agent", "rag", "web-scraping", "seo", "metadata-extractor"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Topic :: Software Development :: Libraries :: Python Modules",
20
+ ]
21
+ dependencies = [
22
+ "webmetadata-extractor>=0.1.0",
23
+ "crewai>=0.80.0",
24
+ "pydantic>=2",
25
+ ]
26
+
27
+ [project.optional-dependencies]
28
+ dev = ["pytest>=7.0", "responses>=0.23"]
29
+
30
+ [project.urls]
31
+ Homepage = "https://github.com/JosejuX/rapidapi-metadata-extractor"
32
+ "RapidAPI Listing" = "https://rapidapi.com/josejuanjocoding/api/web-metadata-and-contact-extractor"
33
+ "PyPI SDK" = "https://pypi.org/project/webmetadata-extractor/"
34
+
35
+ [tool.hatch.build.targets.wheel]
36
+ packages = ["src/crewai_webmetadata_extractor"]
@@ -0,0 +1,11 @@
1
+ from .tools import WebContactsTool, WebMarkdownTool, WebMetadataExtractTool, WebSEOAuditTool, get_tools
2
+
3
+ __all__ = [
4
+ "WebMetadataExtractTool",
5
+ "WebMarkdownTool",
6
+ "WebContactsTool",
7
+ "WebSEOAuditTool",
8
+ "get_tools",
9
+ ]
10
+
11
+ __version__ = "0.1.0"
@@ -0,0 +1,102 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ from typing import Optional, Type
6
+
7
+ from crewai.tools import BaseTool
8
+ from pydantic import BaseModel, ConfigDict, Field
9
+
10
+ from webmetadata_extractor import WebMetadataClient
11
+ from webmetadata_extractor.exceptions import WebMetadataAPIError
12
+
13
+
14
+ class UrlInput(BaseModel):
15
+ """Input schema shared by every tool in this package."""
16
+
17
+ url: str = Field(description="The fully-qualified URL to fetch and analyze, e.g. https://example.com")
18
+
19
+
20
+ def _dumps(result: dict) -> str:
21
+ return json.dumps(result, ensure_ascii=False)
22
+
23
+
24
+ class _BaseWebMetadataTool(BaseTool):
25
+ """Shared config and dispatch logic. Not meant to be used directly.
26
+
27
+ Reads the RapidAPI key from the `api_key` constructor argument, falling back
28
+ to the `WEBMETADATA_API_KEY` environment variable if not given.
29
+ """
30
+
31
+ model_config = ConfigDict(arbitrary_types_allowed=True)
32
+ args_schema: Type[BaseModel] = UrlInput
33
+ client_method: str = ""
34
+ api_key: Optional[str] = Field(default=None, exclude=True)
35
+
36
+ def _run(self, url: str) -> str:
37
+ client = WebMetadataClient(api_key=self.api_key or os.environ.get("WEBMETADATA_API_KEY"))
38
+ try:
39
+ return _dumps(getattr(client, self.client_method)(url))
40
+ except WebMetadataAPIError as exc:
41
+ return _dumps({"error": True, "status_code": exc.status_code, "detail": exc.body})
42
+ finally:
43
+ client.close()
44
+
45
+
46
+ class WebMetadataExtractTool(_BaseWebMetadataTool):
47
+ """Full extraction: SEO/OpenGraph metadata, contacts, tech stack, schema.org, security, links."""
48
+
49
+ name: str = "web_metadata_extract"
50
+ description: str = (
51
+ "Extract the full structured web intelligence payload for a URL: SEO/OpenGraph metadata, "
52
+ "public contact info (emails/phones/social links), detected tech stack, Schema.org product data, "
53
+ "a graded security-headers audit, and internal/external links. Use this when you need a broad "
54
+ "picture of a page rather than one specific facet. Input is a single URL."
55
+ )
56
+ client_method: str = "extract"
57
+
58
+
59
+ class WebMarkdownTool(_BaseWebMetadataTool):
60
+ """Clean, AI/LLM-ready Markdown of a page's main content — for RAG ingestion pipelines."""
61
+
62
+ name: str = "web_markdown_reader"
63
+ description: str = (
64
+ "Fetch a URL and return its main article content as clean, LLM-ready Markdown (boilerplate, nav, "
65
+ "and ads stripped). Use this to ingest web pages into a RAG pipeline or to let an agent read a "
66
+ "page's actual content. Input is a single URL."
67
+ )
68
+ client_method: str = "markdown"
69
+
70
+
71
+ class WebContactsTool(_BaseWebMetadataTool):
72
+ """Public contact discovery (emails, phone numbers, social links) — a raw signal for lead-gen crews."""
73
+
74
+ name: str = "web_contacts_extract"
75
+ description: str = (
76
+ "Find public contact signals on a URL: email addresses, phone numbers, and social media profile "
77
+ "links present in the page's HTML. This is a raw signal for a lead-generation or outreach workflow, "
78
+ "not verified company/people intelligence. Input is a single URL."
79
+ )
80
+ client_method: str = "contacts"
81
+
82
+
83
+ class WebSEOAuditTool(_BaseWebMetadataTool):
84
+ """14-point automated SEO diagnostic with a warnings list and readability metrics."""
85
+
86
+ name: str = "web_seo_audit"
87
+ description: str = (
88
+ "Run a 14-point automated SEO audit on a URL: overall score, a list of warnings with severity and "
89
+ "evidence, and readability metrics (heading structure, sentence/paragraph counts). Use this when "
90
+ "asked to review, grade, or diagnose a page's SEO. Input is a single URL."
91
+ )
92
+ client_method: str = "seo_audit"
93
+
94
+
95
+ def get_tools(api_key: Optional[str] = None) -> list[BaseTool]:
96
+ """Convenience helper: instantiate all four tools with a shared api_key, ready to add to an Agent."""
97
+ return [
98
+ WebMetadataExtractTool(api_key=api_key),
99
+ WebMarkdownTool(api_key=api_key),
100
+ WebContactsTool(api_key=api_key),
101
+ WebSEOAuditTool(api_key=api_key),
102
+ ]
@@ -0,0 +1,84 @@
1
+ import json
2
+
3
+ import responses
4
+ from webmetadata_extractor.client import DEFAULT_BASE_URL
5
+
6
+ from crewai_webmetadata_extractor import (
7
+ WebContactsTool,
8
+ WebMarkdownTool,
9
+ WebMetadataExtractTool,
10
+ WebSEOAuditTool,
11
+ get_tools,
12
+ )
13
+
14
+
15
+ @responses.activate
16
+ def test_extract_tool_run_returns_json_string():
17
+ responses.add(
18
+ responses.GET,
19
+ f"{DEFAULT_BASE_URL}/api/v1/extract",
20
+ json={"title": "GitHub"},
21
+ status=200,
22
+ )
23
+
24
+ tool = WebMetadataExtractTool(api_key="fake-key")
25
+ result = tool._run("https://github.com")
26
+
27
+ assert json.loads(result) == {"title": "GitHub"}
28
+ assert responses.calls[0].request.headers["X-RapidAPI-Key"] == "fake-key"
29
+
30
+
31
+ @responses.activate
32
+ def test_markdown_tool_hits_markdown_endpoint():
33
+ responses.add(
34
+ responses.GET,
35
+ f"{DEFAULT_BASE_URL}/api/v1/markdown",
36
+ json={"markdown_content": "# Hello"},
37
+ status=200,
38
+ )
39
+
40
+ tool = WebMarkdownTool(api_key="fake-key")
41
+ result = tool._run("https://example.com")
42
+
43
+ assert json.loads(result) == {"markdown_content": "# Hello"}
44
+
45
+
46
+ @responses.activate
47
+ def test_contacts_tool_returns_error_payload_on_api_error_instead_of_raising():
48
+ responses.add(
49
+ responses.GET,
50
+ f"{DEFAULT_BASE_URL}/api/v1/contacts",
51
+ json={"detail": "Invalid URL"},
52
+ status=400,
53
+ )
54
+
55
+ tool = WebContactsTool(api_key="fake-key")
56
+ result = tool._run("not-a-url")
57
+
58
+ parsed = json.loads(result)
59
+ assert parsed["error"] is True
60
+ assert parsed["status_code"] == 400
61
+
62
+
63
+ @responses.activate
64
+ def test_seo_audit_tool_reads_env_var_when_no_api_key_passed(monkeypatch):
65
+ monkeypatch.setenv("WEBMETADATA_API_KEY", "env-key")
66
+ responses.add(
67
+ responses.GET, f"{DEFAULT_BASE_URL}/api/v1/seo-audit", json={"seo_score_percentage": 91.7}, status=200
68
+ )
69
+
70
+ tool = WebSEOAuditTool()
71
+ tool._run("https://example.com")
72
+
73
+ assert responses.calls[0].request.headers["X-RapidAPI-Key"] == "env-key"
74
+
75
+
76
+ def test_get_tools_returns_all_four_with_shared_key():
77
+ tools = get_tools(api_key="shared-key")
78
+ assert {t.name for t in tools} == {
79
+ "web_metadata_extract",
80
+ "web_markdown_reader",
81
+ "web_contacts_extract",
82
+ "web_seo_audit",
83
+ }
84
+ assert all(t.api_key == "shared-key" for t in tools)