Python Web-Scraping với BeautifulSoup

Sep 16 2020

Tôi tương đối mới với python và cho một nhiệm vụ, tôi phải viết một chương trình tìm nạp một trang web với BeautifulSoup, trích xuất tất cả các Đoạn từ đó và trích xuất tất cả các từ kết thúc bằng "ing" và cuối cùng lưu nó vào một tệp với định dạng "Word" + tab + "wordcount" + "dòng mới".

Đây là mã của tôi cho đến nay. Có cách nào tốt hơn để xử lý điều này không? Hay nói chung là những cách để cải thiện mã?

from bs4 import BeautifulSoup
import requests
import re


def main():
    site = "https://en.wikipedia.org/wiki/Data_science"
    r = requests.get(site).content
    soup = BeautifulSoup(r)
    ps = soup.findAll('p')
    fulltext = ''
    for p in ps:
        fulltext += p.get_text()
    words = match_words(fulltext)
    formated_words = sort_and_format(words)
    with open(r"Q1_Part1.txt","w") as file:
        file.write(formated_words)


def match_words(string):
    pattern = re.compile(r'\b(\w*ing)\b')
    words = re.findall(pattern, string.lower())
    matching_words = {}
    for word in words:
        if word in matching_words:
            matching_words[word] += 1
        else:
            matching_words[word] = 1
    return matching_words

def sort_and_format(dict):
    ordered_keys = sorted(dict, key=dict.get, reverse=True)
    output_string = ''
    for r in ordered_keys:
        output_string += f"{r}\t{dict[r]}\n"
    return output_string
    
main()

Trả lời

3 Carcigenicate Sep 16 2020 at 20:57
if word in matching_words:
    matching_words[word] += 1
else:
    matching_words[word] = 1

Nếu bạn đang kiểm tra xem từ điển có khóa hay không trước khi thêm vào, thì một defaultdictcó thể là một lựa chọn tốt hơn:

from collections import defaultdict

matching_words = defaultdict(int)
matching_words[word] += 1

inttrả về một 0khi được gọi mà không có đối số và 0được sử dụng làm giá trị mặc định cho từ điển khi khóa không tồn tại.


fulltext = ''
for p in ps:
    fulltext += p.get_text()

Điều này không hiệu quả lắm. Hiệu suất của +=chuỗi đã trở nên tốt hơn trong các phiên bản Python sau này, nhưng nhìn chung vẫn chậm hơn. Giải pháp thay thế điển hình đang sử dụng join:

pieces = [p.get_text() for p in ps]
fulltext = "".join(pieces)

# Or just

fulltext = "".join([p.get_text() for p in ps])

Sau đó, tương tự trong sort_and_format:

output_string = "".join([f"{r}\t{dict[r]}\n"] for r in ordered_keys])

Trong sort_and_format, bạn đã đặt tên cho tham số dict. Điều này là không tối ưu vì một số lý do:

  • dict là một tên chung chung không mô tả đúng dữ liệu.
  • dict là tên của một lớp tích hợp và việc phủ bóng nó làm cho mã của bạn khó hiểu hơn và ngăn bạn sử dụng lớp tích hợp sẵn.

Mặc dù vậy, việc chỉ định loại có thể hữu ích, vì vậy tôi có thể giới thiệu các gợi ý loại ở đây

from typing import Dict

def sort_and_format(words: Dict[str, int]) -> str:
    . . .

Điều này nói rằng các hàm chấp nhận một Dictánh xạ tĩnh strings tới ints và trả về một string


Ngoài ra sort_and_format, tôi nhận thấy rằng khi bạn bắt đầu chú ý andvào tên, điều đó có thể cho thấy rằng hàm đang hoạt động quá nhiều. Bạn có thể thấy rằng mã sẽ có ý nghĩa hơn nếu việc sắp xếp và định dạng diễn ra riêng biệt. Các chức năng đó có thể xử lý hoàn toàn định dạng và có thể được cung cấp một chuỗi để làm việc thay thế. Nếu trình tự đó được sắp xếp, tuyệt vời, nếu không, cũng tuyệt vời. Mục đích của việc định dạng thứ tự sắp xếp là gì không quan trọng.