Cómo corregir un nuevo error de no poder leer la URL en python para yahoo finanzas

2

He estado usando este código durante el último año, pero ahora produce un error. ¿Alguien sabe por qué sucede esto y cómo solucionarlo?


# Importing necessary packages
from pandas_datareader import data as web
import datetime as dt
import matplotlib.pyplot as plt
import pandas as pd
import os
import numpy as np

# Stock selection from Yahoo Finance
stock = input("Enter stock symbol or ticket symbol (Exp. General Electric is 'GE'): ")

# Visualizing the stock over time and setting up the dataframe
start_date = (dt.datetime.now() - dt.timedelta(days=40000)).strftime("%m-%d-%Y")
df = web.DataReader(stock, data_source='yahoo', start=start_date)
#THE ERROR IS ON THIS LINE^

plt.plot(df['Close'])
plt.title('Stock Prices Over Time',fontsize=14)
plt.xlabel('Date',fontsize=14)
plt.ylabel('Mid Price',fontsize=14)
plt.show()

RemoteDataError: No se puede leer la URL: https://finance.yahoo.com/quote/MCD/history?period1=-1830801600&period2=1625284799&interval=1d&frequency=1d&filter=history Texto de respuesta: b '\ n \ n \ n \ n Yahoo \ n \ n \ n \ n html {\ n altura: 100%; \ n} \ n cuerpo {\ n fondo: #fafafc url ( https://s.yimg.com/nn/img/sad-panda-201402200631 .png) 50% 50%; \ n background-size: cover; \ n height: 100%; \ n text-align: center; \ n fuente: 300 18px "helvetica neue", helvetica, verdana, tahoma, arial, sans- serif; \ n} \ n tabla {\ n altura: 100%; \ n ancho: 100%; \ n diseño de tabla: fijo; \ n borde-colapso: colapso; \ n borde-espaciado: 0; \ n borde : ninguno; \ n} \ n h1 {\ n tamaño de fuente: 42px; \ n peso de fuente: 400; \ n color: # 400090; \ n} \ np {\ n color: # 1A1A1A; \ n} \ n # message-1 {\ n font-weight: bold; \ n margin: 0; \ n} \ n # message-2 {\ n display: inline-block; \ n * display: inline; \ n zoom: 1 ; \ n max-width: 17em; \ n _width: 17em; \ n} \ n \ n \ n document.write ('& test = \' + encodeURIComponent (\ '% \') + \ '"width =" 0px "altura =" 0px "/> ');var beacon = new Image (); beacon.src = "// bcn.fp.yahoo.com/p?s=1197757129&t =" + ne ...

4
  • 2
    Extraer datos de Yahoo Finance no es tan sencillo. Implementaron un token de sesión con cada solicitud. Sin este token, verá una página HTML genérica, de ahí su error. Si está utilizando Chrome, encienda la Consola de desarrollador y luego vaya a la pestaña Red para verla. Es mejor utilizar una API de stock dedicada como AlphaVantage 2 de julio a las 14:52
  • ¿Es esto nuevo? Me sorprendió porque esto estaba funcionando bien hasta esta semana. 2 de julio a las 15:06
  • 1
    Hasta donde yo sé, han tenido ese mecanismo anti-raspado por un tiempo. Dependiendo de la biblioteca de scraping que use, es posible que haya podido omitirla hasta que actualicen el código. Dejé de usar Yahoo Finance hace varios años. Como dije, AlphaVantage es una mejor opción 2 de julio a las 15:15
  • Ok, entonces buscaré descubrir cómo implementar eso. ¡¡Gracias por tu ayuda!! 3 de julio a las 2:16
4

Yo tuve el mismo problema. En algún momento reciente, pdr dejó de trabajar con Yahoo (nuevamente). AlphaVantage no tiene todas las acciones que tiene Yahoo; El paquete googlefinance solo obtiene cotizaciones actuales hasta donde yo sé, no series de tiempo; el paquete yahoo-finance no funciona (o no pude hacerlo funcionar); Econdb devuelve algún tipo de marco de datos con un formato extraño (tal vez esto se pueda arreglar); y Quandl tiene un muro de pago en acciones fuera de Estados Unidos.

Entonces, como soy barato, busqué en la funcionalidad de descarga de Yahoo CSV y se me ocurrió esto, que devuelve un df muy parecido a lo que hace pdr:

import pandas as pd
from datetime import datetime as dt
import calendar
import io
import requests

# Yahoo history csv base url
yBase = 'https://query1.finance.yahoo.com/v7/finance/download/'
yHeaders = {
    'Accept': 'text/csv;charset=utf-8'
    }

def getYahooDf(ticker, startDate, endDate=None): # dates in ISO format
    start = dt.fromisoformat(startDate) # To datetime.datetime object
    fromDate = calendar.timegm(start.utctimetuple()) # To Unix timestamp format used by Yahoo
    if endDate is None:
        end=dt.now()
    else:
        end = dt.fromisoformat(endDate)
    toDate = calendar.timegm(end.utctimetuple())
    params = { 
        'period1': str(fromDate),
        'period2': str(toDate),
        'interval': '1d',
        'events': 'history',
        'includeAdjustedClose': 'true'
    }
    response = requests.request("GET", yBase + ticker, headers=yHeaders, params=params)
    if response.status_code < 200 or response.status_code > 299:
        return None
    else:
        csv = io.StringIO(response.text)
        df = pd.read_csv(csv, index_col='Date')
        return df
3
  • Y hoy esto tampoco funciona. Tengo un 403 Forbidden. Me las arreglé para solucionarlo falsificando el agente de usuario en los encabezados, pero tengo la sensación de que Yahoo también puede saltar sobre eso pronto. Sería genial si nos dieran algunas pautas, como "" usa este apikey ", o" está bien, pero limita tus solicitudes a 1000 por hora ", o incluso" no somos una API, vete ". 10 de julio a las 13:36
  • Si consigo que este script me funcione bien, me habrás resuelto un gran problema, ya que yahoo, de vez en cuando, me da el error que es el tema de esta pregunta. Las fechas en Python confunden a los más inexpertos, como yo. Si la fecha de inicio que quiero es "2017-1-4", ¿es esto lo que debo ingresar? "2019-04-05T00: 00: 0Z". Gracias por tu solución.
    efueyo
    10 de julio a las 16:40
  • 1
    Hola. ¡Eres bienvenido! La función toma fechas en formato ISO, es decir, aaaa-mm-dd. No necesitas la parte del tiempo. Entonces, su fecha de ejemplo sería 2017-01-04 (suponiendo que se refiera al cuatro de enero y no al primero de abril ;-)). Como mencioné en mi comentario anterior, deberá falsificar el agente de usuario en el encabezado, ya que Yahoo parece estar rechazando solicitudes del paquete de solicitudes de Python. Mi diccionario de encabezados ahora se ve así yHeaders = { 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0', 'Accept': 'text/csv;charset=utf-8' } 11 de julio a las 18:16
1

También funciona si proporciona encabezados a su objeto de datos de sesión que luego proporciona al lector de datos (por ejemplo, para el propósito de almacenamiento en caché)

session = requests_cache.CachedSession(cache_name='cache', backend='sqlite', expire_after=expire_after)

# just add headers to your session and provide it to the reader
session.headers = {     'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0',     'Accept': 'application/json;charset=utf-8'     }

data = web.DataReader(stock_names, 'yahoo', start, end, session=session)