Веб-парсинг Python с помощью BeautifulSoup
Я относительно новичок в python, и для выполнения задания мне пришлось написать программу, которая извлекает веб-страницу с помощью BeautifulSoup, извлекает из нее все абзацы и извлекает все слова, оканчивающиеся на «ing», и в конце сохраняет ее в файл с формат «Слово» + табуляция + «количество слов» + «новая строка».
Пока это мой код. Есть ли более питонический способ справиться с этим? Или вообще способы улучшить код?
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()
Ответы
if word in matching_words:
matching_words[word] += 1
else:
matching_words[word] = 1
Если вы проверяете, есть ли в словаре ключ перед добавлением к нему, defaultdictлучшим вариантом может быть a:
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:
. . .
Это говорит о том, что функции принимает Dictionary отображения strIngs в intсек, и возвращает strIng
Кроме того sort_and_format, я обнаружил, что когда вы начинаете придерживаться andимен, это может указывать на то, что функция делает слишком много. Вы можете обнаружить, что код будет иметь больше смысла, если сортировка и форматирование будут выполняться отдельно. Эти функции могут обрабатывать только форматирование, и вместо этого им можно передать последовательность для работы. Если эта последовательность отсортирована - отлично, если нет - тоже отлично. Порядок сортировки не имеет значения для целей форматирования.