J'ai essayé d'obtenir tous les hrefs d'une page d'accueil d'article de nouvelles. En fin de compte, je veux créer quelque chose qui me donne les n mots les plus utilisés de tous les articles de presse. Pour ce faire, j'ai pensé qu'il me fallait d'abord les hrefs pour ensuite cliquer dessus les uns après les autres.
Avec beaucoup d'aide d'un autre utilisateur de cette plateforme, voici le code que j'ai en ce moment:
from bs4 import BeautifulSoup from selenium import webdriver url = 'https://ad.nl' # launch firefox with your url above # note that you could change this to some other webdriver (e.g. Chrome) driver = webdriver.Chrome() driver.get(url) # click the "accept cookies" button btn = driver.find_element_by_name('action') btn.click() # grab the html. It'll wait here until the page is finished loading html = driver.page_source # parse the html soup soup = BeautifulSoup(html.lower(), "html.parser") articles = soup.findAll("article") for i in articles: article = driver.find_element_by_class_name('ankeiler') hrefs = article.find_element_by_css_selector('a').get_attribute('href') print(hrefs) driver.quit()
Cela me donne le premier href je pense, mais il ne sera pas itéré sur les suivants. Il me donne juste le premier href autant de fois qu'il doit itérer. Est-ce que quelqu'un sait comment je le fais passer à la prochaine href au lieu de rester coincé sur la première?
PS. si quelqu'un a des suggestions sur la façon de poursuivre mon petit projet, n'hésitez pas à les partager car j'ai encore beaucoup de choses à apprendre sur Python et la programmation en général.
3 Réponses :
Pour obtenir tous les hrefs d'un article, vous pouvez faire:
hrefs = article.find_elements_by_xpath('//a') links = [href.get_attribute("href") for href in hrefs] for link in link: driver.get(link) #Add all words in the article to a dictionary with the key being the words and #the value being the number of times they occur
Pour progresser dans le projet, peut-être que le soufflet ci-dessous aiderait:
hrefs = article.find_elements_by_xpath('//a') #OR article.find_element_by_css_selector('a') for href in hrefs: print(href.get_attribute('href'))
Cela fonctionne en effet. Mais il y a plusieurs hrefs inclus que je ne veux pas avoir. Les hrefs que je veux ont tous une certaine classe appelée «ankeiler__link». Savez-vous peut-être comment je pourrais ne sélectionner que ceux-là? Merci!
J'ai écrit une solution complète comme une autre réponse qui utilise le 'ankeiler__link'.
Au lieu d'utiliser une belle soupe, qu'en est-il de ça?
articles = driver.find_elements_by_css_selector('article') for i in articles: href = i.find_element_by_css_selector('a').get_attribute('href') print(href)
Pour améliorer ma réponse précédente, j'ai écrit une solution complète à votre problème:
from selenium import webdriver url = 'https://ad.nl' #Set up selenium driver driver = webdriver.Chrome() driver.get(url) #Click the accept cookies button btn = driver.find_element_by_name('action') btn.click() #Get the links of all articles article_elements = driver.find_elements_by_xpath('//a[@class="ankeiler__link"]') links = [link.get_attribute('href') for link in article_elements] #Create a dictionary for every word in the articles words = dict() #Iterate through every article for link in links: #Get the article driver.get(link) #get the elements that are the body of the article article_elements = driver.find_elements_by_xpath('//*[@class="article__paragraph"]') #Initalise a empty string article_text = '' #Add all the text from the elements to the one string for element in article_elements: article_text+= element.text + " " #Convert all character to lower case article_text = article_text.lower() #Remove all punctuation other than spaces for char in article_text: if ord(char) > 122 or ord(char) < 97: if ord(char) != 32: article_text = article_text.replace(char,"") #Split the article into words for word in article_text.split(" "): #If the word is already in the article update the count if word in words: words[word] += 1 #Otherwise make a new entry else: words[word] = 1 #Print the final dictionary (Very large so maybe sort for most occurring words and display top 10) #print(words) #Sort words by most used most_used = sorted(words.items(), key=lambda x: x[1],reverse=True) #Print top 10 used words print("TOP 10 MOST USED: ") for i in range(10): print(most_used[i]) driver.quit()
Fonctionne bien pour moi, faites-moi savoir si vous obtenez des erreurs.
Si seulement je pouvais parler néerlandais, alors je comprendrais quels étaient les mots les plus courants :)
C'est incroyable ... La seule chose que je dois ajouter, c'est que cela ne compte pas les mots «le» et «a» «et». J'ai cependant quelques questions. Le pilote, get (lien) remplace-t-il la valeur de pilote de ad.nl par quel que soit le lien? Pourquoi devez-vous créer une nouvelle chaîne vide au lieu d'utiliser uniquement element.text? Comment savez-vous que ord doit être> 122 ou <97, où puis-je trouver les caractères correspondants avec un nombre? Merci beaucoup!
La réponse à la première question est oui, le pilote passe de "ad.nl" à "ad.nl/article1". La réponse à la deuxième question est oui, car il y a plusieurs paragraphes pour chaque article, vous devez donc ajouter tout le texte de tous les paragraphes ensemble. Je savais que ord () devait être compris entre 122 et 97 parce que (97-122) sont les nombres ascii pour les caractères az. Il convient également de noter que 32 est un espace, car nous ne voulons pas supprimer les espaces car ils séparent les mots. Vous pouvez obtenir ces nombres en recherchant "table ASCII".