
Research
PyPI Package Disguised as Instagram Growth Tool Harvests User Credentials
A deceptive PyPI package posing as an Instagram growth tool collects user credentials and sends them to third-party bot services.
A multi-engine web search aggregator that provides a unified interface for searching across various search engines.
asyncio
for efficient concurrent searches.env
files, or directly in codepathlib
for cross-platform path operationstempfile
for secure temporary file operationsget_engine
function to use the correct exception typepip install twat-search
import asyncio
from twat_search.web.api import search
async def main():
results = await search("Python programming", engines=["brave", "google"])
for result in results:
print(f"Title: {result.title}")
print(f"URL: {result.url}")
print(f"Description: {result.description}")
print("---")
asyncio.run(main())
You can configure the search engines using environment variables:
# Enable/disable engines
export BRAVE_ENABLED=true
export GOOGLE_ENABLED=false
# Set API keys
export SERPAPI_API_KEY=your_api_key
export TAVILY_API_KEY=your_api_key
# Configure engine parameters
export BRAVE_DEFAULT_PARAMS='{"count": 10, "country": "US"}'
Or directly in code:
from twat_search.web.config import Config
config = Config(
brave={"enabled": True, "default_params": {"count": 10}},
google={"enabled": False}
)
# Basic search
twat-search web q "Python programming"
# Specify engines
twat-search web q "Python programming" --engines brave,google
# Get JSON output
twat-search web q "Python programming" --json
# List available engines
twat-search web info --plain
The package provides robust error handling with custom exception classes:
SearchError
: Base exception for all search-related errorsEngineError
: Raised when there's an issue with a specific engineExample:
from twat_search.web.api import search
from twat_search.web.exceptions import SearchError, EngineError
try:
results = await search("Python programming")
except EngineError as e:
print(f"Engine error: {e}")
except SearchError as e:
print(f"Search error: {e}")
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
The project maintains several key documentation files:
When contributing to this project, please follow these guidelines:
./cleanup.py status
regularly to check for linting errors and test failures.The project uses several tools to maintain code quality:
Run these tools regularly during development:
# Format code
ruff format --respect-gitignore --target-version py312 .
# Lint code
ruff check --output-format=github --fix --unsafe-fixes .
# Run tests
python -m pytest
import asyncio
from twat_search.web import search
async def main():
# Search across all configured engines
results = await search("quantum computing applications")
# Print results
for result in results:
print(f"[{result.source}] {result.title}")
print(f"URL: {result.url}")
print(f"Snippet: {result.snippet}\n")
# Run the async function
asyncio.run(main())
# Search using all available engines
twat-search web q "climate change solutions"
# Search with specific engines
twat-search web q "machine learning frameworks" -e brave,tavily
# Get json output
twat-search web q "renewable energy" --json
# Use engine-specific command
twat-search web q -e brave "web development trends" --count 10
twat_search/
└── web/
├── engines/ # Individual search engine implementations
│ ├── __init__.py # Engine registration and availability checks
│ ├── base.py # Base SearchEngine class definition
│ ├── brave.py # Brave search implementation
│ ├── bing_scraper.py # Bing scraper implementation
│ └── ... # Other engine implementations
│ └── lib_falla/ # Falla-based search engine implementations
│ ├── core/ # Core Falla functionality
│ │ ├── falla.py # Base Falla class
│ │ ├── google.py # Google search implementation
│ │ └── ... # Other Falla-based implementations
├── __init__.py # Module exports
├── api.py # Main search API
├── cli.py # Command-line interface
├── config.py # Configuration handling
├── exceptions.py # Custom exceptions
├── models.py # Data models
└── utils.py # Utility functions
Twat Search provides a consistent interface to the following search engines:
Engine | Module | API Key Required | Description | Package Extra |
---|---|---|---|---|
Brave | brave | Yes | Web search via Brave Search API | brave |
Brave News | brave_news | Yes | News search via Brave API | brave |
You.com | you | Yes | Web search via You.com API | - |
You.com News | you_news | Yes | News search via You.com API | - |
Tavily | tavily | Yes | Research-focused search API | tavily |
Perplexity | pplx | Yes | AI-powered search with detailed answers | pplx |
SerpAPI | serpapi | Yes | Google search results via SerpAPI | serpapi |
HasData Google | hasdata-google | Yes | Google search results via HasData API | hasdata |
HasData Google Light | hasdata-google-light | Yes | Light version of HasData API | hasdata |
Critique | critique | Yes | Visual and textual search capabilities | - |
DuckDuckGo | duckduckgo | No | Privacy-focused search results | duckduckgo |
Bing Scraper | bing_scraper | No | Web scraping of Bing search results | bing_scraper |
Google Falla | google_falla | No | Google search via Playwright-based scraping | falla |
Configure engines using environment variables:
# Api keys
BRAVE_API_KEY=your_brave_api_key
TAVILY_API_KEY=your_tavily_api_key
PERPLEXITY_API_KEY=your_perplexity_api_key
YOU_API_KEY=your_you_api_key
SERPAPI_API_KEY=your_serpapi_api_key
CRITIQUE_API_KEY=your_critique_api_key
HASDATA_API_KEY=your_hasdata_api_key
# Engine enablement
BRAVE_ENABLED=true
TAVILY_ENABLED=true
PERPLEXITY_ENABLED=true
YOU_ENABLED=true
SERPAPI_ENABLED=true
CRITIQUE_ENABLED=true
DUCKDUCKGO_ENABLED=true
BING_SCRAPER_ENABLED=true
HASDATA_GOOGLE_ENABLED=true
# Default parameters (json format)
BRAVE_DEFAULT_PARAMS='{"count": 10, "safesearch": "off"}'
TAVILY_DEFAULT_PARAMS='{"max_results": 5, "search_depth": "basic"}'
PERPLEXITY_DEFAULT_PARAMS='{"model": "pplx-7b-online"}'
YOU_DEFAULT_PARAMS='{"safe_search": true, "count": 8}'
SERPAPI_DEFAULT_PARAMS='{"num": 10, "gl": "us"}'
HASDATA_GOOGLE_DEFAULT_PARAMS='{"location": "Austin,Texas,United States", "device_type": "desktop"}'
DUCKDUCKGO_DEFAULT_PARAMS='{"max_results": 10, "safesearch": "moderate", "time": "d"}'
BING_SCRAPER_DEFAULT_PARAMS='{"max_retries": 3, "delay_between_requests": 1.0}'
# Global default for all engines
NUM_RESULTS=5
You can store these in a .env
file in your project directory, which will be automatically loaded by the library using python-dotenv
.
Configure engines programmatically when using the Python API:
from twat_search.web import Config, EngineConfig, search
# Create custom configuration
config = Config(
engines={
"brave": EngineConfig(
api_key="your_brave_api_key",
enabled=True,
default_params={"count": 10, "country": "US"}
),
"bing_scraper": EngineConfig(
enabled=True,
default_params={"max_retries": 3, "delay_between_requests": 1.0}
),
"tavily": EngineConfig(
api_key="your_tavily_api_key",
enabled=True,
default_params={"search_depth": "advanced"}
)
}
)
# Use the configuration
results = await search("quantum computing", config=config)
Twat Search provides a robust error handling framework to ensure graceful failure and clear error messages:
SearchError
: Base exception for all search-related errorsEngineError
: Specific exception for engine-related issues# No engines configured
try:
results = await search("query", engines=[])
except SearchError as e:
print(e) # "No search engines specified or available"
# Non-existent engine
try:
results = await search("query", engines=["nonexistent_engine"])
except SearchError as e:
print(e) # "Engine 'nonexistent_engine': not found"
# Disabled engine
try:
results = await search("query", engines=["disabled_engine"])
except SearchError as e:
print(e) # "Engine 'disabled_engine': is disabled"
The latest version includes several important fixes and improvements:
These improvements make the package more robust, easier to debug, and more reliable in various usage scenarios.
The project is actively maintained and regularly updated. All unit tests are passing, and the codebase is continuously improved based on user feedback and identified issues.
Current focus areas include:
For a complete list of planned improvements, see the TODO.md file.
This project is licensed under the MIT License - see the LICENSE file for details.
Engine | Package Extra | API Key Required | Environment Variable | Notes |
---|---|---|---|---|
Brave | brave | Yes | BRAVE_API_KEY | General web search engine |
Brave News | brave | Yes | BRAVE_API_KEY | News-specific search |
You.com | - | Yes | YOU_API_KEY | AI-powered web search |
You.com News | - | Yes | YOU_API_KEY | News-specific search |
Tavily | tavily | Yes | TAVILY_API_KEY | Research-focused search |
Perplexity | pplx | Yes | PPLX_API_KEY | AI-powered search with detailed answers |
SerpAPI | serpapi | Yes | SERPAPI_API_KEY | Google search results API |
HasData Google | hasdata | Yes | HASDATA_API_KEY | Google search results API |
HasData Google Light | hasdata | Yes | HASDATA_API_KEY | Lightweight Google search API |
Critique | - | Yes | CRITIQUE_API_KEY | Supports image analysis |
DuckDuckGo | duckduckgo | No | - | Privacy-focused search |
Bing Scraper | bing_scraper | No | - | Uses web scraping techniques |
FAQs
Web search plugin for twat
We found that twat-search demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
A deceptive PyPI package posing as an Instagram growth tool collects user credentials and sends them to third-party bot services.
Product
Socket now supports pylock.toml, enabling secure, reproducible Python builds with advanced scanning and full alignment with PEP 751's new standard.
Security News
Research
Socket uncovered two npm packages that register hidden HTTP endpoints to delete all files on command.