ContiAI / tools /scraper /scraper_bs4.py
ziadsameh32's picture
Add login page
325b94c
Raw
History Blame Contribute Delete
2.87 kB
from crewai.tools import BaseTool
from typing import Literal
import requests
from bs4 import BeautifulSoup
import fitz # PyMuPDF
from urllib.parse import urlparse
import os
class WebScrapingToolBS4(BaseTool):
name: Literal["web_scraping_tool"]
description: str = (
"Scrapes text and media from a webpage or PDF. "
"Returns a dictionary containing: page_url, title, content, img_url, "
"video_url, audio_url, pdf_url."
)
def extract_pdf_text(self, pdf_url):
try:
response = requests.get(pdf_url, timeout=15)
temp_path = "temp_scraped.pdf"
with open(temp_path, "wb") as f:
f.write(response.content)
text = ""
with fitz.open(temp_path) as doc:
for page in doc:
text += page.get_text()
os.remove(temp_path)
return text.strip()
except Exception as e:
return f"Error extracting PDF text: {str(e)}"
def _run(self, url: str) -> dict:
"""Synchronous execution of the scraping tool."""
try:
parsed = urlparse(url)
# ========== PDF Mode ==========
if parsed.path.lower().endswith(".pdf"):
text = self.extract_pdf_text(url)
return {
"page_url": url,
"title": os.path.basename(parsed.path),
"content": text,
"img_url": [],
"video_url": [],
"audio_url": [],
"pdf_url": [url],
}
# ========== HTML Mode ==========
response = requests.get(url, timeout=15)
soup = BeautifulSoup(response.text, "html.parser")
title = soup.title.string if soup.title else "Untitled"
paragraphs = [p.get_text(" ", strip=True) for p in soup.find_all("p")]
content = "\n".join(paragraphs)
images = [img["src"] for img in soup.find_all("img", src=True)]
videos = [v["src"] for v in soup.find_all("video", src=True)]
audios = [a["src"] for a in soup.find_all("audio", src=True)]
pdfs = [
a["href"]
for a in soup.find_all("a", href=True)
if a["href"].lower().endswith(".pdf")
]
return {
"page_url": url,
"title": title,
"content": content,
"img_url": images,
"video_url": videos,
"audio_url": audios,
"pdf_url": pdfs,
}
except Exception as e:
return {"error": str(e), "page_url": url}
async def _arun(self, url: str) -> dict:
"""Async version (calls sync internally)."""
return self._run(url)