Python Web-Scraping dengan BeautifulSoup

Sep 16 2020

Saya relatif baru mengenal python dan untuk tugas saya harus menulis program yang mengambil halaman web dengan BeautifulSoup, mengekstrak semua Paragraf darinya, dan mengekstrak semua kata yang diakhiri dengan "ing", dan pada akhirnya menyimpannya ke file dengan format "Word" + tab + "wordcount" + "newline".

Ini adalah kode saya sejauh ini. Apakah ada cara yang lebih pythonic untuk menangani ini? Atau umumnya cara untuk meningkatkan kode?

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()

Jawaban

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

Jika Anda memeriksa apakah kamus memiliki kunci sebelum menambahkannya, a defaultdictmungkin pilihan yang lebih baik:

from collections import defaultdict

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

intmengembalikan 0ketika dipanggil tanpa argumen, dan itu 0digunakan sebagai nilai default untuk kamus ketika kuncinya tidak ada.


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

Ini tidak terlalu efisien. Performa +=on string menjadi lebih baik di versi Python yang lebih baru, tetapi secara umum masih lebih lambat. Alternatif tipikal menggunakan join:

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

# Or just

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

Kemudian serupa di sort_and_format:

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

Di sort_and_format, Anda telah memberi nama parameter dict. Ini kurang optimal karena beberapa alasan:

  • dict adalah nama umum yang tidak mendeskripsikan data dengan tepat.
  • dict adalah nama kelas bawaan, dan membayangi itu membuat kode Anda lebih membingungkan, dan mencegah Anda menggunakan bawaan.

Menunjukkan tipe bisa membantu, jadi saya mungkin memperkenalkan petunjuk tipe di sini

from typing import Dict

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

Ini mengatakan bahwa fungsi menerima Dictpemetaan ioner strke ints, dan mengembalikan a string


Juga untuk sort_and_format, saya telah menemukan bahwa ketika Anda mulai menempel andpada nama, itu bisa menunjukkan bahwa fungsinya terlalu banyak. Anda mungkin menemukan bahwa kode akan lebih masuk akal jika pengurutan dan pemformatan dilakukan secara terpisah. Fungsi tersebut dapat menangani pemformatan murni, dan dapat diberikan urutan untuk dikerjakan. Jika urutan itu diurutkan, bagus, jika tidak, juga bagus. Tidak masalah untuk tujuan memformat apa urutan sortirnya.