0
0
Lập trình
NM

Hướng dẫn Scraping Blog Toàn Diện với AI và Pagination

Đăng vào 1 tháng trước

• 6 phút đọc

Giới thiệu

Bạn đã thành thạo việc lấy dữ liệu từ một trang đơn. Nhưng khi cần lấy dữ liệu từ một blog hoặc trang tin tức với hàng chục, thậm chí hàng trăm trang, thì sao? Ngay khi bạn cần nhấn "Tiếp theo", độ phức tạp sẽ tăng vọt.

Trong hướng dẫn này, chúng ta sẽ xây dựng một kịch bản mạnh mẽ để lấy dữ liệu từ mọi bài viết trong một blog và lưu chúng vào file CSV, tất cả thông qua việc sử dụng một tính năng AI mạnh mẽ giúp bạn xử lý những phần khó khăn nhất.

Mục tiêu

Chúng ta sẽ sử dụng phần AutoExtract của API Zyte. Điều này sẽ trả về cho chúng ta dữ liệu JSON với thông tin cần thiết mà không cần phải làm rối.

Chuẩn bị Mã

Cài đặt Thư viện

Đầu tiên, bạn cần cài đặt các thư viện cần thiết. Sử dụng pip để cài đặt:

bash Copy
pip install requests

Lấy API Key

Đảm bảo bạn có một API Key. Truy cập đây để nhận tín dụng miễn phí để thử nghiệm API Web Scraping của chúng tôi.

Mã Khởi Tạo

python Copy
import os
import requests
import csv

APIKEY = os.getenv("ZYTE_API_KEY")
if APIKEY is None:
    raise Exception("Không tìm thấy API key. Vui lòng thiết lập biến môi trường ZYTE_API_KEY.")

Sử Dụng articleNavigation

Đơn Giản Hóa Quy Trình

Chúng ta sẽ tạo một hàm để gửi một yêu cầu thông minh đến API Zyte. Thay vì chỉ yêu cầu HTML thô, chúng ta sẽ đặt articleNavigation thành True.

Hướng dẫn này sẽ giúp API tự động thực hiện một loạt các nhiệm vụ phức tạp:

  1. Render trang trong trình duyệt thực để xử lý nội dung được tải bằng JavaScript.
  2. Xác định danh sách bài viết chính trên trang.
  3. Trích xuất chi tiết quan trọng cho mỗi bài viết (URL, tiêu đề, ngày, v.v.) vào một cấu trúc sạch.
  4. Tìm liên kết "Trang tiếp theo" để cho phép phân trang liền mạch.
python Copy
def request_list(url):
    """
    Gửi yêu cầu đến API Zyte để trích xuất dữ liệu điều hướng bài viết.
    """
    api_response = requests.post(
        "https://api.zyte.com/v1/extract",
        auth=(APIKEY, ""),
        json={
            "url": url,
            "articleNavigation": True,
            "articleNavigationOptions": {"extractFrom":"browserHtml"},
        },
    )
    return api_response

Tại Sao Tính Năng Này Hữu Ích

Với tính năng articleNavigation, bạn không còn phải thực hiện các bước phức tạp:

  • Cách Thủ Công: Lấy HTML, nhận ra rằng nội dung được tải bằng JavaScript và cần sử dụng Selenium hoặc Playwright để điều khiển trình duyệt.
  • Kiểm tra HTML để tìm CSS selectors hoặc XPath cho danh sách bài viết.
  • Viết thêm mã để trích xuất tiêu đề, URL và ngày.
  • Tìm kiếm selector cho nút "Trang tiếp theo".

Tất cả những điều này đều rất tốn thời gian và dễ bị hỏng. Tính năng articleNavigation giúp bạn dễ dàng xử lý mọi thay đổi nhỏ trên trang mà không cần sửa mã.

Vòng Lặp: Lấy Dữ Liệu Từ Trang Này Sang Trang Khác

Chúng ta cần một vòng lặp để duy trì quá trình lấy dữ liệu. Một vòng lặp while là công cụ hoàn hảo cho công việc này.

python Copy
def main():
    articles = []
    nextPage = "https://zyte.com/learn" # Điểm bắt đầu

    while True:
        print(f"Đang lấy dữ liệu từ trang: {nextPage}")
        resp = request_list(nextPage)

        # Thêm các bài viết tìm thấy vào danh sách
        for item in resp.json()["articleNavigation"]["items"]:
            articles.append(item)

        # Tìm liên kết trang tiếp theo
        try:
            nextPage = resp.json()["articleNavigation"]["nextPage"]["url"]
        except KeyError:
            print("Đã đến trang cuối. Kết thúc vòng lặp.")
            break

Lưu Dữ Liệu Vào CSV

Sau khi vòng lặp hoàn tất, chúng ta có một danh sách sạch các từ điển, mỗi từ điển đại diện cho một bài viết. Bước cuối cùng là lưu dữ liệu quý giá này.

python Copy
def save_to_csv(articles):
    """
    Lưu danh sách từ điển bài viết vào file CSV.
    """
    keys = articles[0].keys() # Lấy tiêu đề từ bài viết đầu tiên

    with open('articles.csv', 'w', newline='', encoding='utf-8') as output_file:
        dict_writer = csv.DictWriter(output_file, keys)
        dict_writer.writeheader()
        dict_writer.writerows(articles)

    print(f"\nĐã lưu thành công {len(articles)} bài viết vào articles.csv!")

Tổng Kết

Bạn đã xây dựng một scraper mạnh mẽ, bền bỉ và có thể mở rộng, tự động hóa một trong những nhiệm vụ tốn thời gian nhất trong việc lấy dữ liệu trên web. Bạn đã tiết kiệm được hàng giờ lập trình và bảo vệ mã của mình khỏi những thay đổi nhỏ trên trang web.

Mã Hoàn Chỉnh

python Copy
import os
import requests
import csv

APIKEY = os.getenv("ZYTE_API_KEY")
if APIKEY is None:
    raise Exception("Không tìm thấy API key. Vui lòng thiết lập biến môi trường ZYTE_API_KEY.")

def request_list(url):
    """
    Gửi yêu cầu đến API Zyte để trích xuất dữ liệu điều hướng bài viết.
    """
    api_response = requests.post(
        "https://api.zyte.com/v1/extract",
        auth=(APIKEY, ""),
        json={
            "url": url,
            "articleNavigation": True,
            "articleNavigationOptions": {"extractFrom": "browserHtml"},
        },
    )
    return api_response

def save_to_csv(articles):
    """
    Lưu danh sách từ điển bài viết vào file CSV.
    """
    if not articles:
        print("Không có bài viết nào để lưu.")
        return

    keys = articles[0].keys()

    with open('articles.csv', 'w', newline='', encoding='utf-8') as output_file:
        dict_writer = csv.DictWriter(output_file, keys)
        dict_writer.writeheader()
        dict_writer.writerows(articles)

    print(f"\nĐã lưu thành công {len(articles)} bài viết vào articles.csv!")

def main():
    articles = []
    nextPage = "https://zyte.com/learn"

    while True:
        resp = request_list(nextPage)
        json_response = resp.json()

        found_items = json_response.get("articleNavigation", {}).get("items", [])
        if found_items:
            articles.extend(found_items)

        try:
            nextPage = json_response["articleNavigation"]["nextPage"]["url"]
        except (KeyError, TypeError):
            print("Đã đến trang cuối. Kết thúc việc lấy dữ liệu.")
            break

    save_to_csv(articles)

if __name__ == "__main__":
    main()
Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào