Wczytywanie dokumentów i ekstrakcja tekstu
Uczestnicy wczytają pliki PDF, dokumenty Word i pliki tekstowe za pomocą bibliotek Pythona, oczyszczą wyodrębniony tekst oraz przygotują go do dzielenia na fragmenty i tworzenia embeddingów.
Wczytywanie dokumentów i ekstrakcja tekstu to bezpłatna lekcja AI Engineering Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Engineering Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.
Dlaczego ładowanie dokumentów nie jest trywialne
Pierwszym etapem każdego potoku RAG jest wydobycie surowego tekstu z dokumentów. Brzmi to prosto, ale w praktyce okazuje się zaskakująco trudne. Pliki PDF mogą przechowywać tekst jako znaki, obrazy albo połączenie obu tych form. Dokumenty Word zawierają znaczniki formatowania, które trzeba usunąć. Strony HTML zawierają obok właściwej treści menu nawigacyjne i reklamy. Solidny moduł ładowania musi obsługiwać wszystkie te przypadki i generować czysty, spójny tekst do dzielenia na fragmenty.
Ładowanie plików PDF za pomocą pypdf
pypdf to standardowa biblioteka Python do odczytywania plików PDF zawierających osadzony tekst. Wyodrębnia tekst strona po stronie, zachowując pierwotne granice stron, które są cennymi metadanymi. pypdf nie potrafi jednak odczytywać skanowanych plików PDF (obrazów tekstu) — wymagają one OCR. Zawsze należy wyodrębniać numery stron razem z tekstem, aby można było wskazać dokładną stronę w cytowaniach RAG.
from pypdf import PdfReader
def load_pdf(file_path):
reader = PdfReader(file_path)
pages = []
for page_num, page in enumerate(reader.pages, start=1):
text = page.extract_text()
if text and text.strip(): # skip blank pages
pages.append({
'text': text,
'metadata': {
'source': file_path,
'page': page_num,
'doc_type': 'pdf'
}
})
return pages
docs = load_pdf('annual_report.pdf')
print(f'Loaded {len(docs)} non-empty pages')Ładowanie dokumentów Word za pomocą python-docx
Pliki Microsoft Word (.docx) przechowują treść w formacie XML. Biblioteka python-docx analizuje ten kod XML i udostępnia akapity, tabele oraz nagłówki jako obiekty języka Python. Należy wyodrębniać tekst akapitów w kolejności występowania i zapisywać poziomy nagłówków, aby zachować strukturę dokumentu — nagłówki sekcji są cennym kontekstem, który poprawia jakość dzielenia na fragmenty i wyszukiwania, gdy zostaną dołączone do wprowadzanego przez nie tekstu.
from docx import Document
def load_docx(file_path):
doc = Document(file_path)
sections = []
current_section = {'heading': '', 'text': ''}
for para in doc.paragraphs:
if para.style.name.startswith('Heading'):
if current_section['text'].strip():
sections.append(current_section.copy())
current_section = {'heading': para.text, 'text': ''}
else:
current_section['text'] += para.text + '\n'
if current_section['text'].strip():
sections.append(current_section)
return [{'text': f"{s['heading']}\n{s['text']}",
'metadata': {'source': file_path, 'section': s['heading']}}
for s in sections]Ładowanie stron internetowych i HTML
Strony HTML zawierają dużo szumu: paski nawigacyjne, stopki, banery z prośbą o zgodę na pliki cookie i bloki reklamowe. Należy użyć BeautifulSoup do przeanalizowania kodu HTML i wyodrębnienia wyłącznie głównego obszaru treści. Warto szukać elementów takich jak <article>, <main> lub klas CSS charakterystycznych dla treści. Przed wyodrębnieniem tekstu należy usunąć tagi script, style i nav, aby nie zanieczyszczać fragmentów kodem JavaScript ani elementami menu.
import requests
from bs4 import BeautifulSoup
def load_url(url):
response = requests.get(url, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
# Remove noise elements
for tag in soup(['script', 'style', 'nav', 'footer', 'header', 'aside']):
tag.decompose()
# Try to find main content
main = soup.find('article') or soup.find('main') or soup.find('body')
text = main.get_text(separator='\n', strip=True)
return [{'text': text, 'metadata': {'source': url, 'doc_type': 'html'}}]Obsługa skanowanych plików PDF za pomocą OCR
Zeskanowane pliki PDF przechowują strony jako obrazy bez osadzonego tekstu. Aby wyodrębnić tekst, potrzebują Państwo optycznego rozpoznawania znaków (OCR). Biblioteka pytesseract opakowuje silnik OCR Google Tesseract. OCR działa wolniej i jest mniej dokładny niż ekstrakcja tekstu (na dobrych skanach dokładność rozpoznawania znaków wynosi 80–95%), dlatego zawsze należy wybierać cyfrowe pliki PDF, jeśli są dostępne. Należy zaznaczać w metadanych, że użyto OCR, aby można było sprawdzić ekstrakcje o niskim poziomie pewności.
import pytesseract
from pdf2image import convert_from_path
def load_scanned_pdf(file_path):
# Convert PDF pages to PIL images
pages_as_images = convert_from_path(file_path, dpi=300)
results = []
for page_num, img in enumerate(pages_as_images, start=1):
text = pytesseract.image_to_string(img, lang='eng')
results.append({
'text': text,
'metadata': {
'source': file_path,
'page': page_num,
'ocr': True # flag for quality review
}
})
return resultsUżywanie unstructured dla dowolnego formatu
Biblioteka unstructured jest uniwersalnym narzędziem do wczytywania dokumentów. Obsługuje pliki PDF, Word, Excel, PowerPoint, HTML, wiadomości e-mail i wiele innych formatów, udostępniając ujednolicone API. Wykorzystuje heurystyki do identyfikowania elementów dokumentu (tytułu, tekstu narracyjnego, tabeli, nagłówka) i zwraca je jako ustrukturyzowane obiekty. Jest to szczególnie przydatne, gdy korpus zawiera różne typy dokumentów, a potrzebują Państwo metadanych na poziomie elementów bez pisania parserów zależnych od formatu.
from unstructured.partition.auto import partition
def load_any_document(file_path):
elements = partition(filename=file_path)
docs = []
for element in elements:
docs.append({
'text': str(element),
'metadata': {
'source': file_path,
'element_type': type(element).__name__,
'category': element.category
}
})
return docs
# Works on .pdf, .docx, .pptx, .html, .eml, .xlsx
docs = load_any_document('presentation.pptx')Czyszczenie tekstu po ekstrakcji
Surowy wyodrębniony tekst rzadko jest czysty. Ekstrakcja z plików PDF często powoduje dzielenie wyrazów łącznikiem na końcu wiersza w układach kolumnowych, dodaje nadmiarowe białe znaki, powtarza nagłówki stron na każdej stronie i zniekształca znaki specjalne. Należy zastosować potok czyszczenia: usunąć nadmiarowe białe znaki, połączyć wyrazy podzielone łącznikiem między wierszami, usunąć nagłówki i stopki stron wykryte za pomocą dopasowywania wzorców oraz ujednolicić znaki Unicode. Czysty tekst prowadzi do znacznie lepszej spójności fragmentów.
import re
def clean_text(text):
# Rejoin hyphenated line breaks (PDF column artifacts)
text = re.sub(r'-(\n)([a-z])', r'\2', text)
# Normalize whitespace
text = re.sub(r' +', ' ', text)
text = re.sub(r'\n{3,}', '\n\n', text)
# Remove page numbers standing alone on a line
text = re.sub(r'^\d+$', '', text, flags=re.MULTILINE)
# Strip leading/trailing whitespace from each line
lines = [line.strip() for line in text.split('\n')]
return '\n'.join(lines).strip()Wczytywanie danych z baz danych i interfejsów API
Nie cała wiedza znajduje się w plikach. Źródłami są również wewnętrzne bazy danych, systemy CRM, narzędzia do obsługi zgłoszeń i interfejsy REST API. Ustrukturyzowane wiersze z bazy danych należy wczytywać, łącząc odpowiednie tabele i konkaten 정jąc wartości pól w akapity zapisane językiem naturalnym, które model osadzający może zrozumieć. W przypadku interfejsów API należy pobierać wyniki stronicowane i serializować każdy rekord jako dokument tekstowy z parami klucz–wartość.
import psycopg2
def load_from_database(conn_string, query):
conn = psycopg2.connect(conn_string)
cursor = conn.cursor()
cursor.execute(query)
columns = [desc[0] for desc in cursor.description]
docs = []
for row in cursor.fetchall():
# Convert row to natural language text
parts = [f'{col}: {val}' for col, val in zip(columns, row) if val]
text = '\n'.join(parts)
docs.append({'text': text, 'metadata': {'source': 'database'}})
conn.close()
return docsŚledzenie pochodzenia dokumentów
Każdy wczytany dokument powinien zachowywać metadane pochodzenia w całym potoku: źródłowy adres URL lub ścieżkę pliku, tytuł dokumentu, autora, datę utworzenia i datę ostatniej modyfikacji. Te metadane towarzyszą każdemu fragmentowi w bazie wektorowej i pojawiają się w cytowaniach LLM. Bez informacji o pochodzeniu nie można wskazać użytkownikom źródła odpowiedzi, zaktualizować konkretnych dokumentów w indeksie ani filtrować wyszukiwania według atrybutów źródła.
import os
from datetime import datetime
def load_pdf_with_provenance(file_path):
from pypdf import PdfReader
reader = PdfReader(file_path)
stat = os.stat(file_path)
base_metadata = {
'source': file_path,
'title': reader.metadata.get('/Title', os.path.basename(file_path)),
'author': reader.metadata.get('/Author', 'Unknown'),
'doc_type': 'pdf',
'file_size_kb': stat.st_size // 1024,
'loaded_at': datetime.utcnow().isoformat()
}
pages = []
for i, page in enumerate(reader.pages, 1):
text = page.extract_text()
if text and text.strip():
pages.append({'text': text, 'metadata': {**base_metadata, 'page': i}})
return pagesWczytywanie dużych kolekcji dokumentów partiami
Podczas indeksowania tysięcy dokumentów należy wczytywać je równolegle za pomocą concurrent.futures, aby w pełni wykorzystać zasoby wejścia-wyjścia i procesora. Należy zaimplementować monitorowanie postępu i dziennik błędów, aby nieudane wczytania dokumentów nie powodowały cichego pomijania treści w indeksie. Nie wolno dopuścić, aby pojedynczy uszkodzony plik przerwał całe zadanie wczytywania — należy przechwytywać wyjątki osobno dla każdego dokumentu i przechodzić do następnego.
from concurrent.futures import ThreadPoolExecutor, as_completed
def batch_load_documents(file_paths, max_workers=8):
all_docs = []
errors = []
with ThreadPoolExecutor(max_workers=max_workers) as executor:
future_to_path = {
executor.submit(load_pdf_with_provenance, p): p
for p in file_paths
}
for future in as_completed(future_to_path):
path = future_to_path[future]
try:
docs = future.result()
all_docs.extend(docs)
print(f'Loaded {len(docs)} pages from {path}')
except Exception as e:
errors.append({'path': path, 'error': str(e)})
return all_docs, errorsSprawdzanie jakości wczytanej treści
Po wczytaniu należy sprawdzić, czy wyodrębniono wartościową treść. Należy zweryfikować: minimalną długość tekstu (pomijać fragmenty krótsze niż 50 znaków), wykrywanie języka (jeśli system RAG działa wyłącznie w języku angielskim, odfiltrować strony w innych językach) oraz wykrywanie zniekształconego tekstu (duży udział znaków spoza ASCII może wskazywać na nieudaną operację OCR lub problemy z kodowaniem). Należy rejestrować statystyki, takie jak liczba wczytanych stron, średnia długość strony i współczynnik błędów, aby wcześnie wykrywać problemy z wczytywaniem.
def validate_documents(docs, min_length=100):
valid = []
skipped = 0
for doc in docs:
text = doc['text']
if len(text) < min_length:
skipped += 1
continue
# Check for high non-ASCII ratio (garbled OCR)
non_ascii = sum(1 for c in text if ord(c) > 127)
if non_ascii / max(len(text), 1) > 0.3:
skipped += 1
continue
valid.append(doc)
print(f'Valid: {len(valid)}, Skipped: {skipped}')
return validSzybki test
Sprawdź swoją wiedzę na temat koncepcji inżynierii AI z tej lekcji.
Podsumowanie lekcji
W tej lekcji poznali Państwo: loadery zależne od formatu dla plików PDF z użyciem pypdf, dokumentów Word z użyciem python-docx, kodu HTML z użyciem BeautifulSoup oraz zeskanowanych dokumentów z użyciem OCR, bibliotekę unstructured jako ujednolicony loader obsługujący wiele formatów, a także najlepsze praktyki produkcyjne, w tym czyszczenie tekstu, metadane pochodzenia, równoległe wczytywanie partiami i walidację treści. W następnej części omówimy strategie dzielenia na fragmenty, które określają sposób mapowania pobranego tekstu na kontekst modelu.
Ucz się Python dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 30
- Lekcje
- 120
Często zadawane pytania
Czy lekcja „Wczytywanie dokumentów i ekstrakcja tekstu” jest bezpłatna?
Tak — pełny tekst „Wczytywanie dokumentów i ekstrakcja tekstu” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Engineering Academy, przejdź na CoddyKit PRO. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Wczytywanie dokumentów i ekstrakcja tekstu”?
Uczestnicy wczytają pliki PDF, dokumenty Word i pliki tekstowe za pomocą bibliotek Pythona, oczyszczą wyodrębniony tekst oraz przygotują go do dzielenia na fragmenty i tworzenia embeddingów. Ćwiczysz AI Engineering Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć AI Engineering Academy?
Nie wymagamy żadnego doświadczenia. AI Engineering Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.
Ile czasu zajmuje lekcja „Wczytywanie dokumentów i ekstrakcja tekstu”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji AI Engineering Academy?
Tak. Każda lekcja AI Engineering Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Wczytywanie dokumentów i ekstrakcja tekstu
- Strategie dzielenia tekstu: stały rozmiar, zdania i rekurencja
- Indeksowanie: tworzenie embeddingów i przechowywanie fragmentów
- Zapytanie, pobieranie i generowanie