Skip to content

Commit 2139e37

Browse files
VinciGit00claude
andauthored
fix(search): restore SearchGraph by migrating DuckDuckGo backend to ddgs (#1083)
The 'duckduckgo-search' package was renamed to 'ddgs'. Recent langchain-community releases import 'from ddgs import DDGS' in their DuckDuckGoSearchResults tool, so with the old dependency installed the default SearchGraph path raised ImportError and returned no results (GH #1082). Replace the langchain-community DuckDuckGo wrapper with a direct ddgs call in research_web._search_duckduckgo, extracting result URLs from the structured 'href' field instead of regex-parsing a formatted string. Swap the 'duckduckgo-search' dependency for 'ddgs>=9.0.0'. Fixes #1082 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent bdf69f6 commit 2139e37

3 files changed

Lines changed: 312 additions & 1457 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ dependencies = [
3030
"async-timeout>=4.0.0",
3131
"simpleeval>=1.0.3",
3232
"jsonschema>=4.25.1",
33-
"duckduckgo-search>=8.1.1",
33+
"ddgs>=9.0.0",
3434
"pydantic>=2.12.5",
3535
"scrapegraph-py>=2.0.0",
3636
]

scrapegraphai/utils/research_web.py

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
import requests
1313
from bs4 import BeautifulSoup
14-
from langchain_community.tools import DuckDuckGoSearchResults
1514
from pydantic import BaseModel, Field, validator
1615

1716

@@ -215,12 +214,9 @@ def search_on_web(
215214

216215
results = []
217216
if config.search_engine == "duckduckgo":
218-
# Create a DuckDuckGo search object with max_results
219-
research = DuckDuckGoSearchResults(max_results=config.max_results)
220-
# Run the search
221-
res = research.run(config.query)
222-
# Extract URLs using regex
223-
results = re.findall(r"https?://[^\s,\]]+", res)
217+
results = _search_duckduckgo(
218+
config.query, config.max_results, formatted_proxy
219+
)
224220

225221
elif config.search_engine == "bing":
226222
results = _search_bing(
@@ -247,6 +243,45 @@ def search_on_web(
247243
raise SearchConfigError(f"Invalid search configuration: {str(e)}")
248244

249245

246+
def _search_duckduckgo(
247+
query: str, max_results: int, proxy: Optional[str] = None
248+
) -> List[str]:
249+
"""
250+
Helper function for DuckDuckGo search using the ``ddgs`` package.
251+
252+
The ``duckduckgo-search`` package was renamed to ``ddgs``; recent
253+
``langchain-community`` releases import ``from ddgs import DDGS``, which
254+
silently broke the previous langchain-based implementation. This calls
255+
``ddgs`` directly so results no longer depend on parsing a formatted string.
256+
257+
Args:
258+
query (str): Search query
259+
max_results (int): Maximum number of results to return
260+
proxy (str, optional): Proxy configuration
261+
262+
Returns:
263+
List[str]: List of URLs from search results
264+
"""
265+
try:
266+
from ddgs import DDGS
267+
except ImportError as e:
268+
raise ImportError(
269+
"Could not import the 'ddgs' package required for DuckDuckGo "
270+
"search. Please install it with `pip install -U ddgs`."
271+
) from e
272+
273+
try:
274+
with DDGS(proxy=proxy) as ddgs:
275+
results = [
276+
result["href"]
277+
for result in ddgs.text(query, max_results=max_results)
278+
if result.get("href")
279+
]
280+
return results
281+
except Exception as e:
282+
raise SearchRequestError(f"DuckDuckGo search failed: {str(e)}")
283+
284+
250285
def _search_bing(
251286
query: str, max_results: int, timeout: int, proxy: Optional[str] = None
252287
) -> List[str]:

0 commit comments

Comments
 (0)