Cara mengimplementasikan percobaan ulang permintaan di Python

Komentar: 0

Web scraping adalah metode yang efektif untuk mengekstrak data dari web. Banyak pengembang lebih suka menggunakan pustaka permintaan Python untuk menjalankan proyek web scraping karena sederhana dan efektif. Namun, meskipun bagus, request library memiliki keterbatasan. Salah satu masalah umum yang mungkin kita temui dalam web scraping adalah request yang gagal, yang sering menyebabkan ekstraksi data yang tidak stabil. Pada artikel ini, kita akan membahas proses implementasi request retries di Python, sehingga Anda dapat menangani kesalahan HTTP dan menjaga skrip web scraping Anda tetap stabil dan dapat diandalkan.

Memulai dengan pustaka permintaan

Mari kita siapkan lingkungan kita terlebih dahulu. Pastikan Anda telah menginstal Python dan IDE pilihan Anda. Kemudian instal library request jika Anda belum memilikinya.

pip install requests

Setelah terinstal, mari kita kirim permintaan ke example.com menggunakan modul permintaan Python. Berikut ini adalah fungsi sederhana yang melakukan hal tersebut:

import requests

def send_request(url):
    """
    Mengirimkan permintaan HTTP GET ke URL yang ditentukan dan mencetak kode status respons.
    
    Parameters:
        url (str): URL untuk mengirim permintaan.
    """
    response = requests.get(url)
    print('Response Status Code: ', response.status_code)

send_request('https://example.com')

Output kode ditunjukkan di bawah ini:

How to implement request retries in Python.png

Mari kita lihat lebih dekat kode status HTTP untuk memahaminya dengan lebih baik.

Memahami kode status HTTP

Server merespons permintaan HTTP dengan kode status yang menunjukkan hasil permintaan. Berikut adalah ikhtisar singkatnya:

  1. 1xx (Informasi): Permintaan telah diterima dan terus diproses.
  2. 2xx (Berhasil): Permintaan diterima, dipahami, dan disetujui.
    • 200 OK: Permintaan berhasil. Ini adalah lampu hijau dari kode status HTTP.
  3. 3xx (Pengalihan): Tindakan lebih lanjut diperlukan untuk menyelesaikan permintaan.
  4. 4xx (Kesalahan Klien): Terjadi kesalahan pada permintaan, biasanya disebabkan oleh sesuatu di sisi klien.
  5. 5xx (Kesalahan Server): Server gagal memenuhi permintaan yang valid karena terjadi kesalahan pada server.
    • 500 Kesalahan Server Internal: Server tidak dapat menyelesaikan permintaan. Ini mengindikasikan bahwa server mengalami kondisi tak terduga yang mencegahnya memenuhi permintaan. Ini adalah kode status HTTP yang setara dengan lampu lalu lintas merah.
    • 504 Gateway Timeout: Server tidak menerima respons dari server hulu pada waktunya. Ini adalah kode status HTTP yang setara dengan lampu lalu lintas batas waktu ruang tunggu.

Dalam contoh kita, kode status 200 berarti permintaan ke https://example.com telah selesai. Ini adalah cara server untuk mengatakan, "Semuanya baik-baik saja di sini, permintaan Anda berhasil".

Kode status ini juga dapat berperan dalam deteksi bot dan menunjukkan kapan akses dibatasi karena perilaku seperti bot.

Di bawah ini adalah ikhtisar singkat kode kesalahan HTTP yang terutama terjadi karena masalah deteksi dan autentikasi bot.

  1. 429 terlalu banyak permintaan: kode status ini menunjukkan bahwa pengguna telah mengirim terlalu banyak permintaan dalam waktu tertentu ("pembatasan laju"). Ini adalah respons umum ketika bot melebihi batas permintaan yang telah ditentukan.
  2. 403 forbidden: kode ini dikembalikan ketika server menolak untuk memenuhi permintaan. Hal ini dapat terjadi jika server mencurigai permintaan berasal dari bot, berdasarkan User-Agent atau kriteria lainnya.
  3. 401 tidak sah: status ini dapat digunakan jika akses memerlukan autentikasi yang tidak dimiliki oleh bot.
  4. Layanan 503 tidak tersedia: terkadang digunakan untuk mengindikasikan bahwa server untuk sementara tidak dapat menangani permintaan, yang mungkin terjadi selama lonjakan lalu lintas otomatis.

Menerapkan mekanisme percobaan ulang di Python

Sekarang mari kita tulis mekanisme percobaan ulang sederhana di Python untuk membuat permintaan HTTP GET dengan pustaka permintaan. Ada kalanya permintaan jaringan gagal karena masalah jaringan atau server yang kelebihan beban. Jadi, jika permintaan kita gagal, kita harus mencoba ulang permintaan tersebut.

Mekanisme percobaan ulang dasar

Fungsi send_request_with_basic_retry_mechanism membuat permintaan HTTP GET ke URL yang diberikan dengan mekanisme percobaan ulang dasar yang hanya akan mencoba kembali jika terjadi pengecualian jaringan atau permintaan seperti kesalahan koneksi. Mekanisme ini akan mencoba ulang permintaan sebanyak maksimal max_retries kali. Jika semua percobaan gagal dengan pengecualian seperti itu, maka akan memunculkan pengecualian terakhir yang ditemui.

import requests
import time

def send_request_with_basic_retry_mechanism(url, max_retries=2):
    """
    Mengirimkan permintaan HTTP GET ke URL dengan mekanisme percobaan ulang dasar.
    
    Parameters:
        url (str): URL untuk mengirim permintaan.
        max_retries (int): Jumlah maksimum untuk mencoba kembali permintaan.

    Raises:
        requests.RequestException: Memunculkan pengecualian terakhir jika semua percobaan ulang gagal.

    """
    for attempt in range(max_retries):
        try:
            response = requests.get(url)
            print('Response status: ', response.status_code)
            break  # Keluar dari loop jika permintaan berhasil
        except requests.RequestException as error:
            print(f"Attempt {attempt+1} failed:", error)
            if attempt < max_retries - 1:
                print(f"Retrying...")
                time.sleep(delay)  # Tunggu sebelum mencoba kembali
            else:
                print("Max retries exceeded.")
                # Naikkan kembali pengecualian terakhir jika percobaan ulang maksimum tercapai
                raise
                send_request_with_basic_retry_mechanism('https://example.com')

Mekanisme percobaan ulang lanjutan

Sekarang mari kita mengadaptasi mekanisme percobaan ulang dasar untuk menangani skenario di mana situs web yang ingin kita scrape mengimplementasikan mekanisme deteksi bot yang dapat mengakibatkan pemblokiran. Untuk menangani skenario seperti itu, kita perlu mencoba ulang permintaan dengan tekun beberapa kali, karena mungkin bukan hanya pemblokiran karena deteksi bot tetapi juga karena masalah jaringan atau server.

Fungsi di bawah ini send_request_with_advance_retry_mechanism mengirim permintaan HTTP GET ke URL yang disediakan dengan upaya percobaan ulang opsional dan penundaan percobaan ulang. Fungsi ini mencoba mengirim permintaan beberapa kali untuk jumlah percobaan yang ditentukan dan mencetak kode status respons jika permintaan berhasil mendapatkan respons. Jika menemukan kesalahan selama operasi permintaan, ia akan mencetak pesan kesalahan dan mencobanya kembali. Ia menunggu penundaan percobaan ulang yang ditentukan di antara setiap percobaan. Jika permintaan gagal bahkan setelah jumlah percobaan ulang yang ditentukan, maka akan memunculkan pengecualian terakhir yang ditemui.

Parameter penundaan penting karena menghindari membombardir server dengan banyak permintaan dalam waktu yang berdekatan. Sebaliknya, ia menunggu server memiliki cukup waktu untuk memproses permintaan, membuat server berpikir bahwa manusia dan bukan bot yang membuat permintaan. Jadi, mekanisme percobaan ulang harus ditunda untuk menghindari server yang kelebihan beban atau respons server yang lambat yang dapat memicu mekanisme anti-bot.

import requests
import time

def send_request_with_advance_retry_mechanism(url, max_retries=3, delay=1):
    """
    Mengirimkan permintaan HTTP GET ke URL yang ditentukan dengan mekanisme percobaan ulang tingkat lanjut.
    
    Parameters:
        url (str): URL untuk mengirim permintaan.
        max_retries (int): Jumlah maksimum untuk mencoba ulang permintaan. Standarnya adalah 3.
        delay (int): Penundaan (dalam detik) di antara percobaan ulang. Standarnya adalah 1.

    Raises:
        requests.RequestException: Memunculkan pengecualian terakhir jika semua percobaan ulang gagal.
    """
    for attempt in range(max_retries):
        try:
            response = requests.get(url)
            # Membuat pengecualian untuk kode status 4xx atau 5xx
            response.raise_for_status()
            print('Response Status Code:', response.status_code)
        except requests.RequestException as e:
            # Mencetak pesan kesalahan dan nomor percobaan jika permintaan gagal
            print(f"Attempt {attempt+1} failed:", e)
            if attempt < max_retries - 1:
                # Cetak pesan coba ulang dan tunggu sebelum mencoba kembali
                print(f"Retrying in {delay} seconds...")
                time.sleep(delay)
            else:
                # Jika percobaan ulang maksimum terlampaui, cetak pesan dan naikkan kembali pengecualian
                print("Max retries exceeded.")
                raise

# Contoh penggunaan
send_request_with_advance_retry_mechanism('https://httpbin.org/status/404')

Berikut ini adalah kekurangan dari implementasi ini:

  • Semua kode status yang termasuk dalam rentang 4xx dan 5xx akan dicoba ulang. Namun, permintaan yang menghasilkan kode status 404 (Tidak Ditemukan) tidak perlu dicoba ulang.
  • Beberapa layanan pendeteksi bot mungkin merespons dengan kode status 200 (OK), tetapi konten responsnya mungkin berbeda. Situasi ini tidak ditangani dalam implementasi saat ini. Menerapkan validasi panjang konten dapat mengatasi masalah ini.

Berikut ini adalah kode yang telah diperbaiki bersama dengan komentar yang membahas kekurangannya:

import requests
import time

def send_request_with_advance_retry_mechanism(url, max_retries=3, delay=1, min_content_length=10):
    """
    Mengirimkan permintaan HTTP GET ke URL yang ditentukan dengan mekanisme percobaan ulang tingkat lanjut.

    Parameters:
        url (str): URL untuk mengirim permintaan.
        max_retries (int): Jumlah maksimum untuk mencoba ulang permintaan. Standarnya adalah 3.
        delay (int): Penundaan (dalam detik) di antara percobaan ulang. Standarnya adalah 1.
        min_content_length (int): Panjang minimum konten respons yang dianggap valid. Standarnya adalah 10.

    Raises:
        requests.RequestException: Memunculkan pengecualian terakhir jika semua percobaan ulang gagal.
    """
    for attempt in range(max_retries):
        try:
            response = requests.get(url)
            # Membuat pengecualian untuk kode status 4xx atau 5xx
            response.raise_for_status()
            
            # Periksa apakah kode status respons adalah 404
            if response.status_code == 404:
                print("404 Error: Not Found")
                break  # Keluar dari perulangan untuk kesalahan 404
            
            # Periksa apakah panjang teks respons kurang dari panjang konten minimum yang ditentukan
            if len(response.text) < min_content_length:
                print("Response text length is less than specified minimum. Retrying...")
                time.sleep(delay)
                continue  # Coba lagi permintaan tersebut
            
            print('Response Status Code:', response.status_code)
            # Jika kondisi terpenuhi, keluar dari loop
            break
            
        except requests.RequestException as e:
            print(f"Attempt {attempt+1} failed:", e)
            if attempt < max_retries - 1:
                print(f"Retrying in {delay} seconds...")
                time.sleep(delay)
            else:
                print("Max retries exceeded.")
                # Naikkan kembali pengecualian terakhir jika percobaan ulang maksimum tercapai
                raise

# Contoh penggunaan
send_request_with_advance_retry_mechanism('https://httpbin.org/status/404')

Menangani kesalahan HTTP tertentu dengan proxy

Untuk kesalahan tertentu seperti 429 Terlalu Banyak Permintaan, menggunakan proxy bergilir dapat membantu mendistribusikan permintaan Anda dan menghindari pembatasan kecepatan.

Kode di bawah ini mengimplementasikan strategi percobaan ulang tingkat lanjut bersama dengan penggunaan proksi. Dengan cara ini, kita dapat mengimplementasikan mekanisme permintaan ulang Python. Menggunakan proksi penggalian web berkualitas tinggi juga penting. Proksi ini harus memiliki algoritme yang baik untuk rotasi proksi dan pool yang andal.

import requests
import time

def send_request_with_advance_retry_mechanism(url, max_retries=3, delay=1, min_content_length=10):
    """
    Mengirimkan permintaan HTTP GET ke URL yang ditentukan dengan mekanisme percobaan ulang tingkat lanjut.

    Parameters:
        url (str): URL untuk mengirim permintaan.
        max_retries (int): Jumlah maksimum untuk mencoba ulang permintaan. Standarnya adalah 3.
        delay (int): Penundaan (dalam detik) di antara percobaan ulang. Standarnya adalah 1.
   
    Raises:
        requests.RequestException: Memunculkan pengecualian terakhir jika semua percobaan ulang gagal.
    """
    
    proxies = {
        "http": "http://USER:PASS@HOST:PORT",
        "https": "https://USER:PASS@HOST:PORT"
    }
    
    for attempt in range(max_retries):
        try:
            response = requests.get(url, proxies=proxies, verify=False)
            # Membuat pengecualian untuk kode status 4xx atau 5xx
            response.raise_for_status()
            
            # Periksa apakah kode status respons adalah 404
            if response.status_code == 404:
                print("404 Error: Not Found")
                break  # Keluar dari perulangan untuk kesalahan 404
            
            # Periksa apakah panjang teks respons kurang dari 10 karakter
            if len(response.text) < min_content_length:
                print("Response text length is less than 10 characters. Retrying...")
                time.sleep(delay)
                continue  # Coba lagi permintaan tersebut
            
            print('Response Status Code:', response.status_code)
            # Jika kondisi terpenuhi, keluar dari loop
            break
            
        except requests.RequestException as e:
            print(f"Attempt {attempt+1} failed:", e)
            if attempt < max_retries - 1:
                print(f"Retrying in {delay} seconds...")
                time.sleep(delay)
            else:
                print("Max retries exceeded.")
                # Naikkan kembali pengecualian terakhir jika percobaan ulang maksimum tercapai
                raise

send_request_with_advance_retry_mechanism('https://httpbin.org/status/404')

Permintaan ulang di Python sangat penting untuk penggalian web yang efektif. Metode yang telah kita bahas untuk mengelola pengulangan permintaan dapat membantu mencegah pemblokiran dan meningkatkan efisiensi dan keandalan pengumpulan data. Menerapkan teknik-teknik ini akan membuat skrip scraping web Anda lebih kuat dan tidak mudah terdeteksi oleh sistem proteksi bot.

Komentar:

0 komentar