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 và ... 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ét
Và yê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: 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ệ])
đầu>
![[url]]([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
Và .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
-
java - đối tượng a = đối tượng b; điều gì xảy ra với đối tượng a?
Một trong những giáo sư của tôi đã đưa cho chúng tôi một số câu hỏi thực hành và một trong những câu hỏi có dạng như sau (mã giả): a.setColor(blue); b.setColor(red);
-
Kiểm tra JavaScript(object&& object!== "null"&& object!== "không xác định")
Tôi dường như sử dụng bài kiểm tra này rất nhiều if( object && object !== "null" && object !== "unknown" ){ doSomething() } Trên một đối tượng, tôi
-
Đối tượng/đối tượng C#
Đối tượng/đối tượng C# là loại giá trị hay loại tham chiếu? Tôi đã kiểm tra xem họ có thể giữ tham chiếu này không, nhưng tham chiếu này không thể được sử dụng để thay đổi đối tượng. sử dụng Hệ thống; lớp MyClass { public s
-
java — gửi json qua ajax - đối tượng - đối tượng
Tôi gặp sự cố khi gửi json qua AJAX. var data = [{"name": "Will", "họ": "Smith", "age": "40"},{"name": "Wil
-
Cách nhận giá trị [đối tượng] [đối tượng]
Khi tôi cố gắng truy cập đối tượng {{result}} trong Chế độ xem của mình (mà tôi đang gửi từ máy chủ Express js), nó chỉ hiển thị [object][object] Có ai biết cách lấy giá trị ở định dạng JSON không? Đây là
-
Đối tượng...đối tượng[] và định dạng
Tôi có nhiều loại dữ liệu khác nhau (có thể là chuỗi, số nguyên ...). Đây là một ví dụ đơn giản: public static void main(String[] args) { before("one" }
-
Cách sửa [đối tượng, đối tượng]
Xin chào, tôi mới làm quen với json và javascript. Tôi đã tìm ra cách sử dụng dữ liệu json làm bảng trên trang web này. Tôi tò mò tại sao khi tôi cố gắng sử dụng dữ liệu json làm bảng, tôi lại nhận được [Object,Object]
-
Gỡ lỗi [đối tượng] [đối tượng] JavaScript
Đã đóng cửa. Sự cố này yêu cầu chi tiết gỡ lỗi. Câu trả lời không được chấp nhận vào thời điểm này. Chỉnh sửa câu hỏi để bao gồm hành vi mong muốn, một vấn đề hoặc lỗi cụ thể và
-
Đối tượng == null hoặc null == đối tượng?
Tôi nghe người khác nói rằng null == object tốt hơn object == null check. Ví dụ: void m1(Object obj) { if(null == obj) // Is thi.
-
Hướng dẫn VBS: Đối tượng đối tượng
Đối tượng Match cung cấp quyền truy cập vào các thuộc tính chỉ đọc của các kết quả khớp biểu thức chính quy. Lưu ý rằng các đối tượng Match chỉ có thể được tạo thông qua phương thức Thực thi của đối tượng RegExp, phương thức này thực sự trả về một tập hợp các đối tượng Match. tất cả
-
Hướng dẫn VBS: Đối tượng lớp đối tượng
Đối tượng lớp Một đối tượng được tạo bằng câu lệnh Lớp. Cung cấp quyền truy cập vào các sự kiện khác nhau của lớp. Giải thích Không được phép khai báo rõ ràng một biến là loại Lớp. Trong ngữ cảnh của VBScript, thuật ngữ "đối tượng lớp" dùng để chỉ
-
Hướng dẫn VBS: Đối tượng thư mục đối tượng
Đối tượng Thư mục cung cấp quyền truy cập vào tất cả các thuộc tính của một thư mục. Giải thích rằng đoạn mã sau minh họa cách lấy một đối tượng Thư mục và xem các thuộc tính của nó: Hàm ShowDateCreated(f
-
Hướng dẫn VBS: Đối tượng tệp đối tượng
Đối tượng File cung cấp quyền truy cập vào tất cả các thuộc tính của tệp. Đoạn mã sau minh họa cách lấy một đối tượng File và xem các thuộc tính của nó: Hàm ShowDateCreated(fil
-
Hướng dẫn VBS: Đối tượng ổ đĩa đối tượng
Đối tượng Drive cung cấp quyền truy cập vào các thuộc tính của ổ đĩa hoặc mạng chia sẻ. Mô tả Đoạn mã sau minh họa cách sử dụng đối tượng Drive để truy cập các thuộc tính của ổ đĩa: Hàm ShowFreeSpac
-
Hướng dẫn VBS: Đối tượng-FileSystemObject
Các đối tượng FileSystemObject cung cấp quyền truy cập vào hệ thống tệp của máy tính. Đoạn mã sau minh họa cách sử dụng đối tượng FileSystemObject để trả về một đối tượng TextStream có thể đọc được
-
sự vật
Tôi mới làm quen với javascript OOP và tôi nghĩ đây là một câu hỏi tương đối cơ bản nhưng tôi không thể tìm thấy bất kỳ trợ giúp nào bằng cách tìm kiếm trên web. Tôi có thiếu thứ gì đó không, hay tôi đang đi sai hướng? Đây là mã mẫu của tôi: funcio
-
sự vật
Tôi có thể tạo ra rất nhiều đồ vật khác nhau một cách dễ dàng. Ví dụ như thế này: var myObject = { myFunction: function () { return "" } };
-
sự vật
hàm Person(fname, lname) { this.fname = fname, this.lname = lname, this.getName = hàm()
-
javascript - Trả về JSON(đối tượng, đối tượng)
Có ai có thể giải thích cho tôi tại sao đoạn mã sau lại đưa ra (đối tượng, đối tượng) không? (console.log(dope) cung cấp những gì cần thiết, nhưng trong JSON.stringify và JSON.parse
-
Trả về chú giải công cụ cho [đối tượng, đối tượng]
Tôi đang cố gắng hoàn thành bài tập về biểu đồ phân tán từ Free Code Camp. Tuy nhiên, tôi mới chỉ tự học d3 được vài giờ và tôi đang cố gắng tìm ra cách hiển thị dữ liệu cụ thể trong chú giải công cụ sau khi làm theo hướng dẫn từ lynda.com. Mã này
Tôi là một lập trình viên xuất sắc, rất giỏi!