Seperti yang anda akan lihat dalam catatan blog akan datang, saya berada dalam era celik kewangan saya. Dengan penghujung tahun yang akan datang, saya ingin melihat nombor saya: Berapa banyak cukai yang saya bayar? Berapakah pendapatan saya untuk syif atas panggilan? Berbilang fail PDF bukanlah cara yang paling selesa untuk melihat data ini dan saya mahukan satu fail CSV yang boleh saya mainkan dalam Excel.
Seperti kebanyakan pembangun yang baik, saya terlalu malas untuk memasukkan nombor secara manual, jadi saya menulis skrip. Jika anda menikmati pengaturcaraan — sertai saya dalam pengembaraan! Dan jika anda tiada mood — saya akan tunjukkan kepada anda cara mengubah suai kod agar sepadan dengan struktur slip gaji anda :D
This script receives a directory with payslip PDFs and returns a CSV file with the desired data |
main.py: # translate 1 pdf to 1 dict # loop over the pdf dir # save all dicts to 1 json file # translate json report to csv report
Kami akan bermula dengan menulis kod untuk membaca PDF, termasuk menentukan medan yang kami mahu dalam laporan kami. Ini adalah bahagian yang anda perlu ubah suai untuk memadankan struktur slip gaji anda. Setelah itu diketahui, kami akan mengulangi keseluruhan direktori slip gaji.
Dalam langkah ketiga, saya memilih untuk menambah langkah tambahan antara PDF dan CSV — laporan JSON. Sebaik sahaja kami melihat semuanya berfungsi, kami akan mengalih keluar penggunaan fail itu.
Akhir sekali, kami akan menterjemah data JSON itu ke dalam fail CSV. CSV itu kemudiannya boleh ditukar dengan mudah kepada Helaian Google (hanya klik "buka dengan") atau kepada Excel (arahan boleh didapati di sini).
Itu pelan bagus yang mudah, tetapi anda tahu bagaimana ia berjalan — cabaran ditemui sepanjang perjalanan... Bolehkah anda meneka di mana keadaan mungkin menjadi rumit?
Sebelum kita mula — nota penting: PASTIKAN SLIP GAJI ANDA SWASTA! Jika anda memuat naik projek anda ke GitHub — pastikan anda tidak berkongsi butiran peribadi tersebut! Anda boleh menggunakan .gitignore untuk ini:
/payslips_pdf pdf_rows.txt report.json report.csv
Bolehkah kita mulakan?
Kami akan mulakan dengan membaca PDF dan mencetak semua baris. Dengan cara itu kita akan tahu apa yang muncul dalam setiap baris. Ini hanya perlu dilakukan sekali (manakala laporan mungkin akan dibuat sebulan sekali atau setahun sekali), dan ia bukan sebahagian daripada laporan -jadi kami akan menciptanya dalam fail yang berasingan.
Mulakan dengan mencipta fail Python baharu (saya memanggil saya pdf_to_txt.py) dan tulis fungsi yang membaca pdf dan mencetak hasilnya ke dalam fail .txt:
Kami akan membaca fail PDF dalam skrip utama juga, jadi mengalihkan fungsi ini ke sana adalah lebih baik.
Sekarang kita tahu struktur di mana PDF dibaca — kita boleh menangkap nilai yang diingini. Dalam kes saya — berikut ialah maklumat yang saya minati:
Perhatikan terdapat data dalam jadual (kategori yang mungkin berbeza setiap bulan) dan data di luar jadual.
Data di luar jadual:
Tempoh Gaji — Boleh didapati di baris 19
Bayar Kasar — Yang ini sukar untuk mencari peraturan kerana peraturan itu muncul selepas senarai pembayaran dan tidak mempunyai tajuk "Bayar Kasar".
Seperti yang dinyatakan sebelum ini, bayaran dan potongan boleh berbeza-beza, dan tidak setiap bulan adalah sama. Oleh itu, gaji kasar mungkin muncul dalam baris yang berbeza pada bulan yang berbeza.
Saya perasan ia muncul sejurus selepas nama pekerja — jadi itulah yang saya gunakan. Mulakan dengan menambahkannya berkod keras, dan kemudian kami akan mendapatkannya secara luaran.
Bayar Bersih: Yang ini mudah — ia muncul dalam baris 17.
Saya mengumpulkan nilai luar jadual tersebut ke dalam fungsi:
Butiran Pembayaran dan Potongan: Ini adalah bahagian yang menarik! Kita akan mulakan dengan memotong tatasusunan baris untuk menjimatkan beberapa milisaat dalam gelung for yang akan datang. Kemudian, saya perlu membezakan antara item senarai
dan baris lain.
Saya perhatikan bahawa dalam keseluruhan fail, item senarai adalah satu-satunya item yang sepadan dengan peraturan ini: Mulakan dengan aksara abjad dan berakhir dengan aksara angka dan mengandungi ruang (syarat terakhir ialah menapis baris yang salah dalam saya
slip gaji, anda mungkin tidak memerlukannya).
Sebagai contoh, kita akan melihat item pencen:
main.py: # translate 1 pdf to 1 dict # loop over the pdf dir # save all dicts to 1 json file # translate json report to csv report
Saya tidak kisah tentang baki (nombor di sebelah kanan), tetapi saya mengambil berat tentang kod tersebut (G bermakna ia ditolak daripada gaji Kasar — sebelum cukai — dan N bermakna ia ditolak daripada gaji Bersih — selepas cukai). Jadi idealnya, kita akan mempunyai json_obj["Pencen (G)"]=150.00.
Kami akan menggunakan ruang untuk membelah garisan. Ada baiknya terdapat ruang pendua — dengan cara itu kita boleh membezakan antara pemisahan ruang antara beberapa perkataan dan pemisahan ruang antara beberapa medan.
Penerangan:
Kami akan mencari ruang berkembar pertama dan dibelah olehnya.
Kod:
Jumlah ruang bergantung pada panjang perihalan, jadi kami tidak dapat mengetahui terlebih dahulu jumlah ruang — itulah sebabnya saya akan menggunakan lstrip() juga. Kini selebihnya baris bermula dengan aksara bukan ruang.
Bukan semua item senarai mempunyai kod, jadi kami ingin menyemak sama ada baris itu bermula dengan kod atau digit. Jika ia adalah kod — saya membungkusnya dalam () (termasuk ruang sebelum kurungan pembukaan) , dan melampirkannya pada rentetan penerangan. dan jika tidak — tambahkan apa-apa.
Jumlah:
Jika ada kod — kami akan mempunyai lebih banyak ruang untuk ditanggalkan. Jika tidak, talian kami mungkin mengandungi dua amaun: Bulanan dan baki.
Terdapat 4 kes yang saya perhatikan:
/payslips_pdf pdf_rows.txt report.json report.csv
Selepas mengekstrak kategori dan kod, kami tinggal dengan:
PENSION G 150.00 587.49
Untuk menampung kes 2–3, kami akan mencari indeks ruang yang memisahkan jumlah dan memotong ekor. Ia juga berfungsi untuk kes pertama, di mana tiada ruang (aka tiada ekor).
Untuk menampung kes 4, saya bergantung pada perbezaan antara dua jenis kategori dengan amaun tunggal dalam baris: Yang pertama adalah seperti gaji — di mana kita ingin menyimpan amaun itu, dan jenis kedua adalah seperti penahanan cukai — di mana kita mahu mengabaikannya. Perbezaannya ialah hanya potongan yang menjejaki baki tahunan dalam jadual — jadi saya sedang menyemak -.
Semua bersama-sama, begitulah rupanya:
Ini bukan langkah wajib — kita boleh bekerja dengan objek JSON tanpa mengeksport nilai. Saya lebih suka melihat rupanya, sekurang-kurangnya untuk peringkat pengekodan.
Skalakan kepada Berbilang Fail PDF
Pada asalnya, saya fikir saya perlu menamakan semula fail (Payslip1.pdf -> Payslip01.pdf), tetapi ada penyelesaian yang lebih baik:
Oleh kerana item dalam pembayaran dan potongan mungkin berbeza dari slip gaji ke slip gaji, bahagian ini lebih daripada terjemahan langsung. CSV ialah set data hubungan, yang bermaksud kita perlu mengetahui terlebih dahulu semua kategori dalam pembayaran dan potongan dan memastikan kemasukan itu kosong untuk slip gaji yang tidak wujud. JSON, sebaliknya, tidak berkaitan dan setiap entri menyatakan kuncinya.
Dengan itu, langkah pertama dalam laporan CSV kami ialah mengumpulkan kategori. Semua kategori.
Kumpulkan kategori:
Sekarang, pada pandangan pertama, anda mungkin terfikir untuk menggunakan Set untuk itu — kerana kami mahu semua kategori muncul sekali sahaja. Saya telah mencuba itu. Masalahnya ialah set tidak tersenarai, dan saya rasa penting untuk memadankan susunan item yang muncul dalam slip gaji asal. Apabila menggunakan senarai, jangan lupa untuk menyemak sama ada item itu wujud dalam senarai sebelum menambahkannya:
perlu
berpisah, tetapi saya menjangkakan laporan slip gaji mempunyai semua pembayaran di sebelah kanan dan semua potongan di sebelah kiri, tidak bercampur.
Akhir sekali, saya mengembalikan satu senarai, kerana tidak ada gunanya mengasingkan pembayaran daripada potongan — perpecahan itu adalah untuk memastikan pembayaran akan muncul di sebelah kanan dan potongan akan muncul di sebelah kiri.
Isi jadual CSV:
Sekarang kita mempunyai kategori, kita boleh mula mengisi jadual CSV:
Anda boleh menjadikannya lebih mudah untuk dibaca dengan memuat turun sambungan VS RainbowCSV (atau mana-mana selari dengan IDE lain)
Setelah kami mengetahui perkara berfungsi, kami tidak perlu menulis dan membaca daripada fail JSON — kami boleh menggunakan objek JSON secara langsung:
Daripada menggunakan json_object (seperti dalam json_object = json.dumps(json_payslips)) – kami akan menggunakan json_payslips secara langsung:
Tulis: Tidak perlu menulis untuk melaporkan.json - kami boleh mengalih keluar bahagian ini.
Baca: Hantar json_payslips terus ke fungsi json_to_csv():
Setelah anda menyediakan skrip anda — anda pasti mahu berkongsi dengan rakan sekerja dan rakan anda! Untuk pengalaman pengguna yang bagus, kami akan mengeksport nama pekerja untuk datang daripada baris arahan, dan bukannya meminta mereka membuka kod.
Baca hujah
Kami akan bermula dengan laluan gembira — dengan andaian pengguna memasukkan nama pekerja — dan tambah kod yang menggunakannya:
Dalam pdf_to_dict(), bukannya pengekodan keras EMPLOYEE_NAME = "IFAT NEUMANN", kami akan membacanya daripada hujah: employee_name = sys.argv[1]. Jangan lupa import sys!
Sekarang kita akan memikirkan senario lain:
Tiada nama pekerja diberikan
Bagaimana jika pengguna tidak memasukkan sebarang nama pekerja? Kami ingin menangkapnya secepat mungkin dan memberitahu mereka!
Oleh itu, kami akan menambah semakan dalam baris pertama fungsi utama. Sekarang, gerak hati adalah untuk memulakan pembolehubah nama_pekerja di sana - tetapi ini akan menyebabkan sifat fungsi menggelegak sehingga ia mencapai fungsi yang menggunakan pembolehubah ini - dan saya tidak mendapati pendekatan itu sangat bersih.
Akhir sekali, saya hanya akan cuba mengakses medan ini — dan tangkap jika ia tiada:
main.py: # translate 1 pdf to 1 dict # loop over the pdf dir # save all dicts to 1 json file # translate json report to csv report
Ambil perhatian bahawa menambah pengecualian bermakna fungsi print_warning() berpindah ke main.py. Jika tidak, anda akan mendapat ralat:
Nama pekerja tanpa petikan
Anda boleh melangkau keperluan petikan dan mengulangi argumen, mengumpulkan semua bahagian nama pengguna — tetapi saya dapati pendekatan ini menambahkan kerumitan yang tidak perlu.
Nama pekerja tidak tertera pada slip gaji
Kami tidak akan dapat mencari gaji kasar jika kami tidak mempunyai nama pekerja seperti yang tertera pada slip gaji.
Akhir sekali, kami menangkap semula ralat dalam fungsi utama:
Berikut ialah kod penuh yang boleh anda gunakan untuk bermain dengan slip gaji anda:
https://cupofcode.blog/ |
Atas ialah kandungan terperinci Pengekodan Hujung Minggu: Tukar Slip Gaji PDF Menjadi Laporan CSV Tunggal. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!