sách gpt4 ăn đã đi

Điều gì gây ra kết quả `None` từ các hàm BeautifulSoup? Làm cách nào để tránh "AttributionError: đối tượng 'NoneType' không có thuộc tính..." với đối tượng 'NoneType' không có thuộc tính..." với beauty súp?)

In lại Tác giả: trợ lý lỗi Thời gian cập nhật: 27-10-2023 20:47:15 41 4
mua khóa gpt4 giày nike



Thông thường khi tôi thử sử dụng BeautifulSoup để phân tích một trang web, tôi nhận được một Không có kết quả từ hàm BeautifulSoup, hoặc là một Thuộc tínhError được nâng lên.

Thông thường khi tôi cố gắng phân tích cú pháp một trang web bằng BeautifulSoup, hàm BeautifulSoup nhận được kết quả KHÔNG, nếu không thì AttributionError sẽ xuất hiện.


Sau đây là một số ví dụ độc lập (tức là không cần truy cập internet vì dữ liệu được mã hóa cứng), dựa trên một ví dụ trong tài liệu, không yêu cầu truy cập Internet:

Dưới đây là một số ví dụ độc lập (tức là không cần truy cập Internet vì dữ liệu được mã hóa cứng) dựa trên ví dụ từ tài liệu không yêu cầu quyền truy cập Internet:


>>> html_doc = """
... Câu chuyện về chú chuột sóc
...
...

Câu chuyện về chú chuột sóc


...
...

Ngày xửa ngày xưa có ba cô em gái nhỏ; và tên của họ là
... Elsie,
... Lacie
... Tillie;
... và họ sống dưới đáy giếng.


...
...

...


... """
>>>
>>> từ bs4 nhập BeautifulSoup
>>> súp = BeautifulSoup(html_doc, 'html.parser')
>>> in(soup.sister)
Không có
>>> in(soup.find('a', class_='brother'))
Không có
>>> in(soup.select_one('a.brother'))
Không có
>>> soup.select_one('a.brother').text
Theo dõi (cuộc gọi gần đây nhất là cuộc gọi cuối cùng):
Tệp "", dòng 1, trong
AttributeError: Đối tượng 'NoneType' không có thuộc tính 'text'

Tôi biết rằng Không có là một giá trị đặc biệt trong Python và rằng Không cóLoại là loại của nó; Nhưng... Bây giờ thì sao? Tại sao tôi nhận được những kết quả này và tôi có thể xử lý chúng như thế nào cho đúng?

Tôi biết Không có giá trị đặc biệt trong Python và NoneType là loại của nó; nhưng... lần này là gì? Tại sao tôi nhận được những kết quả này và làm cách nào để xử lý chúng một cách chính xác?




Câu hỏi này đặc biệt liên quan đến các phương thức BeautifulSoup tìm kiếm một kết quả duy nhất (như .tìm thấy). Nếu bạn nhận được kết quả này bằng cách sử dụng một phương pháp như .tìm_tất_cả thường trả về một danh sách, điều này có thể là do sự cố với trình phân tích cú pháp HTML. Xem Lỗi đối tượng 'NoneType' của Python Beautiful Soup để biết thêm chi tiết.

Câu hỏi này đặc biệt về các phương thức BeautifulSoup, chỉ tìm kiếm kết quả (như .find). Nếu bạn nhận được kết quả này bằng cách sử dụng một phương thức như .findall, phương thức này thường trả về một danh sách, thì điều này có thể là do trình phân tích cú pháp HTML có vấn đề. Xem lỗi đối tượng 'NoneType' của Python Beautiful Soup để biết chi tiết.


Thêm câu trả lời
Khuyến nghị câu trả lời tuyệt vời

Các vấn đề phổ biến với dữ liệu thực tế


Tất nhiên, việc sử dụng một ví dụ nhỏ về văn bản được mã hóa cứng sẽ làm rõ lý do tại sao một số lệnh gọi đến tìm thấy v.v. các phương pháp không thành công - nội dung đơn giản là không có ở đó và nó ngay lập tức rõ ràng chỉ bằng cách đọc một vài dòng dữ liệu. Bất kỳ nỗ lực nào để gỡ lỗi mã nên bắt đầu bằng cách kiểm tra cẩn thận lỗi đánh máy:

Tất nhiên, một ví dụ nhỏ sử dụng văn bản được mã hóa cứng sẽ làm rõ lý do tại sao một số lệnh gọi đến các phương thức như find không thành công - đơn giản là nội dung không có ở đó và điều đó hiển nhiên ngay sau khi chỉ đọc một vài dòng dữ liệu. Mọi nỗ lực gỡ lỗi mã nên bắt đầu bằng việc kiểm tra kỹ lỗi chính tả:


>>> html_doc = """
... Câu chuyện về chú chuột sóc
...
...

Câu chuyện về chú chuột sóc


...
...

Ngày xửa ngày xưa có ba cô em gái nhỏ; và tên của họ là
... Elsie,
... Lacie
... Tillie;
... và họ sống dưới đáy giếng.


...
...

...


... """
>>> từ bs4 nhập BeautifulSoup
>>> súp = BeautifulSoup(html_doc, 'html.parser')
>>> print(soup.find('a', class_='sistre')) # lưu ý lỗi đánh máy
Không có
>>> print(soup.find('a', class_='sister')) # đã sửa
Elsie

Tuy nhiên, trong thế giới thực, các trang web có thể dễ dàng kéo dài nhiều kilobyte hoặc thậm chí là megabyte văn bản, do đó, loại kiểm tra trực quan đó là không thực tế. Nhìn chung, đối với các tác vụ phức tạp hơn, trước tiên bạn nên dành thời gian để kiểm tra xem một trang web nhất định có cung cấp Giao diện lập trình ứng dụng (API) để truy cập dữ liệu, thay vì loại bỏ nó khỏi nội dung trang. Nhiều trang web vui vẻ cung cấp dữ liệu trực tiếp, theo định dạng dễ sử dụng hơn (vì nó cụ thể được thiết kế để sử dụng như dữ liệu, thay vì để điền vào chỗ trống của một trang web "mẫu").

Tuy nhiên, trong thế giới thực, các trang web có thể dễ dàng kéo dài hàng kilobyte hoặc thậm chí megabyte văn bản, vì vậy việc kiểm tra trực quan này là không thực tế. Nói chung, đối với các tác vụ phức tạp hơn, trước tiên bạn nên dành thời gian kiểm tra xem một trang web nhất định có cung cấp API để truy cập dữ liệu hay không, thay vì trích xuất dữ liệu từ nội dung trang. Nhiều trang web sẵn lòng cung cấp dữ liệu trực tiếp ở định dạng dễ sử dụng hơn (vì nó được thiết kế đặc biệt để sử dụng làm dữ liệu chứ không phải để lấp đầy khoảng trống của trang web "mẫu").


Như một bản tóm tắt sơ bộ: một API bao gồm điểm cuối - URI có thể được truy cập trực tiếp theo cùng cách như URL trang web, nhưng phản hồi là thứ gì đó khác ngoài trang web. Định dạng phổ biến nhất cho đến nay là JSON, mặc dù có thể sử dụng bất kỳ định dạng dữ liệu nào tùy thuộc vào trường hợp sử dụng chính xác - ví dụ, bảng dữ liệu có thể được trả về dưới dạng CSV. Để sử dụng điểm cuối JSON chuẩn, hãy viết mã xác định URI chính xác để sử dụng, tải nó bình thường, đọc và phân tích phản hồi JSONvà tiếp tục với dữ liệu đó. (Trong một số trường hợp, "khóa API" sẽ là cần thiết; một số công ty sử dụng khóa này để tính phí truy cập dữ liệu cao cấp, nhưng thường chỉ để các yêu cầu thông tin có thể được liên kết với một người dùng cụ thể.)

Tổng quan sơ bộ: API bao gồm điểm cuối - URI, có thể được truy cập trực tiếp theo cách tương tự như URL trang web, nhưng phản hồi không phải là trang web. Cho đến nay, định dạng phổ biến nhất là JSON, nhưng mọi định dạng dữ liệu đều có thể được sử dụng tùy thuộc vào trường hợp sử dụng cụ thể - ví dụ: bảng dữ liệu có thể được trả về dưới dạng CSV. Để sử dụng điểm cuối JSON tiêu chuẩn, hãy viết mã để xác định URI chính xác sẽ sử dụng, tải URI bình thường, đọc và phân tích cú pháp phản hồi JSON, đồng thời tiếp tục xử lý dữ liệu. (Trong một số trường hợp, sẽ cần có "khóa API"; một số công ty sử dụng các khóa này để tính phí truy cập dữ liệu cao cấp, nhưng điều này thường chỉ để ràng buộc các yêu cầu cung cấp thông tin cho một người dùng cụ thể.)


Thông thường, điều này dễ hơn nhiều so với bất kỳ điều gì có thể thực hiện với BeautifulSoup và cũng sẽ tiết kiệm băng thông. Các công ty cung cấp API được ghi chép công khai cho các trang web của họ muốn bạn sử dụng chúng; nói chung, điều này tốt hơn cho tất cả mọi người liên quan.

Điều này thường dễ dàng hơn nhiều so với thực hiện bất kỳ điều gì với BeautifulSoup và sẽ tiết kiệm băng thông. Các công ty cung cấp API được ghi chép công khai cho trang web của họ muốn bạn sử dụng chúng; điều này thường tốt hơn cho tất cả những người tham gia.


Sau khi đã nói như vậy, đây là một số lý do phổ biến tại sao phản hồi web được phân tích bởi BeautifulSoup không chứa những gì nó được mong đợi, hoặc là cách khác không dễ dàng để xử lý.

Tuy nhiên, đây là một số lý do phổ biến khiến phản hồi web được BeautifulSoup phân tích cú pháp không chứa nội dung mà nó mong đợi hoặc không thể xử lý trực tiếp.


Nội dung được tạo động (phía máy khách)


Hãy nhớ rằng BeautifulSoup xử lý HTML tĩnh, không phải JavaScript. Nó có thể chỉ một sử dụng dữ liệu sẽ được nhìn thấy khi truy cập trang web với JavaScript bị vô hiệu hóa.

Hãy nhớ rằng, BeautifulSoup xử lý HTML tĩnh chứ không phải JavaScript. Nó chỉ có thể sử dụng dữ liệu bạn sẽ thấy nếu bạn truy cập trang web bị tắt JavaScript.


Các trang web hiện đại thường tạo ra rất nhiều dữ liệu trang bằng cách chạy JavaScript trong trình duyệt web của khách hàng. Trong những trường hợp điển hình, mã JavaScript này sẽ tạo nhiều yêu cầu HTTP hơn để lấy dữ liệu, định dạng dữ liệu và chỉnh sửa trang hiệu quả (thay đổi DOM) ngay lập tức. BeautifulSoup không thể xử lý bất kỳ điều này. Nó thấy mã JavaScript trong trang web như chỉ là thêm văn bản.

Các trang web hiện đại thường tạo ra lượng lớn dữ liệu trang bằng cách chạy JavaScript trong trình duyệt web của máy khách. Trong trường hợp điển hình, mã JavaScript này sẽ thực hiện nhiều yêu cầu HTTP hơn để lấy dữ liệu, định dạng dữ liệu và chỉnh sửa trang một cách hiệu quả một cách linh hoạt (thay đổi DOM). BeautifulSoup không thể giải quyết được những vấn đề này. Nó xử lý mã JavaScript trong các trang web dưới dạng văn bản hơn.


ĐẾN quét một trang web động, hãy cân nhắc sử dụng Selenium để mô phỏng tương tác với trang web.

Để tạo một trang web động, hãy cân nhắc sử dụng Selify để mô phỏng các tương tác với các trang web.


Thay vào đó, điều tra những gì xảy ra khi sử dụng trang web bình thường. Thông thường, mã JavaScript trên trang sẽ thực hiện lệnh gọi đến các điểm cuối API, có thể thấy trên tab "Mạng" (hoặc tên tương tự) của bảng điều khiển dành cho nhà phát triển của trình duyệt web. Đây có thể là gợi ý tuyệt vời để hiểu API của trang web, ngay cả khi không dễ tìm được tài liệu hướng dẫn tốt.

Hoặc, điều tra điều gì xảy ra khi bạn sử dụng trang web một cách bình thường. Thông thường, mã JavaScript trên trang sẽ gọi điểm cuối API, điểm cuối này có thể được nhìn thấy trên tab "Mạng" (hoặc tên tương tự) của bảng điều khiển dành cho nhà phát triển của trình duyệt web. Ngay cả khi khó tìm được tài liệu tốt thì đây vẫn là mẹo hay để hiểu API trang web của bạn.


Kiểm tra tác nhân người dùng


Mỗi yêu cầu HTTP bao gồm tiêu đề cung cấp thông tin cho máy chủ để giúp máy chủ xử lý yêu cầu. Bao gồm thông tin về bộ nhớ đệm (để máy chủ có thể quyết định xem có thể sử dụng phiên bản dữ liệu được lưu trong bộ nhớ đệm hay không), định dạng dữ liệu có thể chấp nhận được (để máy chủ có thể áp dụng nén cho phản hồi để tiết kiệm băng thông) và về máy khách (để máy chủ có thể điều chỉnh đầu ra để hiển thị đúng trên mọi trình duyệt web).

Mọi yêu cầu HTTP đều bao gồm các tiêu đề cung cấp thông tin cho máy chủ để giúp máy chủ xử lý yêu cầu. Thông tin này bao gồm thông tin về bộ nhớ đệm (để máy chủ có thể quyết định liệu nó có thể sử dụng phiên bản dữ liệu được lưu trong bộ nhớ đệm hay không), các định dạng dữ liệu được chấp nhận (để máy chủ có thể nén phản hồi nhằm tiết kiệm băng thông) và thông tin về máy khách (để máy chủ Bạn có thể điều chỉnh đầu ra để nó hiển thị chính xác trên mọi trình duyệt web).


Phần cuối cùng được thực hiện bằng cách sử dụng phần "user-agent" của tiêu đề. Tuy nhiên, theo mặc định, các thư viện HTML (như la hétyêu cầu) thường sẽ không yêu cầu bất kỳ trình duyệt web nào - về phía máy chủ, đây là một dấu hiệu cảnh báo lớn cho biết "người dùng này đang chạy một chương trình để thu thập dữ liệu trang web chứ không thực sự sử dụng trình duyệt web".

Phần cuối cùng được thực hiện bằng cách sử dụng phần "tác nhân người dùng" của tiêu đề. Tuy nhiên, theo mặc định, các thư viện HTML như urllib và các yêu cầu thường không khai báo bất kỳ trình duyệt web nào -- về phía máy chủ, đây là một dấu hiệu cảnh báo lớn rằng "người dùng này đang chạy một chương trình để quét web". hơn là thực sự sử dụng trình duyệt web".


Hầu hết các công ty không thích điều đó lắm. Họ muốn bạn thấy trang web thực tế (bao gồm cả quảng cáo). Vì vậy, máy chủ có thể chỉ tạo ra một số loại trang giả (hoặc lỗi HTTP) thay thế. (Lưu ý: điều này có thể bao gồm lỗi "quá nhiều yêu cầu", nếu không sẽ chỉ ra giới hạn tốc độ như mô tả trong phần tiếp theo.)

Hầu hết các công ty không thích điều này lắm. Họ muốn bạn xem trang web thực tế (bao gồm cả quảng cáo). Do đó, máy chủ có thể tạo ra một số loại trang giả mạo (hoặc lỗi HTTP). (Lưu ý: Điều này có thể bao gồm lỗi "quá nhiều yêu cầu", nếu không nó sẽ dẫn đến giới hạn tốc độ như được mô tả trong phần tiếp theo.)


Để giải quyết vấn đề này, hãy đặt tiêu đề theo cách phù hợp với thư viện HTTP:

Để giải quyết vấn đề này, hãy đặt tiêu đề cho thư viện HTTP theo cách thích hợp:



Giới hạn tỷ lệ


Một dấu hiệu khác của "bot" là cùng một người dùng yêu cầu nhiều trang web nhanh nhất có thể, hoặc thậm chí không đợi một trang tải xong trước khi yêu cầu trang khác. Máy chủ theo dõi người đang thực hiện yêu cầu theo IP (và có thể theo thông tin "dấu vân tay" khác) ngay cả khi không yêu cầu đăng nhập và có thể chỉ từ chối nội dung trang cho người yêu cầu trang quá nhanh.

Một dấu hiệu khác của "bot" là cùng một người dùng đang yêu cầu nhiều trang web nhanh như kết nối internet cho phép hoặc thậm chí không đợi một trang tải xong trước khi yêu cầu một trang khác. Ngay cả khi không cần đăng nhập, máy chủ vẫn theo dõi xem ai đang thực hiện yêu cầu bằng IP (và có thể cả thông tin "dấu vân tay" khác) và có thể đơn giản từ chối nội dung trang đối với người yêu cầu trang quá nhanh.


Các giới hạn như thế này thường sẽ áp dụng như nhau cho một API (nếu có) - máy chủ đang tự bảo vệ mình khỏi tấn công từ chối dịch vụ. Vì vậy, nhìn chung giải pháp duy nhất là sửa mã để thực hiện ít yêu cầu hơn, ví dụ như tạm dừng chương trình giữa các yêu cầu.

Những hạn chế như vậy cũng thường áp dụng cho API (nếu có) - máy chủ đang tự bảo vệ mình khỏi các cuộc tấn công từ chối dịch vụ. Do đó, giải pháp duy nhất thường là sửa mã để thực hiện các yêu cầu ít thường xuyên hơn, chẳng hạn như bằng cách tạm dừng chương trình giữa các yêu cầu.


Xem ví dụ Cách tránh lỗi HTTP 429 (Quá nhiều yêu cầu) python.

Ví dụ: xem Cách tránh Lỗi HTTP 429 (Quá nhiều yêu cầu).


Yêu cầu đăng nhập


Điều này khá đơn giản: nếu nội dung thường chỉ dành cho người dùng đã đăng nhập thì tập lệnh thu thập dữ liệu sẽ phải mô phỏng bất kỳ quy trình đăng nhập nào mà trang web sử dụng.

Điều này khá đơn giản: nếu nội dung thường chỉ có sẵn cho người dùng đã đăng nhập thì tập lệnh thu thập thông tin sẽ phải mô phỏng bất kỳ quy trình đăng nhập nào mà trang web sử dụng.


Tên động/ngẫu nhiên phía máy chủ


Hãy nhớ rằng máy chủ quyết định gửi gì cho mỗi yêu cầu. Nó không nhất thiết phải giống nhau mỗi lần và không nhất thiết phải tương ứng với bất kỳ tệp tin thực tế nào trong bộ nhớ lưu trữ cố định của máy chủ.

Hãy nhớ rằng, máy chủ quyết định những gì sẽ gửi cho mỗi yêu cầu. Nó không nhất thiết phải giống nhau mọi lúc và cũng không nhất thiết phải tương ứng với bất kỳ tệp thực tế nào trong bộ lưu trữ vĩnh viễn của máy chủ.


Ví dụ, nó có thể bao gồm tên lớp hoặc ID ngẫu nhiên được tạo ra khi đang chạy, có khả năng khác nhau mỗi lần truy cập trang. Khó hơn nữa: do lưu trữ đệm, tên có thể xuất hiện để duy trì sự nhất quán... cho đến khi bộ nhớ đệm hết hạn.

Ví dụ: nó có thể bao gồm các tên hoặc ID lớp ngẫu nhiên được tạo động có thể khác nhau mỗi khi trang được truy cập. Đây là phần phức tạp hơn: Do bộ nhớ đệm, tên có thể nhất quán... cho đến khi bộ nhớ đệm hết hạn.


Nếu tên lớp hoặc ID trong nguồn HTML có vẻ như có một loạt các ký tự rác vô nghĩa, hãy cân nhắc không dựa vào việc tên đó phải nhất quán - hãy nghĩ đến một cách khác để xác định dữ liệu cần thiết. Ngoài ra, có thể tìm ra ID thẻ một cách động, bằng cách xem một số khác thẻ trong HTML đề cập đến nó.

Nếu tên lớp hoặc ID trong tệp nguồn HTML của bạn dường như chứa nhiều ký tự rác vô nghĩa, hãy cân nhắc việc không dựa vào tên đó để thống nhất -- hãy nghĩ cách khác để xác định dữ liệu cần thiết. Ngoài ra, ID thẻ có thể được tính toán linh hoạt bằng cách xem cách các thẻ khác trong HTML tham chiếu đến nó.


Dữ liệu có cấu trúc không đều


Ví dụ, giả sử trang "Giới thiệu" của trang web công ty hiển thị thông tin liên lạc của một số nhân viên chủ chốt, với

thẻ bao bọc thông tin của từng người. Một số trong số chúng liệt kê địa chỉ email, và một số khác thì không; khi địa chỉ không được liệt kê, thẻ tương ứng hoàn toàn không có, thay vì chỉ không có bất kỳ văn bản nào:

Ví dụ: giả sử trang "Giới thiệu" trên trang web của công ty hiển thị thông tin liên hệ của một số nhân viên chủ chốt và mục đích sử dụng.

Tags gói thông tin của mọi người. Một số trong số chúng liệt kê địa chỉ email, trong khi một số khác thì không; khi địa chỉ không được liệt kê, đánh dấu tương ứng hoàn toàn không có, thay vì không có bất kỳ văn bản nào:


súp = BeautifulSoup("""
Nhân viên công ty
Tên: Alice A. Email:

Tên: Bob B. Email:

Tên: Cameron C.


Xem sitemap của VNExpress """, 'html.parser')

Việc lặp lại và in từng tên và email sẽ không thành công vì thiếu email:

Cố gắng lặp lại và in từng tên và email sẽ không thành công vì thiếu email:


>>> cho nhân viên trong soup.select('div.staff'):
... print('Tên:', staff.find('span', class_='name').text)
... in('Email:', staff.find('span', class_='email').text)
...
Tên: Alice A.
E-mail: [email protected]
Tên: Bob B.
E-mail: [email protected]
Tên: Cameron C.
Theo dõi (cuộc gọi gần đây nhất là cuộc gọi cuối cùng):
Tệp "", dòng 3, trong
AttributeError: Đối tượng 'NoneType' không có thuộc tính 'text'

Đây chỉ là sự bất thường cần phải lường trước và giải quyết.

Đó chỉ là sự bất thường cần được dự đoán và xử lý.


Tuy nhiên, tùy thuộc vào các yêu cầu chính xác, có thể có những cách tiếp cận thanh lịch hơn. Ví dụ, nếu mục tiêu chỉ đơn giản là thu thập tất cả các địa chỉ email (mà không cần lo lắng về tên), trước tiên chúng ta có thể thử mã xử lý các thẻ con với một danh sách hiểu biết:

Tuy nhiên, tùy thuộc vào yêu cầu chính xác, có thể có cách tiếp cận thanh lịch hơn. Ví dụ: nếu mục tiêu chỉ là thu thập tất cả địa chỉ email (và không phải lo lắng về tên), trước tiên chúng tôi có thể thử sử dụng tính năng hiểu danh sách để xử lý mã của thẻ con:


>>> [staff.find('span', class_='email').text cho nhân viên trong soup.select('div.staff')]
Theo dõi (cuộc gọi gần đây nhất là cuộc gọi cuối cùng):
Tệp "", dòng 1, trong
Tệp "", dòng 1, trong
AttributeError: Đối tượng 'NoneType' không có thuộc tính 'text'

Chúng ta có thể giải quyết vấn đề bằng cách thay vào đó lấy một danh sách email cho mỗi tên (sẽ có 0 hoặc 1 phần tử) và sử dụng một danh sách lồng nhau được thiết kế để có kết quả phẳng:

Chúng ta có thể giải quyết vấn đề này bằng cách lấy danh sách email cho mỗi tên (sẽ có 0 hoặc 1 phần tử) và sử dụng cách hiểu danh sách lồng nhau được thiết kế cho kết quả phẳng:


>>> [email.text dành cho nhân viên trong soup.select('div.staff') dành cho email trong staff.find_all('span', class_='email')]
['[email protected]', '[email protected]']

Hoặc chúng ta có thể sử dụng một truy vấn tốt hơn:

Ngoài ra, chúng ta có thể chỉ cần sử dụng một truy vấn tốt hơn:


>>> # có lẽ chúng ta không cần phải kiểm tra thẻ div?
>>> [email.text cho email trong soup.select('span.email')]
['[email protected]', '[email protected]']
>>> # Hoặc nếu chúng ta làm vậy, hãy sử dụng bộ chọn CSS chuyên dụng:
>>> # tìm kiếm span ở bất kỳ đâu bên trong div
>>> [email.text cho email trong soup.select('div.staff span.email')]
['[email protected]', '[email protected]']
>>> # yêu cầu div là phần tử cha trực tiếp của span
>>> [email.text cho email trong soup.select('div.staff > span.email')]
['[email protected]', '[email protected]']

HTML không hợp lệ đã được "sửa" bởi trình duyệt


HTML rất phức tạp, và HTML thực tế thường đầy lỗi đánh máy và lỗi nhỏ mà trình duyệt bỏ qua. Không ai sử dụng trình duyệt cầu kỳ chỉ hiện thông báo lỗi nếu nguồn trang không tuân thủ chuẩn 100% (cả lúc đầu và sau mỗi thao tác JavaScript) - vì một phần rất lớn của trang web sẽ biến mất khỏi tầm nhìn.

HTML rất phức tạp và HTML trong thế giới thực thường có nhiều lỗi chính tả và lỗi nhỏ mà trình duyệt che đậy. Không ai sẽ sử dụng trình duyệt mô phạm bật lên thông báo lỗi (ở đầu hoặc sau mỗi thao tác JavaScript) nếu nguồn trang không tuân thủ đầy đủ 100% - do một phần lớn như vậy của trang web sẽ biến mất từ tầm nhìn.


BeautifulSoup cho phép điều này bằng cách để trình phân tích cú pháp HTML xử lý nó và để người dùng chọn một trình phân tích cú pháp HTML nếu có những trình phân tích cú pháp khác được cài đặt ngoài trình phân tích cú pháp thư viện chuẩn. Mặt khác, trình duyệt web có trình phân tích cú pháp HTML riêng được tích hợp sẵn, có thể dễ dãi hơn nhiều và cũng có nhiều cách tiếp cận nặng nề hơn để "sửa" lỗi.

BeautifulSoup cho phép trình phân tích cú pháp HTML xử lý nó, cho phép người dùng chọn trình phân tích cú pháp HTML nếu các trình phân tích cú pháp khác được cài đặt ngoài thư viện chuẩn. Mặt khác, các trình duyệt web có trình phân tích cú pháp HTML riêng được tích hợp sẵn, điều này có thể nhẹ nhàng hơn nhiều và áp dụng cách tiếp cận chặt chẽ hơn để "sửa" lỗi.


TRONG ví dụ này, trình duyệt của OP đã hiển thị một thẻ bên trong một trong chế độ xem "Kiểm tra phần tử" của nó, mặc dù điều đó không có trong nguồn trang thực tếMặt khác, trình phân tích cú pháp HTML được BeautifulSoup sử dụng thì không; nó chỉ đơn giản chấp nhận có các thẻ lồng nhau trực tiếp bên trong một . Vì vậy, tương ứng Nhãn phần tử được tạo bởi BeautifulSoup để biểu diễn bảng, được báo cáo Không có cho nó tbody thuộc tính.

Trong trường hợp này, trình duyệt của OP ở chế độ xem "Kiểm tra phần tử"

Hiển thị trongthẻ, ngay cả khi thẻ không tồn tại trong mã nguồn trang thực tế. Mặt khác, trình phân tích cú pháp HTML được BeautifulSoup sử dụng không thực hiện việc này;Thẻ được lồng trực tiếp bên trong
ở giữa. Do đó, phần tử thẻ tương ứng mà BeautifulSoup tạo để thể hiện bảng không báo cáo gì trong thuộc tính tbody của nó.


Thông thường, những vấn đề như thế này có thể được giải quyết bằng cách tìm kiếm trong một phần phụ của súp (ví dụ bằng cách sử dụng bộ chọn CSS), thay vì cố gắng "bước vào" từng thẻ lồng nhau. Điều này tương tự như vấn đề dữ liệu có cấu trúc không đều.

Thông thường, những vấn đề như thế này có thể được giải quyết bằng cách tìm kiếm trong một phần phụ của SOUP (ví dụ: sử dụng bộ chọn CSS), thay vì cố gắng "xem qua" từng thẻ lồng nhau. Điều này tương tự như vấn đề dữ liệu có cấu trúc không đều.


Không phải HTML chút nào


Vì đôi khi nó xuất hiện và cũng liên quan đến cảnh báo ở trên: không phải mọi yêu cầu web sẽ tạo ra một trang web. Ví dụ, một hình ảnh không thể được xử lý bằng BeautifulSoup; nó thậm chí không thể biểu diễn chữ, chưa nói đến HTML. Ít rõ ràng hơn, một URL có thứ gì đó giống như /api/v1/ ở giữa có khả năng cao là được dùng làm điểm cuối API, không phải trang web; phản hồi có khả năng cao là dữ liệu được định dạng JSON, không phải HTML. BeautifulSoup không phải là công cụ phù hợp để phân tích dữ liệu này.

Bởi vì đôi khi nó xuất hiện và cũng liên quan đến cảnh báo ở trên cùng: không phải mọi yêu cầu web đều dẫn đến một trang web. Ví dụ: một hình ảnh không thể được xử lý bằng BeautifulSoup; nó thậm chí không thể biểu thị văn bản, chứ đừng nói đến HTML. Điều ít rõ ràng hơn là một URL có nội dung như /api/v1/ ở giữa có thể là điểm cuối API chứ không phải trang web; phản hồi có thể là dữ liệu có định dạng JSON, không phải HTML. BeautifulSoup không phải là công cụ thích hợp để phân tích dữ liệu này.


Các trình duyệt web hiện đại thường tạo ra một tài liệu HTML "wrapper" cho dữ liệu như vậy. Ví dụ, nếu tôi xem một hình ảnh trên Imgur, với URL hình ảnh trực tiếp (không phải một trong những trang "gallery" của Imgur), và mở chế độ xem web-inspector của trình duyệt, tôi sẽ thấy một cái gì đó như (với một số chỗ giữ chỗ được thay thế):

Các trình duyệt web hiện đại thường tạo tài liệu HTML "trình bao bọc" cho dữ liệu này. Ví dụ: nếu tôi xem một hình ảnh trên Imgur bằng URL hình ảnh trực tiếp (trái ngược với trang "Thư viện" của chính Imgur) và mở chế độ xem trình kiểm tra web của trình duyệt, tôi sẽ thấy một cái gì đó như thế này (với một số chi tiết):



<đầu>



[tên hình ảnh] ([định dạng] Hình ảnh, [chiều rộng]×[chiều cao] pixel) — Đã chia tỷ lệ ([hệ số tỷ lệ])


[url]



Đối với JSON, một trình bao bọc phức tạp hơn nhiều được tạo ra - thực chất đây là một phần trong cách triển khai trình xem JSON của trình duyệt.

Đối với JSON, một trình bao bọc phức tạp hơn nhiều được tạo ra - đây thực sự là một phần trong cách triển khai trình xem JSON của trình duyệt.


Điều quan trọng cần lưu ý ở đây là BeautifulSoup sẽ không thấy bất kỳ HTML nào như vậy khi mã Python thực hiện yêu cầu web - yêu cầu đó không bao giờ được lọc qua trình duyệt web và chính trình duyệt cục bộ tạo ra mã HTML này chứ không phải máy chủ từ xa.

Điều quan trọng cần lưu ý ở đây là khi mã Python thực hiện một yêu cầu web, BeautifulSoup sẽ không thấy bất kỳ HTML nào như vậy - yêu cầu không bao giờ được lọc qua trình duyệt web và được tạo bởi trình duyệt cục bộ chứ không phải máy chủ từ xa.



Tổng quan


Nhìn chung, BeautifulSoup cung cấp hai loại truy vấn: loại tìm kiếm đơn lẻ cụ thể phần tử (thẻ, thuộc tính, văn bản, v.v.) và những phần tử tìm kiếm mỗi yếu tố đáp ứng các yêu cầu.

Nhìn chung, BeautifulSoup cung cấp hai loại truy vấn: truy vấn tìm một thành phần cụ thể (thẻ, thuộc tính, văn bản, v.v.) và truy vấn tìm mọi thành phần đáp ứng yêu cầu.


Đối với nhóm sau - những người như .tìm_tất_cả có thể đưa ra nhiều kết quả - giá trị trả về sẽ là một danh sách. Nếu không có kết quả nào, thì danh sách chỉ đơn giản là trống rỗng. Đẹp và đơn giản.

Đối với nhóm sau -- những nhóm như .findall có thể cung cấp nhiều kết quả -- giá trị trả về sẽ là một danh sách. Nếu không có kết quả, danh sách trống. Đẹp và dễ dàng.


Tuy nhiên, cho các phương pháp như .tìm thấy.chọn_một chỉ có thể đưa ra một kết quả duy nhất, nếu không tìm thấy gì trong HTML, kết quả sẽ là Không có. BeautifulSoup sẽ không trực tiếp đưa ra một ngoại lệ để giải thích vấn đề. Thay vào đó, một Thuộc tínhError sẽ thường xảy ra trong tiếp theo mã, cố gắng sử dụng cái Không có không phù hợp (vì nó mong đợi nhận được thứ gì đó khác - thường là một trường hợp của Nhãn lớp mà BeautifulSoup định nghĩa). Điều này xảy ra bởi vì Không có đơn giản là không hỗ trợ hoạt động; nó được gọi là Thuộc tínhError bởi vì . cú pháp có nghĩa là truy cập vào một thuộc tính của bất cứ thứ gì ở phía bên trái.
[TODO: khi một chuẩn mực thích hợp tồn tại, hãy liên kết đến phần giải thích về các thuộc tính là gì và những gì Thuộc tínhError là.]

Tuy nhiên, đối với các phương thức như .find và .select_one chỉ có thể đưa ra một kết quả duy nhất, nếu không tìm thấy gì trong HTML thì kết quả sẽ là KHÔNG. BeautifulSoup không trực tiếp đưa ra ngoại lệ để giải quyết vấn đề. Ngược lại, AttributionError thường xảy ra trong mã cố gắng sử dụng Không có gì không thích hợp (vì nó mong đợi nhận được thứ gì đó khác - thường là một phiên bản của lớp Tag được định nghĩa bởi BeautifulSoup). Điều này xảy ra bởi vì không có ai không hỗ trợ hoạt động này; nó được gọi là AttributionError. Cú pháp có nghĩa là truy cập các thuộc tính của bất kỳ thứ gì ở bên trái. [CẦN LÀM: Khi đã có thông số kỹ thuật phù hợp, vui lòng liên kết đến phần giải thích về thuộc tính là gì và AttributionError là gì. ]


Ví dụ


Chúng ta hãy xem xét từng ví dụ về mã không hoạt động trong câu hỏi:

Hãy xem xét từng ví dụ về mã không hoạt động trong câu hỏi:


>>> in(soup.sister)
Không có

Điều này cố gắng tìm kiếm một thẻ trong HTML (không một thẻ khác có một lớp học, nhận dạng hoặc thuộc tính khác tương đương với em gái). Không có cái nào cả, nên kết quả là `Không có.

Điều này cố gắng tìm thẻ trong HTML (ngược lại với một thẻ khác có cùng lớp, id hoặc các thuộc tính tương tự khác với chị em). Không có nên kết quả là không có.


>>> in(soup.find('a', class_='brother'))
Không có

Điều này cố gắng tìm một thẻ có một lớp học thuộc tính bằng anh trai, giống Bobby. Tài liệu không chứa bất cứ điều gì như thế; không có Một các thẻ có lớp đó (tất cả chúng đều có em gái thay vào đó là lớp).

nó cố gắng tìm mộtMark, thuộc tính class của nó bằng Brother chẳng hạnBobby. Tài liệu không chứa bất cứ thứ gì tương tự; không có thẻ a nào chứa lớp (tất cả chúng đều có các lớp chị em).


>>> in(soup.select_one('a.brother'))
Không có

Đây là một cách khác để thực hiện cùng một việc như ví dụ trước, với một phương pháp khác. (Thay vì truyền tên thẻ và một số giá trị thuộc tính, chúng ta truyền bộ chọn truy vấn CSS.) Kết quả là giống nhau.

Đây là một cách khác để thực hiện điều tương tự như ví dụ trước theo một cách khác. (Thay vì chuyển tên thẻ và một số giá trị thuộc tính, chúng tôi chuyển bộ chọn truy vấn CSS.) Kết quả là như nhau.


>>> soup.select_one('a.brother').text
Theo dõi (cuộc gọi gần đây nhất là cuộc gọi cuối cùng):
Tệp "", dòng 1, trong
AttributeError: Đối tượng 'NoneType' không có thuộc tính 'text'

Từ soup.select_one('a.brother') đã trả lại Không có, điều này cũng giống như cố gắng làm Không có.văn bản. Lỗi này có nghĩa chính xác như tên gọi của nó: Không có không có một chữ để truy cập. Trên thực tế, nó không có bất kỳ thuộc tính "bình thường" nào; Không cóLoại lớp chỉ định nghĩa các phương thức đặc biệt như __chuỗi__ (chuyển đổi Không có đến chuỗi 'Không có', để nó có thể trông giống như văn bản thực tế Không có khi nó được in).

Vì Soup.select_one('a.brother') trả về KHÔNG, điều này cũng giống như cố gắng thực hiện NON.Text. Lỗi này có nghĩa chính xác như những gì nó nói: không có văn bản nào để truy cập. Trên thực tế, nó không có bất kỳ thuộc tính "bình thường" nào; lớp NoneType chỉ định nghĩa phương thức đặc biệt __str__ (chuyển None thành chuỗi 'None' để khi in nó trông giống như văn bản thực sự None).


Thêm câu trả lời
41 4 0
trợ lý lỗi
Hồ sơ

Tôi là một lập trình viên xuất sắc, rất giỏi!

Nhận phiếu giảm giá taxi Didi miễn phí
Phiếu giảm giá taxi Didi
Xem sitemap của VNExpress