Dans l'extrait de code ci-dessous, vous pouvez voir que j'essaie de récupérer certaines données du site Web de basket-ball masculin de la NCAA.

import requests

url = "https://www.ncaa.com/scoreboard/basketball-men/d1/"

response = requests.get(url)
html = response.text

print(html)
print(response.headers)
print("\n\n")
print(response.request.headers)

Le site Web contient une liste des jeux et leurs scores. J'ai compris comment extraire toutes les données dont j'avais besoin en utilisant des requêtes Python pour la requête HTTP, puis BeautifulSoup pour extraire des données du HTML. Le grattoir complet est là si vous souhaitez y jeter un œil.

Le problème: lorsque Requests obtient la réponse du site Web de la NCAA, les données sont beaucoup plus anciennes (parfois jusqu'à 30 ou 40 minutes, au moins) que les données sur le site Web réel.

Je google ça depuis des heures. Après avoir lu les documents sur les demandes Python, je crois avoir découvert que le site Web de la NCAA le serveur envoie des données obsolètes. Mais je ne comprends pas pourquoi il enverrait des données obsolètes à mon programme lorsqu'il envoie à Google Chrome (ou à n'importe quel navigateur Web) les données correctes.

La raison pour laquelle je pense que le serveur envoie des données obsolètes est que lorsque j'imprime les en-têtes de réponse, l'un des éléments est 'Last-Modified': 'Sam, 26 jan 2019 17:49:13 GMT' tandis qu'un autre est 'Date': 'Sam, 26 jan 2019 18:20:29 GMT' , il semble donc que le serveur reçoive la demande au bon moment, mais fournit des données qui n'ont pas été modifié dans un certain temps.

Ma question: connaissez-vous une raison pour laquelle cela se produirait? Y a-t-il quelque chose que je dois ajouter dans ma demande HTTP qui amènerait le serveur à m'envoyer des données cohérentes avec ce qui envoie des navigateurs Web?

P.S. Je suis tellement désolé pour la longue question. J'ai essayé de rester concis, tout en expliquant les choses clairement.

9
JoeKreydt 26 janv. 2019 à 21:40

3 réponses

Meilleure réponse

Avant votre requests.get(), essayez d'ajouter un en-tête:

import requests

url = "https://www.ncaa.com/scoreboard/basketball-men/d1/"

headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}   


response = requests.get(url, headers = headers)
html = response.text

Mon autre suggestion serait d'utiliser:

url = 'https://data.ncaa.com/casablanca/scoreboard/basketball-men/d1/2019/01/26/scoreboard.json'

Et utilisez le paquet json pour le lire. Tout est en direct et là pour vous dans un joli format JSON

Code

import json
import requests

url = 'https://data.ncaa.com/casablanca/scoreboard/basketball-men/d1/2019/01/26/scoreboard.json'
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}    

response = requests.get(url, headers = headers)

jsonStr = response.text

jsonObj = json.loads(jsonStr)

J'ai vérifié et l'objet JSON renvoie des scores / données en direct. Et tout ce que vous devez faire est de modifier la date dans l'URL 2019/01/26 pour obtenir les données de dates finales précédentes pour les jeux.


MODIFIER - SUPPLÉMENTAIRE

Cela pourrait vous aider à extraire les données. Remarquez comment je l'ai changé à la date d'aujourd'hui pour obtenir les données actuelles. Il le met dans une belle trame de données pour vous:

from pandas.io.json import json_normalize
import json
import requests

url = 'https://data.ncaa.com/casablanca/scoreboard/basketball-men/d1/2019/01/27/scoreboard.json'
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}    

# Thanks to InfectedDrake wisdom, the following 3 lines that I previously had can be replaced by a single line. See below
#response = requests.get(url, headers = headers)
#jsonStr = response.text
#jsonObj = json.loads(jsonStr)

jsonObj = requests.get(url, headers = headers).json()

result = json_normalize(jsonObj['games'])
6
chitown88 21 févr. 2019 à 09:52

Essayez de changer l'agent utilisateur dans l'en-tête de la demande pour le rendre identique à votre agent utilisateur Google Chrome en l'ajoutant à vos en-têtes:

headers = {
    'User-Agent': 'Add your google chrome user-agent here'
}
3
s. wolfe 26 janv. 2019 à 18:48

Comme indiqué dans les réponses ci-dessus, la chose que vous devez faire est de définir un agent utilisateur légitime. Ajoutez donc des en-têtes pour émuler un navigateur:

# This is a standard user-agent of Chrome browser running on Windows 10 
headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36' }

De plus, vous pouvez ajouter un autre ensemble d'en-têtes pour faire semblant (plus) comme un navigateur légitime. Ajoutez d'autres en-têtes comme celui-ci:

headers = { 
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36', 
'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 
'Accept-Language' : 'en-US,en;q=0.5', 
'Accept-Encoding' : 'gzip', 
'DNT' : '1', # Do Not Track Request Header 
'Connection' : 'close' }
0
Infected Drake 29 janv. 2019 à 01:22