PythonWeb-BeautifulSoupによるスクレイピング

Sep 16 2020

私はPythonに比較的慣れていないので、BeautifulSoupを使用してWebページをフェッチし、そこからすべての段落を抽出し、「ing」で終わるすべての単語を抽出するプログラムを作成し、最後に次のファイルに保存する必要がありました。形式は「Word」+タブ+「wordcount」+「newline」です。

これはこれまでの私のコードです。これを処理するためのよりPython的な方法はありますか?または一般的にコードを改善する方法は?

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

int0引数なしで呼び出された場合はを返します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:
    . . .

これは、関数がsへのDictイオンマッピングを受け入れ、ingを返すことstrを意味intしますstr


また、についてはsort_and_format、and名前に固執し始めたときに、関数が実行しすぎていることを示唆している可能性があることがわかりました。並べ替えと書式設定を別々に行うと、コードの意味が理解できる場合があります。その関数は純粋にフォーマットを処理でき、代わりに操作するシーケンスを渡すことができます。そのシーケンスがソートされている場合、そうでない場合でも、素晴らしいです。ソート順が何であるかをフォーマットする目的には関係ありません。