2
votes

Récupérer des données d'un site sur lequel l'URL ne change pas en cliquant sur "Afficher plus"

J'essaie de récupérer tous les liens d'articles d'un site et ai-je réussi à le faire?

La page du site dispose d'un bouton Afficher plus pour charger plus d'articles.

J'utilise Selenium pour cliquer sur ce bouton qui fonctionne également.

Le problème est que cliquer sur Afficher plus ne change pas l'URL de la page, donc je ne peux gratter que les liens initiaux affichés par défaut. p>

Voici l'extrait de code:

def startWebDriver():
    global driver
    options = Options()
    options.add_argument("--disable-extensions")
    driver = webdriver.Chrome(executable_path = '/home/Downloads/chromedriver_linux64/chromedriver',options=options)

startWebDriver()
count = 0 
s = set()

driver.get('https://www.nytimes.com/search? endDate=20181231&query=trump&sort=best&startDate=20180101')
time.sleep(4)
element = driver.find_element_by_xpath('//*[@id="site-content"]/div/div/div[2]/div[2]/div/button')

while(count < 10):
    element.click()
    time.sleep(4)
    count=count+1

url = driver.current_url

Je m'attends à voir tous les liens d'articles affichés sur la page après avoir cliqué sur Afficher plus 10 fois


3 commentaires

avez-vous utilisé set sur les données affichées dans la première itération aux deuxième et troisième?


oui .. J'utilise set pour collecter tous les liens d'articles


Le site ne change pas et ne changera pas l'URL sur laquelle vous vous trouvez, car il récupère les nouvelles données à afficher par ajax. Lorsque vous cliquez sur "Afficher plus", l'interface JS envoie une requête au serveur pour obtenir plus de données, et lorsque cela est rempli, la réponse est ajoutée au HTML de la page actuellement chargée; par exemple. une page dynamique triviale.


3 Réponses :


0
votes

Il semble que votre ressource cible nous donne une belle API pour leurs articles.

Il sera beaucoup plus facile de l'utiliser à la place du sélénium.

Vous pouvez ouvrir cette page dans Chrome. Ensuite, ouvrez Dev Tools -> Network. Cliquez sur "Afficher plus" et vous pouvez voir la requête d'API nommée v2 (on dirait qu'il s'agit d'une passerelle GraphQL).

Quelque chose comme

{
    "operationName":"SearchRootQuery",
    "variables":{
        "first":10,
        "sort":"best",
        "beginDate":"20180101",
        "endDate":"20181231",
        "text":"trump" ...
}}

Vous pouvez imiter cette demande mais demander autant de "premiers" articles que vous le souhaitez.

MODIFIER :

Vous pouvez cliquer avec le bouton droit de la souris dans DevTools et sélectionner "copier en tant que cURL". Puis collez-le sur votre terminal. Vous pouvez donc voir comment cela fonctionne.

Ensuite, vous pouvez utiliser une bibliothèque comme demande de le faire à partir de votre code.


1 commentaires

Merci .. comment imiter cette demande?



1
votes

Voici une imitation d'une requête POST utilisant les informations API comme je le vois dans l'onglet réseau. Je suis revenu aux en-têtes qui semblent obligatoires.

import requests
url = 'https://samizdat-graphql.nytimes.com/graphql/v2'
headers = {
         'nyt-app-type': 'project-vi',
         'nyt-app-version': '0.0.3',
         'nyt-token': 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlYOpRoYg5X01qAqNyBDM32EI/E77nkFzd2rrVjhdi/VAZfBIrPayyYykIIN+d5GMImm3wg6CmTTkBo7ixmwd7Xv24QSDpjuX0gQ1eqxOEWZ0FHWZWkh4jfLcwqkgKmfHJuvOctEiE/Wic5Qrle323SMDKF8sAqClv8VKA8hyrXHbPDAlAaxq3EPOGjJqpHEdWNVg2S0pN62NSmSudT/ap/BqZf7FqsI2cUxv2mUKzmyy+rYwbhd8TRgj1kFprNOaldrluO4dXjubJIY4qEyJY5Dc/F03sGED4AiGBPVYtPh8zscG64yJJ9Njs1ReyUCSX4jYmxoZOnO+6GfXE0s2xQIDAQAB'
}

data = '''
{"operationName":"SearchRootQuery","variables":{"first":10,"sort":"best","beginDate":"20180101","text":"trump","cursor":"YXJyYXljb25uZWN0aW9uOjk="},"extensions":{"persistedQuery":{"version":1,"sha256Hash":"d2895d5a5d686528b9b548f018d7d0c64351ad644fa838384d94c35c585db813"}}}
'''
with requests.Session() as r:
    re = r.post(url, headers = headers, data = data)
    print(re.json())


0 commentaires

0
votes

Pour gratter tous les liens d'article, c'est-à-dire les attributs href de URL en cliquant sur le lien avec le texte comme AFFICHER PLUS , vous pouvez utiliser la solution suivante:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException

options = webdriver.ChromeOptions() 
options.add_argument("start-maximized")
options.add_argument('disable-infobars')
driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:\Utility\BrowserDrivers\chromedriver.exe')
driver.get("https://www.nytimes.com/search?%20endDate=20181231&query=trump&sort=best&startDate=20180101")
myLength = len(WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.XPATH, "//main[@id='site-content']//figure[@class='css-rninck toneNews']//following::a[1]"))))

while True:
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    try:
        WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//button[text()='Show More']"))).click()
        WebDriverWait(driver, 20).until(lambda driver: len(driver.find_elements_by_xpath("//main[@id='site-content']//figure[@class='css-rninck toneNews']//following::a[1]")) > myLength)
        titles = driver.find_elements_by_xpath("//main[@id='site-content']//figure[@class='css-rninck toneNews']//following::a[1]")
        myLength = len(titles)
    except TimeoutException:
        break

for title in titles:
    print(title.get_attribute("href"))
driver.quit()


0 commentaires