Farhaddlrn's picture
Add large file
ce8469e
import re
import json
import fitz
import logging
import requests
from bs4 import BeautifulSoup
def extract_text_from_url(url):
"""
Extracts and cleans text content from a given URL.
This function sends a GET request to the specified URL, parses the HTML content,
removes unwanted elements (such as scripts, styles, headers, footers, navigation, and asides),
and extracts the text from paragraph, preformatted, and code elements. The extracted text
is then normalized to avoid unwanted formatting issues.
Args:
url (str): The URL of the webpage to extract text from.
Returns:
str: The cleaned and extracted text content from the webpage, or None if an error occurs
or if the URL returns a 404 Not Found status.
"""
try:
response = requests.get(url, timeout=10)
if response.status_code == 404:
logging.warning(f"Skipping {url}: 404 Not Found")
return None
soup = BeautifulSoup(response.text, "html.parser")
# Remove unwanted elements
for tag in soup(["script", "style", "header", "footer", "nav", "aside"]):
tag.decompose()
# Extract all relevant elements in the order they appear
content = []
for element in soup.find_all(["p", "pre", "code"]):
if element.name == "p":
content.append(element.get_text(strip=False))
elif element.name in ["pre", "code"]:
content.append(f"\n```\n{element.get_text(strip=False)}\n```\n") # Preserve code block formatting
# Join extracted content while preserving order
full_content = "\n\n".join(content)
# Normalize spaces to avoid unwanted formatting issues
full_content = re.sub(r'\s+', ' ', full_content).strip()
return full_content
except requests.RequestException as e:
logging.info(f"Error fetching {url}: {e}")
return None
def scrape_articles(json_file, output_file):
"""
Scrapes article content from URLs provided in a JSON file and saves the results to an output file.
Args:
json_file (str): Path to the input JSON file containing article names and URLs.
output_file (str): Path to the output JSON file where scraped content will be saved.
The function reads the input JSON file, extracts article names and URLs, scrapes the content from each URL,
and saves the updated data (including the scraped content) into the output JSON file.
The expected format of the input JSON:
{
"description": "Some description",
"data": [
{"Name": "Article 1", "Link": "https://example.com/article1"},
{"Name": "Article 2", "Link": "https://example.com/article2"},
...
]
}
The output JSON will retain the original structure but include the scraped "Content" for each article.
Prints messages to indicate scraping progress and completion, and then return the path of output file.
"""
try:
with open(json_file, "r", encoding="utf-8") as f:
data = json.load(f)
except FileNotFoundError:
raise FileNotFoundError("The file was not found: {}.".format(json_file))
except json.JSONDecodeError:
raise ValueError("Invalid JSON format: {}.".format(json_file))
scraped_data = []
for article in data["data"]:
name = article.get("Name", "")
link = article.get("Link", "")
logging.info(f"Scraping: {name}")
content = extract_text_from_url(link)
if content:
article['Content'] = content
scraped_data.append(article)
with open(output_file, "w", encoding="utf-8") as f:
json.dump({"description": data["description"], "data": scraped_data}, f, indent=4, ensure_ascii=False)
logging.info(f"> Scraping completed. Data saved to {output_file}")
return output_file
def extract_text_from_pdf_url(url) -> str:
"""
Extracts text content from a PDF file located at a given URL.
This function sends a GET request to the specified URL, downloads the PDF content,
and extracts the text using the PyMuPDF library.
Args:
url (str): The URL of the PDF file to extract text from.
Returns:
str: The extracted text content from the PDF, or None if an error occurs.
"""
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
# Open the PDF from the response content
pdf_document = fitz.open(stream=response.content, filetype="pdf")
# Extract text from each page
text = ""
for page_num in range(pdf_document.page_count):
page = pdf_document.load_page(page_num)
text += page.get_text()
return text.strip()
except requests.RequestException as e:
logging.info(f"Error fetching {url}: {e}")
return None
except Exception as e:
logging.info(f"Error processing PDF from {url}: {e}")
return None
def scrape_pdfs(json_file, output_file):
"""
Scrapes PDF content from URLs provided in a JSON file and saves the results to an output file.
Args:
json_file (str): Path to the input JSON file containing article names and URLs.
output_file (str): Path to the output JSON file where scraped content will be saved.
The function reads the input JSON file, extracts article names and URLs, scrapes the content from each URL,
and saves the updated data (including the scraped content) into the output JSON file.
The expected format of the input JSON:
{
"description": "Some description",
"data": [
{"Name": "PDF 1", "Link": "https://example.com/pdf1.pdf"},
{"Name": "PDF 2", "Link": "https://example.com/pdf2.pdf"},
...
]
}
The output JSON will retain the original structure but include the scraped "Content" for each PDF.
Prints messages to indicate scraping progress and completion, and then return the path of output file.
"""
try:
with open(json_file, "r", encoding="utf-8") as f:
data = json.load(f)
except FileNotFoundError:
raise FileNotFoundError("The file was not found: {}.".format(json_file))
except json.JSONDecodeError:
raise ValueError("Invalid JSON format: {}.".format(json_file))
scraped_data = []
for article in data["data"]:
name = article.get("Name", "")
link = article.get("Link", "")
logging.info(f"Scraping PDF: {name}")
content = extract_text_from_pdf_url(link)
if content:
article['Content'] = content
scraped_data.append(article)
with open(output_file, "w", encoding="utf-8") as f:
json.dump({"description": data["description"], "data": scraped_data}, f, indent=4, ensure_ascii=False)
logging.info(f"> PDF scraping completed. Data saved to {output_file}")
return output_file