Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Python

Kỹ thuật Scraping Trang web trong Python bằng Beautiful Soup: Tìm kiếm và Chỉnh sửa DOM

by
Difficulty:IntermediateLength:MediumLanguages:
This post is part of a series called Scraping Webpages in Python with Beautiful Soup.
Scraping Webpages in Python With Beautiful Soup: The Basics

Vietnamese (Tiếng Việt) translation by Dai Phong (you can also view the original English article)

Trong hướng dẫn trước, bạn đã học được những điều cơ bản của thư viện Beautiful Soup. Bên cạnh việc điều hướng trên cây DOM, bạn cũng có thể tìm kiếm các phần tử với một thuộc tính class hoặc id cho trước. Bạn cũng có thể sửa đổi cây DOM bằng thư viện này.

Trong hướng dẫn này, bạn sẽ được tìm hiểu về các phương thức khác nhau để giúp bạn tìm kiếm và sửa đổi. Chúng ta sẽ trích xuất trang Wikipedia về Python từ hướng dẫn trước của chúng ta.

Các Bộ lọc để Tìm kiếm trên Cây DOM

Beautiful Soup có rất nhiều phương thức để tìm kiếm trên cây DOM. Những phương thức này rất giống nhau và nhận các kiểu bộ lọc tương tự như là các đối số. Vì vậy, điều quan trọng là hiểu đúng các bộ lọc khác nhau trước khi đọc về các phương thức. Tôi sẽ sử dụng cùng một phương thức find_all() để giải thích sự khác nhau giữa các bộ lọc khác nhau.

Bộ lọc đơn giản nhất mà bạn có thể truyền cho bất kỳ phương thức tìm kiếm nào là một chuỗi. Beautiful Soup sẽ tìm kiếm thông qua tài liệu để tìm một thẻ khớp hoàn toàn với chuỗi.

Bạn cũng có thể truyền một đối tượng biểu thức chính quy vào phương thức find_all(). Lần này, Beautiful Soup sẽ lọc cây bằng cách khớp tất cả các thẻ với một biểu thức chính quy cho trước.

Code sẽ tìm kiếm tất cả các thẻ bắt đầu bằng chữ "h" và theo sau bởi một chữ số từ 1 đến 6. Nói cách khác, nó sẽ tìm kiếm tất cả các thẻ heading trong tài liệu.

Thay vì sử dụng regex, bạn có thể có được kết quả tương tự bằng cách truyền vào một danh sách tất cả các thẻ mà bạn muốn Beautiful Soup khớp trong tài liệu.

Bạn cũng có thể truyền True vào như một tham số cho phương thức find_all(). Sau đó code sẽ trả về tổng số các thẻ trong tài liệu. Đầu ra dưới đây có nghĩa là hiện có 4.339 thẻ trong trang Wikipedia mà chúng ta đang phân tích.

Nếu bạn vẫn không thể tìm thấy những gì bạn đang tìm kiếm với bất kỳ bộ lọc nào ở trên, bạn có thể định nghĩa hàm của riêng bạn để lấy một phần tử làm đối số duy nhất của nó. Hàm cũng cần phải trả về True nếu khớp và False nếu không khớp. Tùy thuộc vào những gì bạn cần, bạn có thể tạo hàm phức tạp cần thiết để thực hiện công việc. Dưới đây là một ví dụ rất đơn giản:

Hàm ở trên sẽ đi qua trang Wikipedia về Python và tìm kiếm các danh sách không thứ tự có hơn 20 phần tử con.

Tìm kiếm Cây DOM bằng Hàm được Tích hợp Sẵn

Một trong những phương thức phổ biến nhất để tìm kiếm thông qua DOM là find_all(). Nó sẽ đi qua tất cả các con của thẻ và trả về một danh sách tất cả các con phù hợp với tiêu chí tìm kiếm của bạn. Phương thức này có các tham số sau đây:

Tham số name là tên của thẻ mà bạn muốn hàm này tìm kiếm. Bạn có thể tự do cung cấp một chuỗi, một danh sách, một biểu thức chính quy, một hàm hay một giá trị True như một name.

Bạn cũng có thể lọc các phần tử trong cây DOM dựa trên các thuộc tính cơ bản khác nhau như id, href, vân vân. Bạn cũng có thể lấy tất cả các phần tử với một thuộc tính cụ thể bất kể giá trị của nó bằng attribute=True. Tìm kiếm các phần tử với một thuộc tính class cụ thể khác với tìm kiếm bằng các thuộc tính thông thường. Vì class là một từ khoá riêng trong Python, nên bạn sẽ phải sử dụng đối số từ khóa class_ khi tìm các phần tử bằng một class cụ thể.

Bạn có thể thấy rằng tài liệu có 1.734 thẻ với thuộc tính class và 425 thẻ với một thuộc tính id. Nếu bạn chỉ cần vài kết quả đầu tiên trong số những kết quả này, bạn có thể truyền vào một con số cho phương thức này như là giá trị limit (giới hạn). Truyền giá trị này vào sẽ hướng dẫn cho Beautiful Soup ngừng tìm kiếm các phần tử khác khi nó đã đạt đến một số lượng nhất định. Sau đây là một ví dụ:

Khi bạn sử dụng phương thức find_all(), bạn nói với Beautiful Soup hãy đi qua tất cả các con của một thẻ nhất định để tìm những gì bạn đang muốn tìm. Đôi khi, bạn muốn tìm kiếm một phần tử chỉ trong số các con trực tiếp trên một thẻ. Điều này có thể đạt được bằng cách truyền recursive=False vào phương thức find_all().

Nếu bạn quan tâm đến việc tìm kiếm chỉ một kết quả cho một truy vấn tìm kiếm cụ thể, bạn có thể sử dụng phương thức find() để tìm nó thay vì truyền vào limit=1 vào find_all(). Sự khác biệt duy nhất giữa các kết quả trả về bởi hai phương thức này là find_all() trả về một danh sách chỉ với một phần tử và find() chỉ trả về kết quả.

Phương thức find()find_all() đều duyệt qua tất cả các con của một thẻ đã cho để tìm kiếm một phần tử. Có mười phương thức khác tương tự mà bạn có thể sử dụng để duyệt qua cây DOM theo các hướng khác nhau.

Các phương thức find_parent()find_parents() duyệt qua cây DOM để tìm phần tử đã cho. Các phương thức find_next_sibling()find_next_siblings() sẽ lặp qua tất cả các anh chị em theo sau phần tử hiện tại. Tương tự, các phương thức find_previous_sibling()find_previous_siblings() sẽ lặp qua tất cả các anh chị em trước phần tử hiện tại.

Phương thức find_next()find_all_next() sẽ lặp qua tất cả các thẻ và chuỗi theo sau phần tử hiện tại. Tương tự, phương thức find_previous()find_all_previous() sẽ lặp qua tất cả các thẻ và chuỗi xuất hiện trước phần tử hiện tại.

Bạn cũng có thể tìm kiếm các phần tử bằng bộ chọn CSS với sự trợ giúp của phương thức select(). Sau đây là vài ví dụ:

Sửa đổi Cây DOM

Bạn không chỉ có thể duyệt qua cây DOM để tìm kiếm một phần tử mà còn có thể sửa đổi nó. Rất dễ dàng để đổi tên một thẻ và sửa đổi các thuộc tính của nó.

Tiếp tục với ví dụ trước của chúng ta, bạn có thể thay thế nội dung của một thẻ bằng một chuỗi cho trước sử dụng thuộc tính .string. Nếu bạn không muốn thay thế nội dung mà thêm một thứ gì đó vào cuối thẻ, bạn có thể sử dụng phương thức append().

Tương tự, nếu bạn muốn chèn một cái gì đó bên trong một thẻ tại một vị trí cụ thể, bạn có thể sử dụng phương thức insert(). Tham số đầu tiên của phương thức này là vị trí hoặc chỉ mục mà tại đó bạn muốn chèn nội dung, và tham số thứ hai chính là nội dung. Bạn có thể xóa bỏ tất cả mọi nội dung bên trong thẻ bằng phương thức clear(). Điều này sẽ chỉ giữ lại cho bạn cái thẻ và các thuộc tính của nó.

Ở đầu của phần này, bạn đã chọn heading cấp hai từ tài liệu và thay đổi nó thành heading cấp ba. Sử dụng bộ chọn tương tự một lần nữa sẽ hiển thị cho bạn hai heading cấp độ kế tiếp xuất hiện sau cái ban đầu. Điều này dễ hiểu bởi vì heading ban đầu không còn là heading cấp hai.

Heading ban đầu bây giờ có thể được chọn bằng h3:nth-type-type(2). Nếu bạn muốn loại bỏ hoàn toàn một phần tử hoặc thẻ và tất cả nội dung bên trong nó khỏi cây, bạn có thể sử dụng phương thức decompose().

Một khi bạn đã loại bỏ heading ban đầu, thì heading ở vị trí thứ ba thay thế vị trí của nó.

Nếu bạn muốn xóa một thẻ và nội dung của nó khỏi cây nhưng không muốn phá hủy hoàn toàn thẻ, bạn có thể sử dụng phương thức extract(). Phương thức này sẽ trả về thẻ mà nó đã trích xuất. Bây giờ bạn sẽ có hai cây khác nhau để bạn có thể phân tích. Gốc của cây mới sẽ là thẻ mà bạn vừa trích xuất ra.

Bạn cũng có thể thay thế một thẻ bên trong cây bằng một cái gì đó khác mà bạn chọn bằng phương thức replace_with(). Phương thức này sẽ trả về thẻ hoặc chuỗi mà nó thay thế. Nó có thể hữu ích nếu bạn muốn đặt nội dung thay thế ở một nơi khác trong tài liệu.

Trong đoạn code ở trên, heading chính của tài liệu đã được thay thế bằng một thẻ b. Tài liệu không còn thẻ h1 nữa, và đó là lý do tại sao print(soup.h1) bây giờ in ra None.

Tóm tắt

Sau khi đọc hai hướng dẫn trong loạt bài này, bây giờ bạn đã có thể phân tích các trang web khác nhau và trích xuất dữ liệu quan trọng từ tài liệu. Bạn cũng có thể truy xuất trang web gốc, sửa đổi nó cho phù hợp với nhu cầu của riêng bạn và lưu phiên bản đã sửa đổi tại cục bộ.

Nếu bạn có bất kỳ câu hỏi nào liên quan đến hướng dẫn này, xin vui lòng cho tôi biết trong phần bình luận nhé.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.