Lập trình web scraping với JavaScript: Hướng dẫn thực tế về Node.js

Lập trình web scraping với JavaScript

API Scraping toàn cầu Scrapeless cung cấp cho các chương trình JavaScript nội dung trang đã được fetch hoặc render thông qua một yêu cầu HTTP xác thực.

TL;DR

  • Việc scraping bằng JavaScript bắt đầu với phân loại một trang. Sử dụng một khách hàng HTTP và một trình phân tích HTML khi các trường yêu cầu tồn tại trong thân phản hồi; sử dụng trình render trình duyệt khi script tạo ra chúng muộn hơn.
  • Cheerio phân tích cú pháp markup nhưng không chạy script trang. Giới hạn đó khiến Cheerio trở thành một lựa chọn tốt cho các trang được render trên máy chủ và lựa chọn kém cho nội dung chỉ trên khách hàng.
  • Các bộ chọn nên mô tả ý nghĩa, không phải hình thức. Các thuộc tính ổn định, các phần tử ngữ nghĩa và các mối quan hệ có phạm vi tồn tại lâu hơn các chuỗi lớp được tạo ra dài.
  • Phân trang cần một quy tắc dừng rõ ràng. Theo một liên kết tiếp theo đã được xác minh hoặc một con trỏ được tài liệu hóa và dừng lại khi nguồn cho biết bộ sưu tập đã kết thúc.
  • Đầu ra sản xuất cần một lược đồ. Chuẩn hóa văn bản, giải quyết URL, giữ lại các trường có thể null và xác thực mỗi bản ghi trước khi lưu trữ.

Cách web scraping JavaScript hoạt động

Web scraping bằng JavaScript là một quy trình fetch, phân tích, chọn và chuẩn hóa. Bước fetch lấy byte qua HTTP. Trình phân tích biến những byte đó thành một cây tài liệu. Các bộ chọn xác định các nút mang các trường bạn cần. Bước cuối cùng chuyển đổi các giá trị hình dạng trang thành một bản ghi ổn định mà ứng dụng của bạn có thể lưu trữ hoặc so sánh.

Quyết định đầu tiên là liệu phản hồi đã chứa dữ liệu hay chưa. Mở công cụ phát triển trình duyệt, kiểm tra phản hồi mạng hoặc nguồn trang, và tìm kiếm một giá trị hiển thị trên màn hình. Nếu giá trị đó xuất hiện trong HTML trả về, một trình phân tích nhẹ là đủ. Nếu phản hồi chỉ là một lớp vỏ và giá trị xuất hiện sau khi JavaScript chạy, lớp thu mua phải render trang hoặc gọi một điểm cuối có cấu trúc được phép.

Node.js hiện đại cung cấp một giao diện fetch tương thích với trình duyệt.Fetch trả về một đối tượng phản hồi; gọi text() đọc HTML. Tình trạng phản hồi vẫn quan trọng. Một trang đăng nhập, màn hình đồng ý hoặc tài liệu từ chối truy cập có thể là HTML hợp lệ, vì vậy việc phân tích thành công không chứng minh rằng trang đúng đã đến.

Chọn giữa Cheerio và một Trình duyệt

Cheerio là trình phân tích JavaScript đúng khi nội dung mục tiêu có trong HTML tĩnh. Việc giới thiệu chính thức về Cheerio rất rõ ràng về ranh giới: Cheerio phân tích cú pháp markup và cung cấp một API duyệt như jQuery, nhưng nó không phải là một trình duyệt và không thực thi JavaScript, tải tài nguyên phụ, hoặc vẽ một trang.

Điều kiện trangĐường đi được khuyến nghịLý do
Các trường xuất hiện trong HTML phản hồifetch cộng với CheerioChi phí thấp và lựa chọn CSS trực tiếp
Các script tạo ra các nút cần thiếtThu mua được renderPhản hồi ban đầu không chứa dữ liệu
Một phản hồi JSON công khai hỗ trợ trangAPI được tài liệu hóa hoặc điểm cuối được phépDữ liệu có cấu trúc tránh việc diễn giải DOM
Một cú nhấp chuột hoặc cuộn thay đổi tập hợp kết quảTự động hóa trình duyệtQuy trình làm việc phụ thuộc vào trạng thái trang và sự kiện

Một đường dẫn trình duyệt tốn nhiều bộ nhớ và thời gian khởi động hơn, vì vậy nó nên là một lựa chọn có chủ đích. Render chỉ khi dữ liệu hoặc tương tác yêu cầu điều đó. Sự tách biệt này cũng làm cho việc kiểm thử dễ dàng hơn: trình phân tích có thể được kiểm tra với HTML đã lưu, trong khi lớp thu mua được kiểm tra dựa trên mạng và trạng thái trang.

Xây dựng một trình thu thập dữ liệu HTML tĩnh nhỏ

Dự án Node.js cơ bản cần Cheerio và một thời gian chạy Node hiện tại. Cài đặt gói, yêu cầu một trang, kiểm tra tình trạng, tải thân, và giữ công việc bộ chọn có phạm vi ở mỗi thẻ lặp lại. Ví dụ sau đọc tiêu đề và liên kết canonical từ Domain Ví dụ. Nó được giới hạn một cách cố ý ở một trang công khai.

import * as cheerio from 'cheerio';

const response = await fetch('https://example.com/');
if (!response.ok) {
  throw new Error(`Unexpected HTTP status: ${response.status}`);
}

const html = await response.text();
const $ = cheerio.load(html);

const record = {
  title: $('h1').first().text().trim(),
  link: new URL($('a').first().attr('href'), response.url).href,
};

console.log(JSON.stringify(record, null, 2));

Bộ chọn ngắn vì trang đơn giản. Trên một danh mục, chọn trước thùng chứa lặp lại, sau đó truy vấn các nút con bên trong thùng chứa đó. Việc định phạm vi ngăn chặn lỗi chất lượng dữ liệu phổ biến, nơi mỗi hàng nhận tiêu đề hoặc giá đầu tiên trên trang. Các trường thiếu nên trở thành null, không phải là một chuỗi rỗng không thể phân biệt với một giá trị trống thật sự.

Thiết kế các bộ chọn tồn tại sau khi thay đổi

Độ bền của bộ chọn quan trọng hơn sự tinh vi của bộ chọn. Ưu tiên một phần tử có định danh ổn định, thuộc tính dữ liệu được tài liệu hóa, mối quan hệ ngữ nghĩa, hoặc hình dạng URL bền. Một bộ chọn sao chép từ trình kiểm tra trình duyệt có thể bao gồm các bộ bọc bố cục và tên lớp được tạo mà thay đổi mà không thay đổi mô hình nội dung.

Đặc tả cấp độ 4 của các bộ chọn định nghĩa mô hình bộ chọn CSS được sử dụng trên toàn bộ công cụ trình duyệt và phân tích cú pháp. Trong thực tế, tập con an toàn nhất thường đơn giản: một bộ chọn thuộc tính cho một trường, một bộ chọn hình thành từ một thẻ, và một bộ chọn con trực tiếp khi sự phân cấp mang ý nghĩa. Tránh bộ chọn vị trí trừ khi vị trí đó là một phần của hợp đồng nguồn.

  • Ghim mỗi bản ghi tại một container lặp lại. Trích xuất tiêu đề, giá và liên kết tương đối với nút đó thay vì tìm kiếm toàn bộ tài liệu bên trong một vòng lặp.
  • Giải quyết các URL tương đối ngay lập tức. Xây dựng các URL tuyệt đối dựa trên URL phản hồi cuối cùng để các chuyển hướng và đường dẫn lồng nhau không làm hỏng các truy vấn lấy sau này.
  • Chuẩn hóa chỉ những gì mà sơ đồ yêu cầu. Cắt bỏ khoảng trắng xung quanh và phân tích các định dạng số đã biết, trong khi vẫn bảo tồn văn bản gốc khi việc diễn giải không chắc chắn.
  • Khẳng định danh tính của trang. Kiểm tra một tiêu đề, URL tiêu chuẩn hoặc dấu hiệu cấu trúc đã biết trước khi chấp nhận các hàng.

Xử lý Phân trang và Trạng thái Trang

Phân trang trong việc thu thập dữ liệu JavaScript nên tuân theo tín hiệu tiếp tục của nguồn. Đối với các trang số, trích xuất và giải quyết liên kết tiếp theo. Đối với các phản hồi dựa trên con trỏ, tồn tại con trỏ được trả về cùng với dữ liệu. Đối với danh sách vô hạn, một quy trình làm việc trong trình duyệt cần điều kiện hoàn thành có thể đo đạc như điều khiển bị vô hiệu hóa, số lượng mục không thay đổi, hoặc một dấu hiệu kết thúc rõ ràng.

Không giả định rằng một kết quả trống có nghĩa là bộ sưu tập đã kết thúc. Các hàng trống cũng có thể nghĩa là sai ngôn ngữ địa phương, một lớp đồng ý, một bộ chọn đã thay đổi, hoặc một shell được render từ phía khách hàng. Lưu trữ các chẩn đoán nhẹ nhàng với mỗi lần lấy dữ liệu: URL cuối, trạng thái, loại nội dung, kiểm tra danh tính trang, và số lượng container đã được khớp. Những giá trị đó giải thích một kết quả không có hàng mà không cần đặt toàn bộ phần thân trang vào nhật ký.

Biến Các Giá Trị Được Trích Xuất Thành Các Bản Ghi Đáng Tin Cậy

Một trình thu thập dữ liệu JavaScript trở nên đáng tin cậy khi việc trích xuất và chuẩn hóa là các chức năng riêng biệt. Việc trích xuất đọc những gì mà trang nói. Chuẩn hóa ánh xạ văn bản đó vào sơ đồ ứng dụng. Giữ cho ranh giới rõ ràng ngăn chặn mã bộ chọn từ việc âm thầm thực hiện các quyết định kinh doanh, chẳng hạn như coi “Không có sẵn” là số không hoặc chuyển đổi một định dạng thập phân khu vực với các quy tắc sai.

Định nghĩa các trường yêu cầu và tùy chọn trước khi viết các bộ chọn. Từ chối một bản ghi khi trường danh tính của nó không có. Bảo tồn các trường tùy chọn như null. Khử trùng với một khóa nguồn ổn định hoặc URL tiêu chuẩn hơn là một tiêu đề có thể thay đổi. Thêm dấu thời gian thu hồi vào lớp lưu trữ, không bằng cách thu thập đồng hồ trang.

Kiểm tra Pipeline Trước Khi Mở Rộng Nó

Bắt đầu với các tệp fixtures đã được lưu cho các kiểm tra phân tích cú pháp. Giữ một tệp HTML đại diện cho một trang bình thường, một tệp có trường tùy chọn bị thiếu, và một tệp mà nên thất bại trong kiểm tra danh tính. Các fixtures này khiến cho các thay đổi bộ chọn có thể xem xét và giữ cho các kiểm tra phân tích cú pháp độc lập với khả năng truy cập mạng.

Kiểm tra việc thu thập dữ liệu riêng biệt với một mục tiêu công khai nhỏ. Xác nhận URL cuối cùng, lớp trạng thái và dấu hiệu dự kiến. Các đặc tả ngữ nghĩa HTTP giải thích tại sao mã trạng thái mô tả phản hồi nhưng không thể chứng minh rằng cơ thể đó là trang kinh doanh mà bạn mong đợi. Một phản hồi 200 hợp lệ vẫn có thể là một trang đồng ý hoặc trang tài khoản.

Khi khối lượng công việc tăng lên, giới hạn độ song song theo máy chủ và giữ hàng đợi có thể quan sát được. Đo lường các bản ghi đã được chấp nhận, các bản ghi bị từ chối, danh tính trang bất ngờ và những lần bỏ lỡ bộ chọn. Một trình thu thập dữ liệu nhanh chóng lưu trữ trang sai còn tệ hơn một cái chậm chạp mà thất bại rõ ràng.

Kết luận

Việc thu thập dữ liệu web với JavaScript hoạt động tốt nhất khi quyết định vận chuyển được thực hiện trước khi công việc chọn lọc. Sử dụng fetch và Cheerio cho HTML phản hồi, chỉ hiển thị khi các kịch bản trang hoặc tương tác tạo ra trạng thái yêu cầu, và giữ cho việc trích xuất khác biệt với chuẩn hóa. Kết quả là một hệ thống nhỏ hơn với các tín hiệu thất bại rõ ràng và các bài kiểm tra vẫn hữu ích khi bố cục nguồn thay đổi.

Sẵn sàng xây dựng một quy trình làm việc dữ liệu JavaScript?

Kết nối một lớp thu thập dữ liệu Node.js với Scrapeless, giữ các bộ chọn hiện có của bạn và xác minh một quy trình làm việc công dữ liệu có giới hạn từ đầu đến cuối.

Đăng ký hôm nay và nhận được 5 đô la tín dụng miễn phíkhông yêu cầu thẻ tín dụng.

Nhận tín dụng 5 đô la của bạn →

Câu hỏi thường gặp

Có thể JavaScript thu thập dữ liệu một trang web mà không cần trình duyệt không?

Có. JavaScript có thể thu thập dữ liệu một trang được render từ máy chủ bằng một client HTTP và một trình phân tích HTML như Cheerio. Một trình duyệt chỉ cần thiết khi nội dung cần thiết được sản xuất bởi các kịch bản trang hoặc phụ thuộc vào tương tác.

Tại sao Cheerio không trả về các phần tử cho nội dung hiển thị trên màn hình?

Cheerio không trả về các phần tử khi những nút đó thiếu trong HTML mà nó nhận được. So sánh nguồn trang với DOM trực tiếp; nếu các kịch bản tạo ra các nút, hãy sử dụng thu thập dữ liệu đã được render hoặc nguồn cấu trúc cho phép.

Trình thu thập dữ liệu JavaScript nên sử dụng bộ chọn CSS hay XPath?

Các bộ chọn CSS thường là mặc định thực tiễn trong các bộ phân tích Node.js và API trình duyệt. XPath có thể diễn đạt một số truy vấn nặng về mối quan hệ, nhưng sự ổn định của bộ chọn và việc phân định rõ ràng quan trọng hơn ngôn ngữ truy vấn.

Trình thu thập dữ liệu JavaScript nên xử lý các markup đã thay đổi như thế nào?

Một trình thu thập dữ liệu JavaScript nên thất bại trong một kiểm tra cấu trúc rõ ràng, lưu lại một chẩn đoán nhỏ và yêu cầu cập nhật bộ chọn. Đối xử với số lượng không khớp là một trang trống thành công thì dễ dàng che giấu sự cố và có thể xóa dữ liệu hợp lệ phía dưới.

Việc thu thập dữ liệu web bằng JavaScript có hợp pháp không?

Việc thu thập dữ liệu web bằng JavaScript không tuân theo một quy tắc phổ quát nào. Giới hạn việc thu thập dữ liệu đến dữ liệu công khai có ủy quyền, xem xét luật và điều khoản trang web áp dụng, tôn trọng các quyền kiểm soát truy cập, và tìm kiếm lời khuyên pháp lý cho các trường hợp sử dụng nhạy cảm hoặc có tác động lớn.

Tài liệu tham khảo