tech-stack-lookup 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,5 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ApiVault Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
@@ -0,0 +1,100 @@
1
+ Metadata-Version: 2.4
2
+ Name: tech-stack-lookup
3
+ Version: 0.1.0
4
+ Summary: Python SDK for Tech Stack Lookup on Apify. Find websites by technologies, market signals and public contact availability through the hosted Apify Actor.
5
+ Author: ApiVault Labs
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/apivault-labs/tech-stack-lookup-python
8
+ Project-URL: Documentation, https://github.com/apivault-labs/tech-stack-lookup-python#readme
9
+ Project-URL: Apify Actor, https://apify.com/apivault_labs/tech-stack-lookup
10
+ Project-URL: Bug Tracker, https://github.com/apivault-labs/tech-stack-lookup-python/issues
11
+ Keywords: tech-stack,technology-lookup,website-leads,sales-intelligence,b2b-leads,apify,python-sdk
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: requests>=2.31.0
16
+ Dynamic: license-file
17
+
18
+ # Tech Stack Lookup — Python SDK
19
+
20
+ Python client for the [Tech Stack Lookup Apify Actor](https://apify.com/apivault_labs/tech-stack-lookup). Send public Actor inputs, wait for the hosted run, and receive clean Dataset rows without maintaining scraping infrastructure.
21
+
22
+ [![Apify Actor](https://img.shields.io/badge/Apify-Actor-blue)](https://apify.com/apivault_labs/tech-stack-lookup)
23
+ [![Python 3.9+](https://img.shields.io/badge/Python-3.9%2B-blue)](https://www.python.org/)
24
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
25
+
26
+ ## Results
27
+
28
+ - Technology and category targeting
29
+ - Country and vertical filters
30
+ - Public contact availability filters
31
+ - Stable sorting, pagination and count previews
32
+
33
+ The repository exposes only the Actor's public input and output contract. Data selection and processing remain inside the hosted Actor.
34
+
35
+ ## Install
36
+
37
+ ```bash
38
+ pip install git+https://github.com/apivault-labs/tech-stack-lookup-python.git
39
+ ```
40
+
41
+ Create an Apify token at [Console → Integrations](https://console.apify.com/account/integrations), then:
42
+
43
+ ```python
44
+ from tech_stack_lookup import TechStackLookupClient
45
+
46
+ client = TechStackLookupClient(api_token="apify_api_xxxxxx")
47
+ rows = client.run({'mode': 'find',
48
+ 'technologies': ['Shopify'],
49
+ 'country': ['US'],
50
+ 'hasEmail': True,
51
+ 'maxItems': 100})
52
+ print(rows[0] if rows else "No results")
53
+ ```
54
+
55
+ You can set `APIFY_API_TOKEN` instead of passing the token in code.
56
+
57
+ ## Public input options
58
+
59
+ | Field | Type | Default | Description |
60
+ |---|---|---|---|
61
+ | `mode` | `string` | `find` | Find matching websites or inspect supplied domains. |
62
+ | `domains` | `array` | `[]` | Domains to inspect in lookup mode. |
63
+ | `technologies` | `array` | `[]` | Technology names to include. |
64
+ | `matchMode` | `string` | `any` | Match any or all selected technologies. |
65
+ | `excludeTechnologies` | `array` | `[]` | Technology names to exclude. |
66
+ | `category` | `array` | `[]` | Technology categories to include. |
67
+ | `country` | `array` | `[]` | ISO-2 country codes. |
68
+ | `vertical` | `array` | `[]` | Business verticals to include. |
69
+ | `hasEmail` | `boolean` | `False` | Return records with a public email. |
70
+ | `hasPhone` | `boolean` | `False` | Return records with a public phone. |
71
+ | `sortBy` | `string` | `` | Public field used to order results. |
72
+ | `sortDesc` | `boolean` | `True` | Return highest values first. |
73
+ | `dedupeByDomain` | `boolean` | `True` | Return each root domain once. |
74
+ | `outputPreset` | `string` | `essential` | Choose a public result layout. |
75
+ | `countOnly` | `boolean` | `False` | Return a count preview instead of rows. |
76
+ | `maxItems` | `integer` | `100` | Maximum number of returned rows. |
77
+ | `offset` | `integer` | `0` | Rows to skip for pagination. |
78
+
79
+ The complete, versioned schema is also available on the [Actor page](https://apify.com/apivault_labs/tech-stack-lookup).
80
+
81
+ ## Pricing
82
+
83
+ Pay per delivered result through Apify, starting around **$7/1,000 results** on paid tiers. Free-plan pricing and platform usage can differ; check the Actor page before large runs.
84
+
85
+ ## Examples
86
+
87
+ - `examples/quickstart.py` — first run
88
+ - `examples/bulk_analysis.py` — expand a target list
89
+ - `examples/export_csv.py` — save flat result fields
90
+ - `examples/save_json.py` — preserve nested output
91
+ - `examples/cost_estimate.py` — estimate result-event charges
92
+ - `examples/environment_token.py` — keep credentials out of code
93
+
94
+ ## Architecture and privacy
95
+
96
+ This repository is intentionally a thin API client. Collection, retries, analysis and billing run inside the hosted Apify Actor. No private implementation, credentials, scoring weights or infrastructure configuration are included.
97
+
98
+ ## License
99
+
100
+ MIT. The hosted Actor is a separate paid service governed by Apify terms.
@@ -0,0 +1,83 @@
1
+ # Tech Stack Lookup — Python SDK
2
+
3
+ Python client for the [Tech Stack Lookup Apify Actor](https://apify.com/apivault_labs/tech-stack-lookup). Send public Actor inputs, wait for the hosted run, and receive clean Dataset rows without maintaining scraping infrastructure.
4
+
5
+ [![Apify Actor](https://img.shields.io/badge/Apify-Actor-blue)](https://apify.com/apivault_labs/tech-stack-lookup)
6
+ [![Python 3.9+](https://img.shields.io/badge/Python-3.9%2B-blue)](https://www.python.org/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
8
+
9
+ ## Results
10
+
11
+ - Technology and category targeting
12
+ - Country and vertical filters
13
+ - Public contact availability filters
14
+ - Stable sorting, pagination and count previews
15
+
16
+ The repository exposes only the Actor's public input and output contract. Data selection and processing remain inside the hosted Actor.
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ pip install git+https://github.com/apivault-labs/tech-stack-lookup-python.git
22
+ ```
23
+
24
+ Create an Apify token at [Console → Integrations](https://console.apify.com/account/integrations), then:
25
+
26
+ ```python
27
+ from tech_stack_lookup import TechStackLookupClient
28
+
29
+ client = TechStackLookupClient(api_token="apify_api_xxxxxx")
30
+ rows = client.run({'mode': 'find',
31
+ 'technologies': ['Shopify'],
32
+ 'country': ['US'],
33
+ 'hasEmail': True,
34
+ 'maxItems': 100})
35
+ print(rows[0] if rows else "No results")
36
+ ```
37
+
38
+ You can set `APIFY_API_TOKEN` instead of passing the token in code.
39
+
40
+ ## Public input options
41
+
42
+ | Field | Type | Default | Description |
43
+ |---|---|---|---|
44
+ | `mode` | `string` | `find` | Find matching websites or inspect supplied domains. |
45
+ | `domains` | `array` | `[]` | Domains to inspect in lookup mode. |
46
+ | `technologies` | `array` | `[]` | Technology names to include. |
47
+ | `matchMode` | `string` | `any` | Match any or all selected technologies. |
48
+ | `excludeTechnologies` | `array` | `[]` | Technology names to exclude. |
49
+ | `category` | `array` | `[]` | Technology categories to include. |
50
+ | `country` | `array` | `[]` | ISO-2 country codes. |
51
+ | `vertical` | `array` | `[]` | Business verticals to include. |
52
+ | `hasEmail` | `boolean` | `False` | Return records with a public email. |
53
+ | `hasPhone` | `boolean` | `False` | Return records with a public phone. |
54
+ | `sortBy` | `string` | `` | Public field used to order results. |
55
+ | `sortDesc` | `boolean` | `True` | Return highest values first. |
56
+ | `dedupeByDomain` | `boolean` | `True` | Return each root domain once. |
57
+ | `outputPreset` | `string` | `essential` | Choose a public result layout. |
58
+ | `countOnly` | `boolean` | `False` | Return a count preview instead of rows. |
59
+ | `maxItems` | `integer` | `100` | Maximum number of returned rows. |
60
+ | `offset` | `integer` | `0` | Rows to skip for pagination. |
61
+
62
+ The complete, versioned schema is also available on the [Actor page](https://apify.com/apivault_labs/tech-stack-lookup).
63
+
64
+ ## Pricing
65
+
66
+ Pay per delivered result through Apify, starting around **$7/1,000 results** on paid tiers. Free-plan pricing and platform usage can differ; check the Actor page before large runs.
67
+
68
+ ## Examples
69
+
70
+ - `examples/quickstart.py` — first run
71
+ - `examples/bulk_analysis.py` — expand a target list
72
+ - `examples/export_csv.py` — save flat result fields
73
+ - `examples/save_json.py` — preserve nested output
74
+ - `examples/cost_estimate.py` — estimate result-event charges
75
+ - `examples/environment_token.py` — keep credentials out of code
76
+
77
+ ## Architecture and privacy
78
+
79
+ This repository is intentionally a thin API client. Collection, retries, analysis and billing run inside the hosted Apify Actor. No private implementation, credentials, scoring weights or infrastructure configuration are included.
80
+
81
+ ## License
82
+
83
+ MIT. The hosted Actor is a separate paid service governed by Apify terms.
@@ -0,0 +1,23 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "tech-stack-lookup"
7
+ version = "0.1.0"
8
+ description = "Python SDK for Tech Stack Lookup on Apify. Find websites by technologies, market signals and public contact availability through the hosted Apify Actor."
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ authors = [{ name = "ApiVault Labs" }]
12
+ requires-python = ">=3.9"
13
+ dependencies = ["requests>=2.31.0"]
14
+ keywords = ["tech-stack", "technology-lookup", "website-leads", "sales-intelligence", "b2b-leads", "apify", "python-sdk"]
15
+
16
+ [project.urls]
17
+ Homepage = "https://github.com/apivault-labs/tech-stack-lookup-python"
18
+ Documentation = "https://github.com/apivault-labs/tech-stack-lookup-python#readme"
19
+ "Apify Actor" = "https://apify.com/apivault_labs/tech-stack-lookup"
20
+ "Bug Tracker" = "https://github.com/apivault-labs/tech-stack-lookup-python/issues"
21
+
22
+ [tool.setuptools.packages.find]
23
+ include = ["tech_stack_lookup*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,6 @@
1
+ """Python SDK for the hosted Tech Stack Lookup Apify Actor."""
2
+ from .client import TechStackLookupClient
3
+ from .exceptions import TechStackLookupError, AuthenticationError, ActorRunError, ActorTimeoutError
4
+
5
+ __version__ = "0.1.0"
6
+ __all__ = ["TechStackLookupClient", "TechStackLookupError", "AuthenticationError", "ActorRunError", "ActorTimeoutError"]
@@ -0,0 +1,112 @@
1
+ """Thin synchronous client for the Tech Stack Lookup Apify Actor."""
2
+ from __future__ import annotations
3
+
4
+ import os
5
+ import time
6
+ from typing import Any, Mapping
7
+
8
+ import requests
9
+
10
+ from .exceptions import ActorRunError, ActorTimeoutError, AuthenticationError, TechStackLookupError
11
+
12
+ ACTOR_ID = "apivault_labs~tech-stack-lookup"
13
+ APIFY_API_BASE = "https://api.apify.com/v2"
14
+ TERMINAL_FAIL = {"FAILED", "TIMED-OUT", "ABORTED"}
15
+
16
+
17
+ class TechStackLookupClient:
18
+ """Run the hosted Actor and download its Dataset results."""
19
+
20
+ def __init__(self, api_token: str | None = None, timeout: int = 600,
21
+ poll_interval: float = 3.0):
22
+ token = api_token or os.environ.get("APIFY_API_TOKEN")
23
+ if not token:
24
+ raise AuthenticationError(
25
+ "Pass api_token or set APIFY_API_TOKEN. Create a token at "
26
+ "https://console.apify.com/account/integrations"
27
+ )
28
+ self.timeout = int(timeout)
29
+ self.poll_interval = float(poll_interval)
30
+ self.base_url = APIFY_API_BASE
31
+ self.session = requests.Session()
32
+ self.session.headers.update({
33
+ "Authorization": f"Bearer {token}",
34
+ "Content-Type": "application/json",
35
+ "User-Agent": "tech-stack-lookup-python/0.1.0",
36
+ })
37
+
38
+ def run(self, actor_input: Mapping[str, Any], *, actor_timeout_secs: int = 300) -> list[dict[str, Any]]:
39
+ """Start one Actor run, wait for completion and return clean Dataset items."""
40
+ if not isinstance(actor_input, Mapping):
41
+ raise TypeError("actor_input must be a mapping")
42
+ run_id = self._start(dict(actor_input), actor_timeout_secs)
43
+ run = self._wait(run_id)
44
+ dataset_id = run.get("defaultDatasetId")
45
+ if not dataset_id:
46
+ raise ActorRunError("Successful run did not expose a Dataset ID")
47
+ return self._dataset(dataset_id)
48
+
49
+ def run_one(self, actor_input: Mapping[str, Any], **kwargs: Any) -> dict[str, Any]:
50
+ """Return the first Dataset row, raising when no result was produced."""
51
+ rows = self.run(actor_input, **kwargs)
52
+ if not rows:
53
+ raise ActorRunError("Actor completed but returned no Dataset rows")
54
+ return rows[0]
55
+
56
+ @staticmethod
57
+ def estimate_cost(result_count: int, price_per_1000: float = 7.0) -> float:
58
+ """Estimate result charges; actual tier pricing and platform usage may vary."""
59
+ if result_count < 0:
60
+ raise ValueError("result_count cannot be negative")
61
+ return round(result_count * price_per_1000 / 1000, 6)
62
+
63
+ def _start(self, payload: dict[str, Any], timeout_secs: int) -> str:
64
+ try:
65
+ response = self.session.post(
66
+ f"{self.base_url}/acts/{ACTOR_ID}/runs",
67
+ params={"timeout": int(timeout_secs)}, json=payload, timeout=30,
68
+ )
69
+ except requests.RequestException as exc:
70
+ raise TechStackLookupError(f"Could not start Actor run: {exc}") from exc
71
+ if response.status_code == 401:
72
+ raise AuthenticationError("Apify rejected the API token")
73
+ if response.status_code >= 400:
74
+ raise ActorRunError(f"Run start failed with HTTP {response.status_code}: {response.text[:300]}")
75
+ run_id = (response.json().get("data") or {}).get("id")
76
+ if not run_id:
77
+ raise ActorRunError("Apify response did not contain a run ID")
78
+ return run_id
79
+
80
+ def _wait(self, run_id: str) -> dict[str, Any]:
81
+ deadline = time.monotonic() + self.timeout
82
+ while True:
83
+ try:
84
+ response = self.session.get(f"{self.base_url}/actor-runs/{run_id}", timeout=30)
85
+ except requests.RequestException as exc:
86
+ raise TechStackLookupError(f"Could not poll Actor run: {exc}") from exc
87
+ if response.status_code >= 400:
88
+ raise ActorRunError(f"Run poll failed with HTTP {response.status_code}: {response.text[:300]}")
89
+ run = response.json().get("data") or {}
90
+ status = run.get("status")
91
+ if status == "SUCCEEDED":
92
+ return run
93
+ if status in TERMINAL_FAIL:
94
+ raise ActorRunError(f"Actor run ended with {status}: {run.get('statusMessage') or 'no details'}")
95
+ if time.monotonic() >= deadline:
96
+ raise ActorTimeoutError(f"Actor run {run_id} did not finish within {self.timeout} seconds")
97
+ time.sleep(self.poll_interval)
98
+
99
+ def _dataset(self, dataset_id: str) -> list[dict[str, Any]]:
100
+ try:
101
+ response = self.session.get(
102
+ f"{self.base_url}/datasets/{dataset_id}/items",
103
+ params={"clean": "true", "format": "json"}, timeout=120,
104
+ )
105
+ except requests.RequestException as exc:
106
+ raise TechStackLookupError(f"Could not download Dataset: {exc}") from exc
107
+ if response.status_code >= 400:
108
+ raise ActorRunError(f"Dataset fetch failed with HTTP {response.status_code}: {response.text[:300]}")
109
+ data = response.json()
110
+ if not isinstance(data, list):
111
+ raise ActorRunError("Unexpected Dataset response type")
112
+ return data
@@ -0,0 +1,13 @@
1
+ """Public exception hierarchy for the Tech Stack Lookup SDK."""
2
+
3
+ class TechStackLookupError(Exception):
4
+ """Base SDK error."""
5
+
6
+ class AuthenticationError(TechStackLookupError):
7
+ """The Apify token is missing or rejected."""
8
+
9
+ class ActorRunError(TechStackLookupError):
10
+ """The Actor run or Dataset request failed."""
11
+
12
+ class ActorTimeoutError(TechStackLookupError):
13
+ """The client stopped waiting before the Actor completed."""
@@ -0,0 +1,100 @@
1
+ Metadata-Version: 2.4
2
+ Name: tech-stack-lookup
3
+ Version: 0.1.0
4
+ Summary: Python SDK for Tech Stack Lookup on Apify. Find websites by technologies, market signals and public contact availability through the hosted Apify Actor.
5
+ Author: ApiVault Labs
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/apivault-labs/tech-stack-lookup-python
8
+ Project-URL: Documentation, https://github.com/apivault-labs/tech-stack-lookup-python#readme
9
+ Project-URL: Apify Actor, https://apify.com/apivault_labs/tech-stack-lookup
10
+ Project-URL: Bug Tracker, https://github.com/apivault-labs/tech-stack-lookup-python/issues
11
+ Keywords: tech-stack,technology-lookup,website-leads,sales-intelligence,b2b-leads,apify,python-sdk
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: requests>=2.31.0
16
+ Dynamic: license-file
17
+
18
+ # Tech Stack Lookup — Python SDK
19
+
20
+ Python client for the [Tech Stack Lookup Apify Actor](https://apify.com/apivault_labs/tech-stack-lookup). Send public Actor inputs, wait for the hosted run, and receive clean Dataset rows without maintaining scraping infrastructure.
21
+
22
+ [![Apify Actor](https://img.shields.io/badge/Apify-Actor-blue)](https://apify.com/apivault_labs/tech-stack-lookup)
23
+ [![Python 3.9+](https://img.shields.io/badge/Python-3.9%2B-blue)](https://www.python.org/)
24
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
25
+
26
+ ## Results
27
+
28
+ - Technology and category targeting
29
+ - Country and vertical filters
30
+ - Public contact availability filters
31
+ - Stable sorting, pagination and count previews
32
+
33
+ The repository exposes only the Actor's public input and output contract. Data selection and processing remain inside the hosted Actor.
34
+
35
+ ## Install
36
+
37
+ ```bash
38
+ pip install git+https://github.com/apivault-labs/tech-stack-lookup-python.git
39
+ ```
40
+
41
+ Create an Apify token at [Console → Integrations](https://console.apify.com/account/integrations), then:
42
+
43
+ ```python
44
+ from tech_stack_lookup import TechStackLookupClient
45
+
46
+ client = TechStackLookupClient(api_token="apify_api_xxxxxx")
47
+ rows = client.run({'mode': 'find',
48
+ 'technologies': ['Shopify'],
49
+ 'country': ['US'],
50
+ 'hasEmail': True,
51
+ 'maxItems': 100})
52
+ print(rows[0] if rows else "No results")
53
+ ```
54
+
55
+ You can set `APIFY_API_TOKEN` instead of passing the token in code.
56
+
57
+ ## Public input options
58
+
59
+ | Field | Type | Default | Description |
60
+ |---|---|---|---|
61
+ | `mode` | `string` | `find` | Find matching websites or inspect supplied domains. |
62
+ | `domains` | `array` | `[]` | Domains to inspect in lookup mode. |
63
+ | `technologies` | `array` | `[]` | Technology names to include. |
64
+ | `matchMode` | `string` | `any` | Match any or all selected technologies. |
65
+ | `excludeTechnologies` | `array` | `[]` | Technology names to exclude. |
66
+ | `category` | `array` | `[]` | Technology categories to include. |
67
+ | `country` | `array` | `[]` | ISO-2 country codes. |
68
+ | `vertical` | `array` | `[]` | Business verticals to include. |
69
+ | `hasEmail` | `boolean` | `False` | Return records with a public email. |
70
+ | `hasPhone` | `boolean` | `False` | Return records with a public phone. |
71
+ | `sortBy` | `string` | `` | Public field used to order results. |
72
+ | `sortDesc` | `boolean` | `True` | Return highest values first. |
73
+ | `dedupeByDomain` | `boolean` | `True` | Return each root domain once. |
74
+ | `outputPreset` | `string` | `essential` | Choose a public result layout. |
75
+ | `countOnly` | `boolean` | `False` | Return a count preview instead of rows. |
76
+ | `maxItems` | `integer` | `100` | Maximum number of returned rows. |
77
+ | `offset` | `integer` | `0` | Rows to skip for pagination. |
78
+
79
+ The complete, versioned schema is also available on the [Actor page](https://apify.com/apivault_labs/tech-stack-lookup).
80
+
81
+ ## Pricing
82
+
83
+ Pay per delivered result through Apify, starting around **$7/1,000 results** on paid tiers. Free-plan pricing and platform usage can differ; check the Actor page before large runs.
84
+
85
+ ## Examples
86
+
87
+ - `examples/quickstart.py` — first run
88
+ - `examples/bulk_analysis.py` — expand a target list
89
+ - `examples/export_csv.py` — save flat result fields
90
+ - `examples/save_json.py` — preserve nested output
91
+ - `examples/cost_estimate.py` — estimate result-event charges
92
+ - `examples/environment_token.py` — keep credentials out of code
93
+
94
+ ## Architecture and privacy
95
+
96
+ This repository is intentionally a thin API client. Collection, retries, analysis and billing run inside the hosted Apify Actor. No private implementation, credentials, scoring weights or infrastructure configuration are included.
97
+
98
+ ## License
99
+
100
+ MIT. The hosted Actor is a separate paid service governed by Apify terms.
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ tech_stack_lookup/__init__.py
5
+ tech_stack_lookup/client.py
6
+ tech_stack_lookup/exceptions.py
7
+ tech_stack_lookup.egg-info/PKG-INFO
8
+ tech_stack_lookup.egg-info/SOURCES.txt
9
+ tech_stack_lookup.egg-info/dependency_links.txt
10
+ tech_stack_lookup.egg-info/requires.txt
11
+ tech_stack_lookup.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ requests>=2.31.0
@@ -0,0 +1 @@
1
+ tech_stack_lookup