March 21

пошук валідних URLs для текстового змісту

import os
import re
import requests
from bs4 import BeautifulSoup
import time
import concurrent.futures
from urllib.parse import urlparse, quote
import random

def is_valid_url(url):
"""Перевірка валідності та доступності URL."""
try:
parsed_url = urlparse(url)
if not all([parsed_url.scheme, parsed_url.netloc]):
return False

response = requests.head(url, timeout=5, allow_redirects=True)
return response.status_code < 400
except Exception as e:
print(f"Помилка перевірки URL {url}: {str(e)}")
return False

def extract_text_from_file(file_path):
"""Витяг тексту з файлу."""
try:
with open(file_path, 'r', encoding='utf-8') as file:
return file.read()
except UnicodeDecodeError:
try:
with open(file_path, 'r', encoding='latin-1') as file:
return file.read()
except Exception as e:
print(f"Помилка читання файлу {file_path}: {e}")
return ""
except Exception as e:
print(f"Помилка читання файлу {file_path}: {e}")
return ""

def extract_keywords(text, max_keywords=5):
"""Витяг ключових слів з тексту."""
words = re.findall(r'\b[А-Яа-яA-Za-z]{4,}\b', text.lower())

stop_words = {'the', 'and', 'are', 'for', 'not', 'but', 'was', 'you', 'this', 'that',
'have', 'with', 'from', 'they', 'will', 'would', 'could', 'should',
'what', 'when', 'where', 'which', 'there', 'their', 'about',
'це', 'та', 'але', 'як', 'що', 'для', 'він', 'вона', 'вони', 'був', 'була', 'були',
'цей', 'ця', 'ці', 'той', 'та', 'ті', 'мій', 'моя', 'мої', 'твій', 'твоя', 'твої',
'наш', 'наша', 'наші', 'ваш', 'ваша', 'ваші'}
filtered_words = [word for word in words if word not in stop_words]

if not filtered_words:
return []

from collections import Counter
return [word for word, _ in Counter(filtered_words).most_common(max_keywords)]

def search_web_resources(text, max_results=15):
"""Пошук веб-ресурсів за текстом."""
keywords = extract_keywords(text)
if not keywords:
print("Не знайдено ключових слів.")
return []

query = ' '.join(keywords)
print(f"Пошук: {query}")

all_links = []

try:
ddg_links = search_duckduckgo(query, max_results)
all_links.extend(ddg_links)

if len(all_links) < max_results:
google_links = search_google(query, max_results - len(all_links))
all_links.extend(google_links)

if len(all_links) < max_results:
bing_links = search_bing(query, max_results - len(all_links))
all_links.extend(bing_links)

seen = set()
unique_links = [x for x in all_links if not (x in seen or seen.add(x))]

return unique_links[:max_results]

except Exception as e:
print(f"Помилка пошуку: {e}")
return []

def get_random_user_agent():
"""Повертає випадковий user agent."""
user_agents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36 Edg/90.0.818.66'
]
return random.choice(user_agents)

def search_duckduckgo(query, max_results=15):
"""Пошук за допомогою DuckDuckGo."""
encoded_query = quote(query)
search_url = f"https://html.duckduckgo.com/html/?q={encoded_query}"

headers = {
'User-Agent': get_random_user_agent(),
'Accept': 'text/html,application/xhtml+xml,application/xml',
'Accept-Language': 'uk-UA,uk;q=0.9,en-US;q=0.8,en;q=0.7', # Пріоритет української мови
'Referer': 'https://duckduckgo.com/'
}

try:
response = requests.get(search_url, headers=headers, timeout=10)
if response.status_code != 200:
print(f"Помилка пошуку DuckDuckGo: {response.status_code}")
return []

soup = BeautifulSoup(response.text, 'html.parser')

links = []
for result in soup.find_all('a', class_='result__url'):
href = result.get('href')
if href and href.startswith('http'):
links.append(href)

if not links:
for a in soup.find_all('a'):
href = a.get('href')
if href and href.startswith(('http://', 'https://')) and not any(domain in href for domain in ['duckduckgo.com', '.ppt', '.pptx', '.pdf', '.doc', '.docx']):
links.append(href)

print(f"Знайдено {len(links)} посилань DuckDuckGo.")
return links[:max_results]

except Exception as e:
print(f"Помилка DuckDuckGo: {e}")
return []

def search_google(query, max_results=15):
"""Пошук за допомогою Google."""
encoded_query = quote(query)
search_url = f"https://www.google.com/search?q={encoded_query}"

headers = {
'User-Agent': get_random_user_agent(),
'Accept': 'text/html,application/xhtml+xml,application/xml',
'Accept-Language': 'uk-UA,uk;q=0.9,en-US;q=0.8,en;q=0.7' # Пріоритет української мови
}

try:
response = requests.get(search_url, headers=headers, timeout=10)
if response.status_code != 200:
print(f"Помилка пошуку Google: {response.status_code}")
return []

soup = BeautifulSoup(response.text, 'html.parser')
links = []

for div in soup.find_all('div', class_='yuRUbf'): a_tags = div.find_all('a')
for a in a_tags:
if a.get('href') and a['href'].startswith('http'):
links.append(a['href'])

if not links:
for a in soup.find_all('a', href=True):
href = a['href']
if '/url?q=' in href:
actual_url = href.split('/url?q=')[1].split('&')[0]
if not any(domain in actual_url for domain in ['google.com', 'gstatic.com', '.ppt', '.pptx', '.pdf', '.doc', '.docx']):
links.append(actual_url)

if not links:
for a in soup.find_all('a', href=True):
href = a['href']
if href.startswith(('http://', 'https://')) and not any(domain in href for domain in ['google.com', 'gstatic.com', '.ppt', '.pptx', '.pdf', '.doc', '.docx']):
links.append(href)

print(f"Знайдено {len(links)} посилань Google.")
return links[:max_results]

except Exception as e:
print(f"Помилка Google: {e}")
return []

def search_bing(query, max_results=15):
"""Пошук за допомогою Bing."""
encoded_query = quote(query)
search_url = f"https://www.bing.com/search?q={encoded_query}"

headers = {
'User-Agent': get_random_user_agent(),
'Accept': 'text/html,application/xhtml+xml,application/xml',
'Accept-Language': 'uk-UA,uk;q=0.9,en-US;q=0.8,en;q=0.7' # Пріоритет української мови
}

try:
response = requests.get(search_url, headers=headers, timeout=10)
if response.status_code != 200:
print(f"Помилка пошуку Bing: {response.status_code}")
return []

soup = BeautifulSoup(response.text, 'html.parser')

links = []
for li in soup.find_all('li', class_='b_algo'):
a_tag = li.find('a')
if a_tag and a_tag.get('href'):
href = a_tag['href']
if href.startswith(('http://', 'https://')) and not any(domain in href for domain in ['bing.com', 'microsoft.com', '.ppt', '.pptx', '.pdf', '.doc', '.docx']):
links.append(href)

if not links:
for a in soup.find_all('a', href=True):
href = a['href']
if href.startswith(('http://', 'https://')) and not any(domain in href for domain in ['bing.com', 'microsoft.com', '.ppt', '.pptx', '.pdf', '.doc', '.docx']):
links.append(href)

print(f"Знайдено {len(links)} посилань Bing.")
return links[:max_results]

except Exception as e:
print(f"Помилка Bing: {e}")
return []

def process_file(file_path, output_dir):
"""Обробка файлу та збереження веб-ресурсів."""
try:
base_name = os.path.basename(file_path)
text = extract_text_from_file(file_path)
if not text:
print(f"Не знайдено тексту у файлі {file_path}")
return

print(f"Обробка файлу: {base_name}...")

resources = search_web_resources(text)
if not resources:
print(f"Не знайдено ресурсів для {base_name}")
return

print(f"Знайдено {len(resources)} ресурсів, перевірка валідності...")

valid_urls = []
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
future_to_url = {executor.submit(is_valid_url, url): url for url in resources}
for future in concurrent.futures.as_completed(future_to_url):
url = future_to_url[future]
try:
if future.result():
valid_urls.append(url)
print(f"✓ Валідний URL: {url}")
else:
print(f"✗ Невалідний URL: {url}")
except Exception as e:
print(f"Помилка перевірки URL {url}: {e}")

if valid_urls:
output_file = os.path.join(output_dir, f"links_{base_name}")
with open(output_file, 'w', encoding='utf-8') as f:
for url in valid_urls:
f.write(f"{url}\n")
print(f"Збережено {len(valid_urls)} валідних URL у {output_file}")
else:
print(f"Не знайдено валідних URL для {base_name}")

except Exception as e:
print(f"Помилка обробки файлу {file_path}: {e}")

def main():
folder_path = input("Введіть шлях до папки з файлами: ").strip()

if not os.path.isdir(folder_path):
print(f"Помилка: {folder_path} не є коректною директорією.")
return

output_dir = os.path.join(folder_path, "links_notes")
if not os.path.exists(output_dir):
os.makedirs(output_dir)
print(f"Створено директорію: {output_dir}")

for filename in os.listdir(folder_path):
file_path = os.path.join(folder_path, filename)
if os.path.isfile(file_path) and not filename.startswith('.') and not os.path.basename(file_path).startswith('links_'):
process_file(file_path, output_dir)
time.sleep(random.uniform(2, 5))

print("Обробку завершено!")

if __name__ == "__main__":
main()