Python İle PDF İçerisinden Metin Kazımak
PyPDF2 ve Tabula Kullanım Örnekleri
Bir süredir tahmin (forecasting) çalışmaları için çeşitli çözümleri deniyor, süreci ve yöntemleri anlamaya çalışıyorum. Bunlardan biri de Facebook tarafından geliştirilen, kolay bir şekilde R ve Python programlama dilleri ile kullanabilen Prophet prosedürü oldu.
Prophet, ile ilgili işlemlerde kolay bir şekilde özelleştirmeler yapılabiliyor. Mevsimsellik ve tatil etkilerini modele ayrıca dahil etmek mümkün1. Bu amaçla, prophet ile ilgili çalışma yaparken resmi tatilleri de sürece dahil etmek istedim. Kullandığım veri seti 2017-2021 yıllarını kapsadığı için bu yıllar arasındaki tatil günlerini bulmaya çalışırken 2014-2022 yılları arasındaki resmi tatil günlerinin yer aldığı bir PDF dosyasına ulaştım2.
PDF içerisinden metin kazıma ile ilgili paketleri bir süredir incelemek istiyordum. Güzel bir fırsat elde etmiş oldum.
İlgili PDF dosyası 2 sayfa ve toplamda her yıl için 1 adet olmak üzere 9 tablodan oluşmakta. Aşağıdaki görselde de görüldüğü üzere her tablo başlık, 2 sütun ve 16 satırdan oluşmakta. Tarih bilgileri tabloların solunda yer almakta.

Python ve PDF Dosyasından Metin Kazıma İşlemi
Python programlama dili PDF okuma-yazma işlemleri ile ilgili olarak PDFMiner, PyPDF2, Tabula-py, Slate, PDFQuery ve xpdf gibi pek çok popüler pakete sahip3. Bu paketlerden PDFMiner artık pdfminer.six forku üzerinden geliştirilmekte. Seçenekler arasında PyPDF24 ve tabular5 popülerlikleri ile öne çıktıkları için her iki paketi de denemeye karar verdim.
PyPDF2
Python ile PDF dosyalarını okumak ve yazmak için geliştirilen bir yardımcı paket/uygulama olan PyPDF2 esasında 2 011 yılından bu yana geliştirilen bir pyPdf forku.
PdfFileReader
sınıfına ait stream
parametresine verilen bir file nesnesi veya bir file nesnesine benzer bir nesnesinin yanı sıra bir PDF dosyasının yolunu temsil eden bir path değeri ile işlemler gerçekleştirilebilmesini sağlamakta6.
Hemen örnek işlemimize geçelim.
#!pip install PyPDF2
import urllib.request, io, PyPDF2
import pandas as pd
url = "https://fenbil.aku.edu.tr/FENBILENS/takvim/2014-2022-1RESMI.pdf"
remoteFile = urllib.request.urlopen(url)
pdfReader = PyPDF2.PdfFileReader(io.BytesIO(remoteFile.read()))
Artık pdfReader
'ın sahip olduğu method ve property'lerden faydalanabiliriz. pdfReader.numPages
bize PDF dosyasına ait sayfa sayısını verecektir. Her sayfa için metin kazıma işlemi ayr ayrı gerçekleştirileceği için sayfa sayısını loop için kullanabiliriz. Örneğin, ilk sayfada yer alan metinlere pdfReader.getPage(0).extractText()
şeklinde ulaşabiliriz.
Sonraki işlemlerde kullanmak üzere metinleri bir metin dosyasına alalım.
for i in range(pdfReader.numPages):
with open('pdf.txt', 'a+') as file:
file.write(pdfReader.getPage(i).extractText())
Metin dosyasında da görüldüğü üzere pek çok boşluk ve tablo alanları içerisinde kaymalar mevcut.
df = pd.read_csv('/content/pdf.txt', delimiter = "\n", names=['date'])
df.head()
Açıkçası çok istediğim gibi olmadı. Sütunlar arasındaki kaymalar ve bazı verilerin kazınamamış olması sebebiyle bir başka paketi daha denemeye karar verdim.
date
0 01 Ocak 2016 Cuma
1 23 Nisan 2016 Cumartesi
2 27 Temmuz 2014 Pazar
3 Arefe
4 04 Temmuz 2016 Pazartesi
5 28 Temmuz 2014 Pazartesi
6 17 Temmuz 2015 Cuma
7 18 Temmuz 2015 Cumartesi
8 19 Temmuz 2015 Pazar
9 03 Ekim 2014 Cuma
10 Arefe
...
İlgili kod parçacığına tek parça olarak Python-PyPDF2.py üzerinden ulaşabilirsiniz.
Tabula.py
Java 8+ ve Python 3.6+ gerektirmekte. Verilerin CSV, TSV, JSON gibi formatlara aktarılabilmesini sağlayan, bunun yanı sıra tabloları pandas DataFrame olarak sunabilen Tabula dosya yolu olarak URL de alabilmekte7.
Hemen örneğimize geçelim.
Döngüyü çok daha uygun bir şekilde ele alana kadar nested loop örneği paylaştım. (16, 3)'lük shape'e sahip 3 tabloyu tek bir listeye dönüştürmek beklediğimden daha uğraştırıcı oldu (: Kodun bir önceki revision ve yorum olarak gist sayfasında yer almakta.
İlgili kod parçacığına tek parça olarak Python-Tabula.py üzerinden ulaşabilirsiniz.
0 2014-01-01
1 2014-04-23
2 2014-05-01
3 2014-05-19
4 2014-07-27
...
139 2022-07-11
140 2022-07-12
141 2022-08-30
142 2022-10-28
143 2022-10-29
Name: Date, Length: 144, dtype: datetime64[ns]
Bu işlemin neticesinde 144 kayıttan oluşan tatil bilgisini doğru bir şekilde elde etmiş olduk.
m = Prophet(holidays=holidays)
forecast = m.fit(df).predict(future)
Bir sonraki yazıda Prophet ile ilgili notlarımı aktarmaya çalışacağım.