Cách thực hiện các thử nghiệm yêu cầu trong Python

Bình luận: 0

Scraping web là một phương pháp hiệu quả để trích xuất dữ liệu từ web. Nhiều nhà phát triển thích sử dụng thư viện Python Requests để thực hiện các dự án cào web vì nó đơn giản và hiệu quả. Tuy nhiên, thật tuyệt vời, thư viện yêu cầu có những hạn chế. Một vấn đề điển hình mà chúng ta có thể gặp phải trong việc cạo web là các yêu cầu không thành công, điều này thường dẫn đến trích xuất dữ liệu không ổn định. Trong bài viết này, chúng tôi sẽ trải qua quá trình thực hiện các thử nghiệm yêu cầu trong Python, để bạn có thể xử lý các lỗi HTTP và giữ cho các tập lệnh quét web của bạn ổn định và đáng tin cậy.

Bắt đầu với thư viện yêu cầu

Hãy để thiết lập môi trường của chúng tôi trước. Hãy chắc chắn rằng bạn đã cài đặt Python và bất kỳ IDE nào bạn chọn. Sau đó, cài đặt thư viện yêu cầu nếu bạn không có nó.

pip install requests

Sau khi được cài đặt, chúng ta hãy gửi yêu cầu đến example.com bằng mô -đun yêu cầu của Python. Đây là một chức năng đơn giản chỉ làm điều đó:

import requests

def send_request(url):
    """
    Gửi HTTP Nhận yêu cầu đến URL được chỉ định và in mã trạng thái phản hồi.
    
    Parameters:
        url (str): URL để gửi yêu cầu đến.
    """
    response = requests.get(url)
    print('Response Status Code: ', response.status_code)

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

Đầu ra mã được hiển thị bên dưới:

How to implement request retries in Python.png

Chúng ta hãy xem xét kỹ hơn mã trạng thái HTTP để hiểu chúng tốt hơn.

Hiểu mã trạng thái HTTP

Máy chủ trả lời yêu cầu HTTP với mã trạng thái cho biết kết quả của yêu cầu. Đây là một danh sách nhanh:

  1. 1xx (Thông tin): Yêu cầu đã được nhận và tiếp tục được xử lý.
  2. 2xx (thành công): Yêu cầu đã được nhận, hiểu và chấp nhận.
    • 200 OK: Yêu cầu đã thành công. Đây là ánh sáng màu xanh lá cây của mã trạng thái HTTP.
  3. 3xx (chuyển hướng): Cần có thêm hành động để hoàn thành yêu cầu.
  4. 4xx (lỗi máy khách): Có một lỗi với yêu cầu, thường là do một cái gì đó ở phía máy khách.
  5. 5xx (Lỗi máy chủ): Máy chủ không thực hiện được yêu cầu hợp lệ do lỗi ở cuối.
    • 500 Lỗi máy chủ nội bộ: Máy chủ không thể hoàn thành yêu cầu. Điều này chỉ ra rằng máy chủ gặp phải một điều kiện bất ngờ ngăn cản nó đáp ứng yêu cầu. Đây là mã trạng thái HTTP tương đương với đèn giao thông màu đỏ.
    • Thời gian chờ 504 Gateway: Máy chủ đã không nhận được phản hồi từ máy chủ ngược dòng. Đây là mã trạng thái HTTP tương đương với đèn giao thông thời gian chờ phòng chờ.

Trong ví dụ của chúng tôi, mã trạng thái 200 có nghĩa là yêu cầu đối với https://example.com đã được hoàn thành. Đó là cách nói của máy chủ, "mọi thứ đều tốt ở đây, yêu cầu của bạn là một thành công".

Các mã trạng thái này cũng có thể đóng một vai trò trong phát hiện bot và cho biết khi truy cập bị hạn chế do hành vi giống như bot.

Dưới đây là một danh sách nhanh các mã lỗi HTTP chủ yếu xảy ra do các vấn đề phát hiện bot và xác thực.

  1. 429 Quá nhiều yêu cầu: Mã trạng thái này cho biết người dùng đã gửi quá nhiều yêu cầu trong một thời gian nhất định (giới hạn tốc độ của Hồi giáo). Nó có một phản ứng phổ biến khi các bot vượt quá giới hạn yêu cầu được xác định trước.
  2. 403 Forbidden: Mã này được trả về khi máy chủ từ chối thực hiện yêu cầu. Điều này có thể xảy ra nếu máy chủ nghi ngờ yêu cầu đến từ bot, dựa trên các tiêu chí của người dùng hoặc người dùng.
  3. 401 Nhập học: Trạng thái này có thể được sử dụng nếu truy cập yêu cầu xác thực mà bot không có.
  4. Dịch vụ 503 Không có sẵn: Đôi khi được sử dụng để chỉ ra rằng máy chủ tạm thời không thể xử lý yêu cầu, điều này có thể xảy ra trong quá trình tăng đột biến lưu lượng tự động.

Thực hiện cơ chế thử lại trong Python

Bây giờ, hãy viết một cơ chế thử lại đơn giản trong Python để thực hiện HTTP nhận được yêu cầu với thư viện yêu cầu. Có những lúc yêu cầu mạng không thành công do một số vấn đề mạng hoặc quá tải máy chủ. Vì vậy, nếu yêu cầu của chúng tôi thất bại, chúng tôi nên thử lại các yêu cầu này.

Cơ chế thử lại cơ bản

Hàm send_request_with_basic_retry_mechanism làm cho HTTP nhận được các yêu cầu đến một URL nhất định với cơ chế thử lại cơ bản tại chỗ sẽ chỉ thử lại nếu gặp phải một mạng hoặc yêu cầu như lỗi kết nối. Nó sẽ thử lại mức tối đa của MAX_RETRIES. Nếu tất cả các cố gắng thất bại với một ngoại lệ như vậy, nó sẽ tăng ngoại lệ cuối cùng.

import requests
import time

def send_request_with_basic_retry_mechanism(url, max_retries=2):
    """
    Gửi HTTP Nhận yêu cầu đến URL với cơ chế thử lại cơ bản.
    
    Parameters:
        url (str): URL để gửi yêu cầu đến.
        max_retries (int): Số lần tối đa để thử lại yêu cầu.

    Raises:
        requests.RequestException: Tăng ngoại lệ cuối cùng nếu tất cả các thử lại thất bại.

    """
    for attempt in range(max_retries):
        try:
            response = requests.get(url)
            print('Response status: ', response.status_code)
            break  # Loop thoát nếu yêu cầu thành công
        except requests.RequestException as error:
            print(f"Attempt {attempt+1} failed:", error)
            if attempt < max_retries - 1:
                print(f"Retrying...")
                time.sleep(delay)  # Chờ trước khi thử lại
            else:
                print("Max retries exceeded.")
                # Ném lại ngoại lệ cuối cùng nếu đạt đến số lần thử tối đa
                raise
                send_request_with_basic_retry_mechanism('https://example.com')

Cơ chế thử lại trước

Bây giờ, hãy để điều chỉnh cơ chế thử lại cơ bản để xử lý các kịch bản trong đó trang web mà chúng tôi đang cố gắng thực hiện các cơ chế phát hiện bot có thể dẫn đến chặn. Để giải quyết các kịch bản như vậy, chúng ta cần thử lại yêu cầu siêng năng nhiều lần, vì chúng có thể không chỉ là các khối phát hiện bot mà còn có thể là do các vấn đề về mạng hoặc máy chủ.

Hàm bên dưới Send_Request_With_Advance_Retry_Mechanism gửi một HTTP Nhận yêu cầu đến URL được cung cấp với các lần thử lại tùy chọn và độ trễ thử lại. Nó cố gắng gửi yêu cầu nhiều lần cho số lần thử được chỉ định và in mã trạng thái phản hồi nếu yêu cầu thành công nhận được phản hồi. Nếu nó gặp lỗi trong quá trình hoạt động yêu cầu, nó sẽ in thông báo lỗi và thử lại. Nó chờ đợi độ trễ thử lại được chỉ định giữa mỗi lần thử. Nếu yêu cầu không thành công ngay cả sau khi số lần thử lại được chỉ định, nó sẽ tăng ngoại lệ cuối cùng.

Tham số độ trễ rất quan trọng vì nó tránh bắn phá máy chủ với nhiều yêu cầu trong một khoảng thời gian gần. Thay vào đó, nó chờ máy chủ có đủ thời gian để xử lý yêu cầu, khiến máy chủ nghĩ rằng con người chứ không phải bot đang thực hiện các yêu cầu. Vì vậy, cơ chế thử lại nên bị trì hoãn để tránh quá tải máy chủ hoặc phản hồi máy chủ chậm có thể kích hoạt các cơ chế chống Bot.

import requests
import time

def send_request_with_advance_retry_mechanism(url, max_retries=3, delay=1):
    """
Gửi HTTP Nhận yêu cầu đến URL được chỉ định với cơ chế thử lại nâng cao.    
    Parameters:
        url (str): URL để gửi yêu cầu đến.
        max_retries (int): Số lần tối đa để thử lại yêu cầu. Mặc định là 3.
        delay (int): Độ trễ (tính bằng giây) giữa các thử nghiệm. Mặc định là 1.

    Raises:
        requests.RequestException: Tăng ngoại lệ cuối cùng nếu tất cả các thử lại thất bại.
    """
    for attempt in range(max_retries):
        try:
            response = requests.get(url)
            # Tăng một ngoại lệ cho mã trạng thái 4xx hoặc 5xx
            response.raise_for_status()
            print('Response Status Code:', response.status_code)
        except requests.RequestException as e:
            # In thông báo lỗi và thử số nếu yêu cầu không thành công
            print(f"Attempt {attempt+1} failed:", e)
            if attempt < max_retries - 1:
                # In tin nhắn thử lại và đợi trước khi thử lại
                print(f"Retrying in {delay} seconds...")
                time.sleep(delay)
            else:
                # Nếu MAX vượt quá, in tin nhắn và gửi lại ngoại lệ
                print("Max retries exceeded.")
                raise

# Ví dụ sử dụng
send_request_with_advance_retry_mechanism('https://httpbin.org/status/404')

Dưới đây là những nhược điểm của việc thực hiện này:

  • Tất cả các mã trạng thái thuộc phạm vi 4xx và 5xx đều được thử lại. Tuy nhiên, các yêu cầu dẫn đến mã trạng thái 404 (không tìm thấy) không cần phải được thử lại.
  • Một số dịch vụ phát hiện bot có thể phản hồi với mã trạng thái 200 (OK), nhưng nội dung phản hồi có thể khác nhau. Tình huống này không được xử lý trong việc thực hiện hiện tại. Thực hiện xác thực độ dài nội dung có thể giải quyết vấn đề này.

Đây là mã được sửa cùng với các nhận xét giải quyết các nhược điểm:

import requests
import time

def send_request_with_advance_retry_mechanism(url, max_retries=3, delay=1, min_content_length=10):
    """
    Gửi HTTP Nhận yêu cầu đến URL được chỉ định với cơ chế thử lại nâng cao.
    Parameters:
        url (str): URL để gửi yêu cầu đến.
        max_retries (int): Số lần tối đa để thử lại yêu cầu. Mặc định là 3.
        delay (int): Độ trễ (tính bằng giây) giữa các thử nghiệm. Mặc định là 1.
        min_content_length (int): Độ dài tối thiểu của nội dung phản hồi để xem xét hợp lệ. Mặc định là 10.

    Raises:
        requests.RequestException: Tăng ngoại lệ cuối cùng nếu tất cả các thử lại thất bại.
    """
    for attempt in range(max_retries):
        try:
            response = requests.get(url)
            # Tăng một ngoại lệ cho mã trạng thái 4xx hoặc 5xx
            response.raise_for_status()
            
            # Kiểm tra xem mã trạng thái phản hồi có phải là 404 không
            if response.status_code == 404:
                print("404 Error: Not Found")
                break  # Lỗi thoát cho 404 lỗi
            
            # Kiểm tra xem độ dài của văn bản phản hồi nhỏ hơn độ dài nội dung tối thiểu được chỉ định
            if len(response.text) < min_content_length:
                print("Response text length is less than specified minimum. Retrying...")
                time.sleep(delay)
                continue  # Thử lại yêu cầu            
            print('Response Status Code:', response.status_code)
            # Nếu điều kiện được đáp ứng, hãy thoát ra khỏi vòng lặp
            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.")
                # Ném lại ngoại lệ cuối cùng nếu đạt đến số lần thử tối đa
                raise

# Ví dụ sử dụng
send_request_with_advance_retry_mechanism('https://httpbin.org/status/404')

Xử lý các lỗi HTTP cụ thể với proxy

Đối với một số lỗi nhất định như 429 quá nhiều yêu cầu, sử dụng proxy xoay có thể giúp phân phối các yêu cầu của bạn và tránh giới hạn tỷ lệ.

Mã dưới đây thực hiện một chiến lược thử lại nâng cao cùng với việc sử dụng proxy. Bằng cách này, chúng ta có thể thực hiện một cơ chế thử lại yêu cầu Python. Sử dụng các proxy quét web chất lượng cao cũng rất quan trọng. Những proxy này nên có một thuật toán tốt cho xoay proxy và một nhóm đáng tin cậy.

import requests
import time

def send_request_with_advance_retry_mechanism(url, max_retries=3, delay=1, min_content_length=10):
    """
    Gửi HTTP Nhận yêu cầu đến URL được chỉ định với cơ chế thử lại nâng cao.

    Parameters:
        url (str): URL để gửi yêu cầu đến.
        max_retries (int): Số lần tối đa để thử lại yêu cầu. Mặc định là 3.
        delay (int): Độ trễ (tính bằng giây) giữa các thử nghiệm. Mặc định là 1.
   
    Raises:
        requests.RequestException: Tăng ngoại lệ cuối cùng nếu tất cả các thử lại thất bại.
    """
    
    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)
            # Tăng một ngoại lệ cho mã trạng thái 4xx hoặc 5xx
            response.raise_for_status()
            
            # Kiểm tra xem mã trạng thái phản hồi có phải là 404 không
            if response.status_code == 404:
                print("404 Error: Not Found")
                break  # Exit loop for 404 errors
            
            # Kiểm tra xem độ dài của văn bản phản hồi nhỏ hơn 10 ký tự
            if len(response.text) < min_content_length:
                print("Response text length is less than 10 characters. Retrying...")
                time.sleep(delay)
                continue  # Thử lại yêu cầu
            
            print('Response Status Code:', response.status_code)
            # Nếu điều kiện được đáp ứng, hãy thoát ra khỏi vòng lặp
            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.")
                # Ném lại ngoại lệ cuối cùng nếu đạt đến số lần thử tối đa
                raise

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

Yêu cầu thử lại trong Python là rất quan trọng để quét web hiệu quả. Các phương pháp chúng tôi đã thảo luận để quản lý thử nghiệm có thể giúp ngăn chặn việc ngăn chặn và nâng cao hiệu quả và độ tin cậy của việc thu thập dữ liệu. Việc thực hiện các kỹ thuật này sẽ làm cho các tập lệnh cạo web của bạn mạnh mẽ hơn và ít bị phát hiện bởi các hệ thống bảo vệ bot.

Bình luận:

0 Bình luận