Python Web-Scraping com BeautifulSoup
Sou relativamente novo em Python e, para uma tarefa, tive que escrever um programa que busca uma página da web com BeautifulSoup, extrair todos os parágrafos dela e todas as palavras que terminam com "ing" e, no final, salvá-lo em um arquivo com o formato "Word" + tab + "wordcount" + "newline".
Este é o meu código até agora. Existe uma maneira mais pythônica de lidar com isso? Ou geralmente maneiras de melhorar o código?
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()
Respostas
if word in matching_words:
matching_words[word] += 1
else:
matching_words[word] = 1
Se você estiver verificando se um dicionário tem uma chave antes de adicioná-lo, defaultdictpode ser uma opção melhor:
from collections import defaultdict
matching_words = defaultdict(int)
matching_words[word] += 1
intretorna um 0quando chamado sem argumentos, e que 0é usado como um valor padrão para o dicionário quando a chave não existe.
fulltext = ''
for p in ps:
fulltext += p.get_text()
Isso não é muito eficiente. O desempenho das +=strings melhorou nas versões posteriores do Python, mas geralmente ainda é mais lento. A alternativa típica é usar join:
pieces = [p.get_text() for p in ps]
fulltext = "".join(pieces)
# Or just
fulltext = "".join([p.get_text() for p in ps])
Então, da mesma forma em sort_and_format:
output_string = "".join([f"{r}\t{dict[r]}\n"] for r in ordered_keys])
Em sort_and_format, você nomeou o parâmetro dict. Isso não é ideal por alguns motivos:
dicté um nome genérico que não descreve corretamente os dados.dicté o nome de uma classe integrada, e sombreando-o torna seu código mais confuso e impede que você use a classe integrada.
No entanto, indicar o tipo pode ser útil, então posso apresentar dicas de tipo aqui
from typing import Dict
def sort_and_format(words: Dict[str, int]) -> str:
. . .
Este diz que as funções aceita um Dictionary mapeamento strIngs para ints, e retorna um string
Além disso sort_and_format, descobri que, quando você começa a se limitar anda nomes, isso pode sugerir que a função está fazendo muito. Você pode descobrir que o código fará mais sentido se a classificação e a formatação ocorrerem separadamente. Essas funções podem lidar puramente com a formatação e podem receber uma sequência para trabalhar. Se essa sequência for ordenada, ótimo; se não, ótimo também Para fins de formatação, não importa qual é a ordem de classificação.