Python Web-Scraping ด้วย BeautifulSoup

Sep 16 2020

ฉันค่อนข้างใหม่กับ python และสำหรับงานที่ได้รับมอบหมายฉันต้องเขียนโปรแกรมที่ดึงข้อมูลหน้าเว็บด้วย BeautifulSoup แยกย่อหน้าทั้งหมดจากนั้นและแยกคำทั้งหมดที่ลงท้ายด้วย "ing" และท้ายที่สุดบันทึกลงในไฟล์ด้วย รูปแบบ "Word" + tab + "wordcount" + "newline"

นี่คือรหัสของฉันจนถึงตอนนี้ มีวิธีอื่น ๆ ในการจัดการกับสิ่งนี้หรือไม่? หรือวิธีโดยทั่วไปในการปรับปรุงโค้ด?

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

คำตอบ

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

หากคุณกำลังตรวจสอบว่าพจนานุกรมมีคีย์หรือไม่ก่อนที่จะเพิ่มเข้าไปdefaultdictอาจเป็นตัวเลือกที่ดีกว่า:

from collections import defaultdict

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

intส่งคืน0เมื่อเรียกโดยไม่มีอาร์กิวเมนต์และ0จะใช้เป็นค่าเริ่มต้นสำหรับพจนานุกรมเมื่อไม่มีคีย์


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

สิ่งนี้ไม่มีประสิทธิภาพมากนัก ประสิทธิภาพของ+=สตริงได้ดีขึ้นใน Python รุ่นใหม่ ๆ แต่โดยทั่วไปแล้วก็ยังช้ากว่า ทางเลือกทั่วไปคือการใช้join:

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

# Or just

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

ในทำนองเดียวกันในsort_and_format:

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

ในคุณได้ชื่อพารามิเตอร์sort_and_format dictสิ่งนี้ต่ำกว่าด้วยเหตุผลสองประการ:

  • dict เป็นชื่อทั่วไปที่อธิบายข้อมูลไม่ถูกต้อง
  • dict เป็นชื่อของคลาสในตัวและการแชโดว์ทำให้โค้ดของคุณสับสนมากขึ้นและป้องกันไม่ให้คุณใช้งานในตัว

การระบุประเภทอาจมีประโยชน์ดังนั้นฉันอาจแนะนำคำแนะนำประเภทที่นี่

from typing import Dict

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

สิ่งนี้บอกว่าฟังก์ชั่นยอมรับการDictแมปไอออนิกstrกับints และส่งคืนstrไอเอ็นจี


นอกจากนี้sort_and_formatฉันพบว่าเมื่อคุณเริ่มติดandชื่อนั่นสามารถบ่งบอกได้ว่าฟังก์ชันทำงานมากเกินไป คุณอาจพบว่าโค้ดจะมีเหตุผลมากขึ้นหากการเรียงลำดับและการจัดรูปแบบเกิดขึ้นแยกกัน ฟังก์ชันดังกล่าวสามารถจัดการการจัดรูปแบบอย่างหมดจดและสามารถส่งลำดับให้ทำงานแทนได้ หากเรียงลำดับนั้นดีถ้าไม่ดีก็เยี่ยมเช่นกัน ไม่สำคัญสำหรับวัตถุประสงค์ในการจัดรูปแบบว่าลำดับการจัดเรียงคืออะไร