greydgl--pentestgpt
233 行
8.0 KiB
Python
233 行
8.0 KiB
Python
# This file contains the utility function for performing searches online.
|
|
import os
|
|
|
|
import requests
|
|
from dotenv import load_dotenv
|
|
from newspaper import Article
|
|
from tqdm import tqdm
|
|
|
|
|
|
def parse_url_with_newspaper(url: str) -> str:
|
|
"""
|
|
This function parses the content of a URL using the newspaper library.
|
|
:param url: the URL to parse
|
|
:return: the content of the URL, main body only.
|
|
"""
|
|
article = Article(url)
|
|
article.download()
|
|
article.parse()
|
|
return article.text
|
|
|
|
|
|
def google_search_keyword(keyword: str, top_n=2) -> list:
|
|
"""
|
|
This function performs a Google search using the Google search API.
|
|
:param keyword: the keyword to search
|
|
:return: a list of search results in the format of [(title, link), (title, link), ...]
|
|
return [(None, None)] if no search results are found
|
|
"""
|
|
load_dotenv()
|
|
google_search_key = os.getenv("google_search_key")
|
|
google_search_cx = os.getenv("google_search_cx")
|
|
# perform the search
|
|
# example query: GET https://www.googleapis.com/customsearch/v1?key=INSERT_YOUR_API_KEY&cx=017576662512468239146:omuauf_lfve&q=lectures
|
|
url = f"https://www.googleapis.com/customsearch/v1?key={google_search_key}&cx={google_search_cx}&q={keyword}"
|
|
response = requests.get(url).json()
|
|
# get the top n search results on the current page
|
|
try:
|
|
search_results = response["items"][0:top_n]
|
|
except KeyError: # if no search results are found or the API is out of quota
|
|
return [(None, None)]
|
|
# return the search results
|
|
return [(result["title"], result["link"]) for result in search_results]
|
|
|
|
|
|
def google_search_keyword_openserp(keyword: str, top_n=1) -> list:
|
|
"""
|
|
This function performs a Google search via openserp.
|
|
:param keyword: the keyword to search
|
|
:return: a list of search results in the format of [(title, link), (title, link), ...]
|
|
return [(None, None)] if no search results are found
|
|
"""
|
|
# maintain a blacklist of websites that should not be included in the search results
|
|
blacklist = ["medium.com", "github.com"]
|
|
# example query: GET http://127.0.0.1:7001/google/search?lang=EN&limit=20&text=hello%20world
|
|
url = f"http://127.0.0.1:7001/google/search?lang=EN&limit=10&text={keyword}"
|
|
try:
|
|
response = requests.get(url, timeout=30).json() # add timeout of 30 seconds
|
|
except Exception as e:
|
|
print(f"Online Search Request failed: {e};")
|
|
return [(None, None)]
|
|
# get the top n search results on the current page
|
|
search_result = []
|
|
i = 0
|
|
while len(search_result) < top_n and i < len(response):
|
|
try:
|
|
# if any elements in the blacklist are in the link, skip the link
|
|
if any([item in response[i]["url"] for item in blacklist]):
|
|
i += 1
|
|
continue
|
|
search_results = response[i]
|
|
search_result.append((search_results["title"], search_results["url"]))
|
|
except Exception as e:
|
|
print(f"Error: {e}")
|
|
finally:
|
|
i += 1
|
|
return search_result
|
|
|
|
|
|
def crawl_search(search_results: list) -> list:
|
|
"""
|
|
This function crawls the search results into a JSON string as RAG.
|
|
:param search_results: the search results returned by `search_online`
|
|
the search result should be in the format of [(title, link), (title, link), ...]
|
|
the search result should be as [None, None] if no search results are found
|
|
:return: a list of strings as RAG
|
|
"""
|
|
rag = []
|
|
for title, link in search_results:
|
|
# each website info is in the format of {title: "title", link: "link", content: "content"}
|
|
if title is None or link is None:
|
|
continue
|
|
|
|
# try with Jina API read first, then fallback to newspaper, then return failed
|
|
try:
|
|
main_content = jina_read(link)
|
|
if main_content is False:
|
|
main_content = parse_url_with_newspaper(link)
|
|
rag.append({"title": title, "link": link, "content": main_content})
|
|
except Exception as e:
|
|
print(f"Request failed on {link}: {e}")
|
|
rag.append(
|
|
{"title": title, "link": link, "content": "Failed to retrieve content"}
|
|
)
|
|
continue
|
|
return rag
|
|
|
|
|
|
def check_search_connection(backend="google"):
|
|
"""
|
|
This function checks if the search backend is available.
|
|
:param backend: the backend to use for searching.
|
|
Default is "openserp".
|
|
Availables are "google" and "openserp"
|
|
"""
|
|
if backend == "google":
|
|
# perform a sample search
|
|
try:
|
|
response = google_search_keyword("test")
|
|
return response != [(None, None)]
|
|
except Exception: # any exception can be handled as False
|
|
return False
|
|
|
|
return False
|
|
elif backend == "openserp":
|
|
# perform a get request to localhost:7001
|
|
try:
|
|
response = requests.get(
|
|
"http://localhost:7001/google/search?text=test", timeout=30
|
|
) ## add timeout of 30 seconds
|
|
return response.status_code == 200
|
|
except Exception: # any exception can be handled as False
|
|
return False
|
|
else:
|
|
return False
|
|
|
|
|
|
def search_as_RAG(list_of_keywords: list, backend="google") -> list:
|
|
"""
|
|
This function searches the list of keywords and returns the search results as RAG.
|
|
:param list_of_keywords: a list of keywords to search
|
|
:param backend: the backend to use for searching.
|
|
Default is "openserp".
|
|
Availables are "google" and "openserp"
|
|
"""
|
|
rag = []
|
|
for keyword in tqdm(list_of_keywords):
|
|
if backend == "google":
|
|
search_results = google_search_keyword(keyword)
|
|
elif backend == "openserp":
|
|
search_results = google_search_keyword_openserp(keyword)
|
|
else:
|
|
search_results = google_search_keyword_openserp(keyword)
|
|
rag.extend(crawl_search(search_results))
|
|
return rag
|
|
|
|
|
|
def jina_read(url: str) -> str:
|
|
"""
|
|
This function reads the content of a URL using the Jina API.
|
|
:param url: the URL to read
|
|
return
|
|
string format of the URL content
|
|
"""
|
|
|
|
JINA_API_KEY = os.getenv("JINA_API_KEY")
|
|
base_url = "https://r.jina.ai"
|
|
headers = {
|
|
"Authorization": f"Bearer {JINA_API_KEY}",
|
|
}
|
|
url = f"{base_url}/{url}"
|
|
# make the query
|
|
try:
|
|
response = requests.get(url, headers=headers)
|
|
if response.status_code == 200:
|
|
return response.text
|
|
else:
|
|
return False
|
|
except Exception as e:
|
|
return False
|
|
|
|
|
|
def jina_search(text: str) -> str:
|
|
"""
|
|
This function performs a search using the Jina API.
|
|
:param url: the URL to search
|
|
return
|
|
string format of the search result
|
|
"""
|
|
JINA_API_KEY = os.getenv("JINA_API_KEY")
|
|
base_url = "https://s.jina.ai"
|
|
headers = {
|
|
"Authorization": f"Bearer {JINA_API_KEY}",
|
|
}
|
|
url = f"{base_url}/{text}"
|
|
# make the query
|
|
try:
|
|
response = requests.get(url, headers=headers)
|
|
if response.status_code == 200:
|
|
return response.text
|
|
else:
|
|
return False
|
|
except Exception as e:
|
|
return False
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print(jina_search("Common Vulnerabilities in Uniswap V3."))
|
|
|
|
# pre-check: check connection
|
|
connection_status = check_search_connection()
|
|
print("Connection Status:", connection_status)
|
|
if connection_status:
|
|
# test 1: search with openserp
|
|
result = google_search_keyword_openserp("AAVE Security Considerations")
|
|
print(result)
|
|
|
|
# test 2: crawl information with openserp
|
|
rag = search_as_RAG(
|
|
["AAVE Security Considerations", "ERC721 Security Considerations"]
|
|
)
|
|
print(rag)
|
|
for item in rag:
|
|
print(item["title"], item["link"])
|
|
|
|
else:
|
|
print("Search Backend is not available.")
|
|
# use the Google API search
|
|
rag = search_as_RAG(
|
|
["AAVE Security Considerations", "ERC721 Security Considerations"],
|
|
backend="google",
|
|
)
|
|
print(rag)
|