Xây dựng công cụ xác thực dữ liệu và thu thập hình ảnh web trong Python

Trong quá trình phát triển phần mềm, việc xác thực định dạng dữ liệu đầu vào và tự động hóa thu thập thông tin từ web là hai tác vụ cốt lõi. Phần dưới đây trình bày cách sử dụng biểu thức chính quy (Regular Expression) để kiểm tra tính hợp lệ của các chuỗi ký tự đặc thù, đồng thời kết hợp kỹ thuật Decorator để xây dựng một công cụ web scraping có khả năng đo lường hiệu năng và ghi nhật ký.

Xác thực dữ liệu với Regular Expression

Thư viện re cung cấp các phương thức mạnh mẽ để đối sánh mẫu. Để tối ưu hóa hiệu suất và dễ dàng bảo trì, các pattern nên được đóng gói trong một lớp (Class) và biên dịch trước bằng re.compile. Dưới đây là kiến trúc hệ thống xác thực cho các định dạng: số điện thoại cố định (mã vùng 029), mã bưu chính, địa chỉ email và số căn cước công dân.

import re

class DataFormatValidator:
    # Tiền biên dịch các biểu thức chính quy
    PATTERNS = {
        "landline_phone": re.compile(r"^029-\d+$"),
        "postal_code": re.compile(r"^\d{6}$"),
        "email_address": re.compile(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"),
        "id_card": re.compile(r"^\d{17}[\dXx]$")
    }

    @classmethod
    def is_valid(cls, data_type: str, input_string: str) -> bool:
        """Kiểm tra tính hợp lệ của chuỗi dựa trên loại dữ liệu."""
        pattern = cls.PATTERNS.get(data_type)
        if not pattern:
            raise ValueError(f"Loại dữ liệu '{data_type}' không được hỗ trợ.")
        return bool(pattern.fullmatch(input_string))

# Bộ dữ liệu kiểm thử
dataset = [
    ("landline_phone", "029-12345", True),
    ("landline_phone", "021-12345", False),
    ("postal_code", "745100", True),
    ("postal_code", "7451A", False),
    ("email_address", "contact@university.edu.vn", True),
    ("email_address", "contact@university", False),
    ("id_card", "62282519960504337X", True),
    ("id_card", "6228251996050433", False),
]

if __name__ == "__main__":
    for dtype, value, expected in dataset:
        is_match = DataFormatValidator.is_valid(dtype, value)
        status = "Hợp lệ" if is_match == expected else "Lỗi logic"
        print(f"[{status}] {dtype}: {value}")

Thu thập đường dẫn hình ảnh và ghi nhật ký bằng Decorator

Khi xây dựng các công cụ cào dữ liệu (web scraper), việc theo dõi thời gian thực thi, số lượng dữ liệu thu được và trạng thái lỗi là rất quan trọng. Decorator trong Python cho phép mở rộng chức năng của hàm mà không cần sửa đổi mã nguồn gốc. Đoạn mã sau sử dụng requestsBeautifulSoup để trích xuất các thẻ hình ảnh, kết hợp với module logging để lưu vết quá trình hoạt động vào tệp cục bộ.

Trước khi chạy mã, cần cài đặt các thư viện phụ thuộc:

pip install requests beautifulsoup4

Triển khai chi tiết:

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
import time
import logging
from functools import wraps

# Cấu hình logging để ghi log ra file
logging.basicConfig(
    filename='scraper_metrics.log',
    level=logging.INFO,
    format='%(asctime)s | %(levelname)s | %(message)s'
)

def monitor_scraping(func):
    """Decorator giám sát hiệu năng và lưu log quá trình cào dữ liệu."""
    @wraps(func)
    def wrapper(target_url, *args, **kwargs):
        start_epoch = time.time()
        logging.info(f"Bắt đầu truy cập: {target_url}")
        
        try:
            result = func(target_url, *args, **kwargs)
            elapsed = time.time() - start_epoch
            item_count = len(result) if isinstance(result, list) else 0
            
            logging.info(f"Hoàn thành trong {elapsed:.3f}s | Thu thập được {item_count} mục.")
            return result
        except Exception as e:
            logging.error(f"Lỗi khi cào dữ liệu từ {target_url}: {str(e)}")
            return []
    return wrapper

@monitor_scraping
def extract_image_links(base_url: str, output_filename: str = "extracted_images.txt") -> list:
    """Trích xuất các liên kết hình ảnh từ HTML và lưu vào tệp."""
    session = requests.Session()
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"
    })
    
    response = session.get(base_url, timeout=15)
    response.raise_for_status()
    response.encoding = response.apparent_encoding
    
    parser = BeautifulSoup(response.text, 'html.parser')
    raw_links = [img.get('src') for img in parser.find_all('img') if img.get('src')]
    
    # Chuẩn hóa các đường dẫn tương đối thành tuyệt đối
    absolute_links = []
    for link in raw_links:
        if link.startswith('//'):
            absolute_links.append(f"https:{link}")
        else:
            absolute_links.append(urljoin(base_url, link))
    
    # Ghi dữ liệu ra file
    if absolute_links:
        with open(output_filename, 'w', encoding='utf-8') as file:
            file.write('\n'.join(absolute_links))
            
    return absolute_links

if __name__ == "__main__":
    target_website = "https://www.example-university.edu/"
    extract_image_links(target_website, "university_assets.txt")

Thẻ: python Regular Expression web scraping requests BeautifulSoup

Đăng vào ngày 16 tháng 9 lúc 11:55