Beranda BlogPengikisan web Pembersihan Data 101: Hapus Tag dengan BeautifulSoup

Pembersihan Data 101: Hapus Tag dengan BeautifulSoup

oleh Kadek

Membersihkan data kotor dan menangani kasus edge

Data yang diambil dari Internet sering kali tidak konsisten atau tidak lengkap, sehingga menimbulkan tantangan dalam sebagian besar proyek scraping. Bagian ini menjelaskan strategi untuk menangani kasus-kasus khusus tersebut, termasuk data yang hilang, format data yang berbeda, dan entri duplikat.

Berikut beberapa strategi untuk menangani kasus edge

  • Coba/Kecuali – Berguna untuk menangani kesalahan dengan baik.
  • Penguraian bersyarat – Menerapkan logika kondisional untuk menganalisis data secara berbeda berdasarkan strukturnya.
  • Kelas data – Gunakan kelas data Python untuk menyusun data Anda agar pembersihan dan manipulasi menjadi lebih mudah.
  • Saluran data – Menerapkan saluran data untuk membersihkan, memvalidasi, dan mengubah data sebelum disimpan.
  • Pembersihan selama analisis data – Lakukan pembersihan data sebagai bagian dari proses analisis data Anda.

Menerapkan kelas data untuk data terstruktur

Di bagian ini, kami menggunakan kelas data untuk menyusun data sisa kami guna memastikan konsistensi dan kemudahan manipulasi.

Sebelum kami membersihkan dan memproses data, kami menentukan impor yang diperlukan dari dataclasses Modul dan atur milik kita Product Kelas data. Kelas ini berfungsi sebagai cetak biru untuk menyusun data produk kami yang telah di-crack.

	from dataclasses import dataclass, field, InitVar

	@dataclass
	class Product:
		name: str = ""
		price: InitVar(str) = ""
		url: str = ""
		price_gbp: float = field(init=False)
		price_usd: float = field(init=False)
	
		def __post_init__(self, price):
			self.url = self.normalize_url()
			self.price_gbp = self.clean_price(price)
			self.price_usd = self.price_to_usd()

Di sini kita mengimpor dataclass, fieldDan InitVar dari itu dataclasses Modul. Itu @dataclass Dekorator secara otomatis menambahkan metode khusus ke dalamnya Product kelas, seperti __init__ Dan __repr__berdasarkan atribut kelasnya.

Kelas produk didefinisikan dengan beberapa atribut:

  • Nama belakang: String yang mewakili nama produk.
  • Harga: Variabel inisialisasi (InitVar), yang berisi harga sebagai string. Atribut ini tidak termasuk dalam kelas __init__ metode dan digunakan untuk pengolahan sebelum dibuang.
  • URL (URL): String yang mewakili URL produk.
  • Harga_GBP: Float yang mewakili harga produk dalam GBP. Atribut ini tidak termasuk dalam kelas __init__ metode dan diatur selama inisialisasi (init=False).
  • Harga (Rp: Float yang mewakili harga produk dalam USD. Bagaimana price_gbpatribut ini tidak termasuk dalam kelas __init__ Metode dan diatur selama inisialisasi.

Penyiapan ini memberikan cara terstruktur untuk mengelola data produk, termasuk pembersihan dan konversi harga, normalisasi URL, dan banyak lagi.

Langkah selanjutnya mencakup penerapan metode di dalam Product kelas untuk melakukan operasi ini.

Bersihkan harganya

Dengan kami Product Setelah kelas data ditentukan, langkah selanjutnya adalah menerapkan metode untuk membersihkan data harga. Kami membersihkan string harga dengan menghapus karakter yang tidak perlu seperti simbol mata uang (“£”) dan indikator harga jual (“Harga jual£”, “Harga jualDari £”).

Tentukan metode clean_price dalam Product Kelas yang mengambil string harga, menghapus semua karakter non-numerik, dan mengembalikan harga yang telah disanitasi sebagai float.

	def clean_price(self, price_string: str):
    price_string = price_string.strip()
    price_string = price_string.replace("Sale price£", "")
    price_string = price_string.replace("Sale priceFrom £", "")
    price_string = price_string.replace("£", "")
    if price_string == "":
        return 0.0
    return float(price_string)

  • Metode ini pertama-tama menghilangkan spasi di awal atau akhir dari string harga
  • Semua contoh “Harga Jual£” dan “Harga JualDari £” kemudian dihapus dari string
  • Simbol “£” kemudian akan dihapus.

Jika string yang dihasilkan kosong, “0,0” dikembalikan, menunjukkan bahwa harga tidak ada atau tidak tersedia. Jika tidak, string yang dibersihkan akan diubah menjadi float dan dikembalikan.

Konversikan harganya

Setelah kami membersihkan harga, kami perlu mengonversikannya dari GBP ke USD untuk menstandarkan mata uang di seluruh kumpulan data kami, terutama saat menangani data internasional.

	def price_to_usd(self):
    return self.price_gbp * 1.28

Metode ini mengalikan harga GBP yang disesuaikan dengan kurs konversi (1.28 dalam contoh ini) untuk menghitung harga dalam USD. Nilai konversi ini dapat diperbarui secara dinamis berdasarkan nilai tukar saat ini.

Normalisasikan URL

Kasus umum lainnya saat mengambil data adalah format URL yang tidak konsisten. Beberapa URL dapat berupa jalur relatif sementara yang lain merupakan URL absolut. Normalisasi URL memastikan bahwa URL diformat secara konsisten, sehingga lebih mudah digunakan.

Kita akan mendefinisikan a normalize_url metode di dalam Product Kelas yang memeriksa apakah URL dimulai dengan http:// atau https://. Jika tidak, maka diberi “awalan”http://example.com“ ke URL.

	def normalize_url(self):
    if self.url == "":
        return "missing"
    if not self.url.startswith("http://") and not self.url.startswith("https://"):
        return "http://example.com" + self.url
    return self.url

  • Cara ini pertama-tama memeriksa apakah URL tersebut kosong. Jika hal ini terjadi, “hilang” dikembalikan.
  • Ia kemudian memeriksa apakah URL tidak dimulai dengan “http://” atau “https://”.
  • Dalam hal ini, URL diawali dengan “http://example.com” untuk memastikan formatnya valid.
  • Jika URL sudah diawali dengan "http://" atau "https://", URL dikembalikan tanpa perubahan.

Uji kelas data produk

Terakhir, uji kelas data Produk dengan beberapa data sampel.

	# Sample scraped data
	scraped_products = (
		{"name": "Delicious Chocolate", "price": "Sale priceFrom £1.99", "url": "/delicious-chocolate"},
		{"name": "Yummy Cookies", "price": "£2.50", "url": "http://example.com/yummy-cookies"},
		{"name": "Tasty Candy", "price": "Sale price£0.99", "url": "/apple-pies"}
	)
	
	# Process and clean the data
	processed_products = (Product(name=product("name"), price=product("price"), url=product("url")) for product in scraped_products)
	
	# Display the processed products
	for product in processed_products:
		print(f"Name: {product.name}, GBP_Price: £{product.price_gbp}, USD_Price: ${product.price_usd}, URL: {product.url}")

Kode ini membuat daftar kamus yang mewakili beberapa data produk yang diekstrak. Ia kemudian mengulangi daftar ini dan membuat a Product Contoh untuk setiap kamus dan tambahkan ke processed_products Daftar.

Akhirnya itu mengulangi processed_products Cantumkan dan cetak nama, harga GBP, harga USD dan URL masing-masing produk.

	Name: Delicious Chocolate, GBP_Price: £1.99,  USD_Price: $2.5472,URL: http://example.com/delicious-chocolate
	Name: Yummy Cookies, GBP_Price: £2.5,  USD_Price: $3.2,URL: http://example.com/yummy-cookies
	Name: Tasty Candy, GBP_Price: £0.99,  USD_Price: $1.2672,URL: http://example.com/apple-pies

Tindakan ini memverifikasi bahwa kelas data produk membersihkan dan memproses data yang dihapus dengan benar.

Kode kelas data lengkap

Berikut kode lengkapnya Product Contoh kelas data.

	from dataclasses import dataclass, field, InitVar

	@dataclass
	class Product:
		name: str = ""
		price: InitVar(str) = ""
		url: str = ""
		price_gbp: float = field(init=False)
		price_usd: float = field(init=False)
	
		def __post_init__(self, price):
			self.url = self.normalize_url()
			self.price_gbp = self.clean_price(price)
			self.price_usd = self.price_to_usd()
	
	
		def clean_price(self, price_string: str):
			price_string = price_string.strip()
			price_string = price_string.replace("Sale price£", "")
			price_string = price_string.replace("Sale priceFrom £", "")
			price_string = price_string.replace("£", "")
			if price_string == "":
				return 0.0
			return float(price_string)
		
		def normalize_url(self):
		  if self.url == "":
				return "missing"
		  if not self.url.startswith("http://") and not self.url.startswith("https://"):
				return "http://example.com" + self.url
		  return self.url
		
		def price_to_usd(self):
			return self.price_gbp * 1.28
	
	# Sample scraped data
	sample_products = (
		{'name': 'Artisanal Chocolate', 'price': 'Sale price£2.99', 'url': '/artisanal-chocolate'},
		{'name': 'Gourmet Cookies', 'price': '£5.50', 'url': 'http://example.com/gourmet-cookies'},
		{'name': 'Artisanal Chocolate', 'price': 'Sale price£2.99', 'url': '/artisanal-chocolate'},
		{"name": "Delicious Chocolate", "price": "Sale priceFrom £1.99", "url": "/delicious-chocolate"},
		{"name": "Yummy Cookies", "price": "£2.50", "url": "http://example.com/yummy-cookies"},
		{"name": "Tasty Candy", "price": "Sale price£0.99", "url": "/apple-pies"}
	)
	
	
	# Process and clean the data
	processed_products = ()
	for product in scraped_products:
		prod = Product(name=product("name"),
					   price=product("price"),
					   url=product("url"))
		processed_products.append(prod)
	
	# Display the processed products
	for product in processed_products:
		print(f"Name: {product.name}, GBP_Price: £{product.price_gbp},  USD_Price: ${product.price_usd},URL: {product.url}")

Memproses dan menyimpan data yang tergores dengan saluran data

Setelah membersihkan data menggunakan pendekatan terstruktur Kelas Data Produk, kami melanjutkan ke langkah penting berikutnya: memproses dan menyimpan data ini secara efisien.

Pada fase ini, pipeline data memainkan peran sentral, memungkinkan kita memproses data secara sistematis sebelum menyimpannya. Operasi dalam saluran data kami meliputi:

  • Cek duplikat: Periksa apakah suatu elemen sudah ada dalam kumpulan data untuk menghindari redundansi.
  • Manajemen antrian data: Menyimpan sementara data yang diproses sebelum menyimpan dan mengelola aliran dan volume.
  • Penyimpanan data berkala: Menyimpan data ke file CSV secara berkala atau berdasarkan pemicu tertentu.

Menyiapkan kelas ProductDataPipeline

Pertama mari kita definisikan struktur kita ProductDataPipeline Kelas, dengan penekanan pada inisialisasi dan metode dasar yang mendukung operasi di atas:

	import csv
	from dataclasses import asdict, fields
	
	class ProductDataPipeline:
		def __init__(self, csv_filename='product_data.csv', storage_queue_limit=10):
			self.names_seen = set()
			self.storage_queue = ()
			self.storage_queue_limit = storage_queue_limit
			self.csv_filename = csv_filename
			self.csv_file_open = False
	
		def save_to_csv(self):
			pass
		
		def clean_raw_product(self, scraped_data):
			pass
		
		def is_duplicate(self, product_data):
			pass
		
		def add_product(self, scraped_data):
			pass
		
		def close_pipeline(self):
			pass

Itu __init__ Metode ini menyiapkan kondisi awal, termasuk kumpulan untuk melacak nama produk yang terlihat (untuk memeriksa duplikat), antrean untuk menyimpan produk sementara, dan konfigurasi untuk keluaran file CSV.

Bersihkan data produk mentah

Sebelum suatu produk dapat ditambahkan ke antrean pemrosesan kami, produk tersebut harus dibersihkan dan disusun terlebih dahulu. Itu clean_raw_product Metode ini mencapai hal ini dengan mengubah data mentah yang tergores menjadi sebuah instance Product Kelas data untuk memastikan bahwa data kami sesuai dengan struktur dan tipe yang diharapkan.

	def clean_raw_product(self, scraped_data):
    cleaned_data = {
        "name": scraped_data.get("name", ""),
        "price": scraped_data.get("price", ""),
        "url": scraped_data.get("url", "")
    }
    return Product(**cleaned_data)

Setelah data produk mentah dibersihkan, data tersebut harus diperiksa apakah ada duplikatnya dan, jika unik, ditambahkan ke antrean pemrosesan. Ini dikelola oleh add_product Dan is_duplicate metode atau

Tambahkan produk dan periksa duplikatnya

Itu is_duplicate() Fungsi memeriksa apakah suatu produk sudah ada di names_seen Daftar. Jika ya, pesan akan dicetak dan dikembalikan True, menunjukkan bahwa produk tersebut adalah duplikat. Jika tidak, nama produk ditambahkan names_seen daftar dan kembali False.

	def is_duplicate(self, product_data):
    if product_data.name in self.names_seen:
        print(f"Duplicate item found: {product_data.name}. Item dropped.")
        return True
    self.names_seen.add(product_data.name)
    return False

Itu add_product Metode ini pertama-tama membersihkan data yang dihapus dan membuat a Product Obyek. Ia kemudian memeriksa apakah produk tersebut duplikat is_duplicate Metode. Jika bukan duplikat, produk akan ditambahkan ke dalamnya storage_queue. Terakhir, ia memeriksa apakah antrean penyimpanan telah mencapai batasnya dan, jika ya, akan memanggilnya save_to_csv Metode untuk menyimpan produk dalam file CSV.

	def add_product(self, scraped_data):
    product = self.clean_raw_product(scraped_data)
    if not self.is_duplicate(product):
        self.storage_queue.append(product)
        if len(self.storage_queue) >= self.storage_queue_limit:
            self.save_to_csv()

Penyimpanan data secara teratur dalam format CSV

Itu save_to_csv Metode ini diaktifkan ketika antrean penyimpanan mencapai batasnya atau ketika alur ditutup, sehingga memastikan persistensi data.

	def save_to_csv(self):
    if not self.storage_queue:
        return
    
    self.csv_file_open = True
    with open(self.csv_filename, mode='a', newline='', encoding='utf-8') as csvfile:
        writer = csv.DictWriter(csvfile, fieldnames=(field.name for field in fields(self.storage_queue(0))))
        if csvfile.tell() == 0:
            writer.writeheader()
        for product in self.storage_queue:
            writer.writerow(asdict(product))
    self.storage_queue.clear()
    self.csv_file_open = False

Itu save_to_csv Metode ini dirancang untuk dieksekusi ketika antrian memori tidak kosong. Ini menandai file CSV sebagai terbuka (untuk mengelola akses bersamaan), kemudian mengulangi setiap produk dalam antrian dan membuat cerita bersambung ke dalam kamus (menggunakan asdict) dan tulis ke file CSV.

File CSV terbuka dalam mode penambahan (a), yang memungkinkan data ditambahkan tanpa menimpa informasi yang sudah ada. Metode ini memeriksa apakah file telah dibuat ulang dan menulis header kolom yang sesuai.

Setelah menyimpan produk yang antri, antrean dikosongkan dan file CSV ditandai sebagai ditutup, siap untuk kumpulan data berikutnya.

Menutup pipa

Dipastikan tidak ada data yang belum disimpan close_pipeline Metode ini menangani aliran data akhir ke dalam file CSV.

	def close_pipeline(self):
    if self.storage_queue:
        self.save_to_csv()

Menguji saluran data

Untuk menunjukkan keefektifan kami ProductDataPipelineMari kita simulasikan proses penambahan beberapa produk, termasuk duplikat, untuk melihat bagaimana saluran kami mengelola pembersihan data, deteksi duplikat, dan penyimpanan CSV.

	data_pipeline = ProductDataPipeline(csv_filename='product_data.csv', storage_queue_limit=3)

	# Sample scraped data to add to our pipeline
	sample_products = (
		{'name': 'Artisanal Chocolate', 'price': 'Sale price£2.99', 'url': '/artisanal-chocolate'},
		{'name': 'Gourmet Cookies', 'price': '£5.50', 'url': 'http://example.com/gourmet-cookies'},
		{'name': 'Artisanal Chocolate', 'price': 'Sale price£2.99', 'url': '/artisanal-chocolate'},
		{"name": "Delicious Chocolate", "price": "Sale priceFrom £1.99", "url": "/delicious-chocolate"},
		{"name": "Yummy Cookies", "price": "£2.50", "url": "http://example.com/yummy-cookies"},
		{"name": "Tasty Candy", "price": "Sale price£0.99", "url": "/apple-pies"}
	)
	
	# Add each product to the pipeline
	for product in sample_products:
		data_pipeline.add_product(product)
	
	# Ensure all remaining data in the pipeline gets saved to the CSV file
	data_pipeline.close_pipeline()
	
	print("Data processing complete. Check the product_data.csv file for output.")

Skrip pengujian ini menginisialisasi ProductDataPipeline dengan nama file CSV tertentu dan batas antrian penyimpanan. Kami kemudian akan mencoba menambahkan tiga produk, termasuk duplikatnya, untuk melihat bagaimana saluran kami menanganinya.

Itu close_pipeline Metode ini dipanggil terakhir untuk memastikan bahwa semua data ditulis ke file CSV. Hal ini menunjukkan kemampuan pipeline untuk mengelola data secara end-to-end.

Kode saluran data lengkap

Berikut kode lengkapnya ProductDataPipeline Kelas yang mengintegrasikan semua langkah yang disebutkan dalam artikel ini:

	import csv
	from dataclasses import asdict, fields
	
	class ProductDataPipeline:
		def __init__(self, csv_filename='product_data.csv', storage_queue_limit=10):
			self.names_seen = set()
			self.storage_queue = ()
			self.storage_queue_limit = storage_queue_limit
			self.csv_filename = csv_filename
			self.csv_file_open = False
	
		def save_to_csv(self):
			if not self.storage_queue:
				return
			
			self.csv_file_open = True
			with open(self.csv_filename, mode='a', newline='', encoding='utf-8') as csvfile:
				writer = csv.DictWriter(csvfile, fieldnames=(field.name for field in fields(self.storage_queue(0))))
				if csvfile.tell() == 0:
					writer.writeheader()
				for product in self.storage_queue:
					writer.writerow(asdict(product))
			self.storage_queue.clear()
			self.csv_file_open = False
	
		def clean_raw_product(self, scraped_data):
			cleaned_data = {
				"name": scraped_data.get("name", ""),
				"price": scraped_data.get("price", ""),
				"url": scraped_data.get("url", "")
			}
			return Product(**cleaned_data)
	
		def is_duplicate(self, product_data):
			if product_data.name in self.names_seen:
				print(f"Duplicate item found: {product_data.name}. Item dropped.")
				return True
			self.names_seen.add(product_data.name)
			return False
	
		def add_product(self, scraped_data):
			product = self.clean_raw_product(scraped_data)
			if not self.is_duplicate(product):
				self.storage_queue.append(product)
				if len(self.storage_queue) >= self.storage_queue_limit:
					self.save_to_csv()
	
		def close_pipeline(self):
			if self.storage_queue:
				self.save_to_csv()
	
	
	data_pipeline = ProductDataPipeline(csv_filename='product_data.csv', storage_queue_limit=3)
	
	# Sample scraped data to add to our pipeline
	sample_products = (
		{'name': 'Artisanal Chocolate', 'price': 'Sale price£2.99', 'url': '/artisanal-chocolate'},
		{'name': 'Gourmet Cookies', 'price': '£5.50', 'url': 'http://example.com/gourmet-cookies'},
		{'name': 'Artisanal Chocolate', 'price': 'Sale price£2.99', 'url': '/artisanal-chocolate'},
		{"name": "Delicious Chocolate", "price": "Sale priceFrom £1.99", "url": "/delicious-chocolate"},
		{"name": "Yummy Cookies", "price": "£2.50", "url": "http://example.com/yummy-cookies"},
		{"name": "Tasty Candy", "price": "Sale price£0.99", "url": "/apple-pies"}
	)
	
	# Add each product to the pipeline
	for product in sample_products:
		data_pipeline.add_product(product)
	
	# Ensure all remaining data in the pipeline gets saved to the CSV file
	data_pipeline.close_pipeline()
	
	print("Data processing complete. Check the product_data.csv file for output.")

Terus belajar

Dalam artikel ini, kami telah memberikan panduan komprehensif untuk membersihkan dan menyusun data tergores menggunakan kelas data dan saluran data. Dengan mengikuti teknik ini, Anda dapat memastikan bahwa data yang Anda ambil akurat, konsisten, dan siap untuk dianalisis.

Jika Anda ingin mengambil data dalam jumlah besar tanpa diblokir, Anda harus menggunakan ScraperAPI. Ini menyediakan API sederhana yang memungkinkan Anda mendapatkan respons HTML yang dirender sepenuhnya, termasuk respons dari situs web dinamis.

Sampai jumpa lagi, selamat menggores!

Pos terkait

Tinggalkan Komentar