0
votes

Comment itérer sur hrefs avec du sélénium?

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.


0 commentaires

3 Réponses :


0
votes

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


2 commentaires

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'.



1
votes

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)


0 commentaires

0
votes

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.


3 commentaires

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".