urllib2.HTTPError: HTTP Error 403: Forbidden


102

Sto cercando di automatizzare il download dei dati storici delle scorte utilizzando Python. L'URL che sto cercando di aprire risponde con un file CSV, ma non riesco ad aprirlo utilizzando urllib2. Ho provato a cambiare l'agente utente come specificato in alcune domande precedenti, ho anche provato ad accettare i cookie di risposta, senza fortuna. Puoi per favore aiutare.

Nota: lo stesso metodo funziona per yahoo Finance.

Codice:

import urllib2,cookielib

site= "http://www.nseindia.com/live_market/dynaContent/live_watch/get_quote/getHistoricalData.jsp?symbol=JPASSOCIAT&fromDate=1-JAN-2012&toDate=1-AUG-2012&datePeriod=unselected&hiddDwnld=true"

hdr = {'User-Agent':'Mozilla/5.0'}

req = urllib2.Request(site,headers=hdr)

page = urllib2.urlopen(req)

Errore

File "C: \ Python27 \ lib \ urllib2.py", riga 527, in http_error_default solleva HTTPError (req.get_full_url (), code, msg, hdrs, fp) urllib2.HTTPError: HTTP Error 403: Forbidden

Grazie per la tua assistenza


Utilizzi Windows come piattaforma?
Denis

Risposte:


170

Aggiungendo qualche altra intestazione sono stato in grado di ottenere i dati:

import urllib2,cookielib

site= "http://www.nseindia.com/live_market/dynaContent/live_watch/get_quote/getHistoricalData.jsp?symbol=JPASSOCIAT&fromDate=1-JAN-2012&toDate=1-AUG-2012&datePeriod=unselected&hiddDwnld=true"
hdr = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
       'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
       'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
       'Accept-Encoding': 'none',
       'Accept-Language': 'en-US,en;q=0.8',
       'Connection': 'keep-alive'}

req = urllib2.Request(site, headers=hdr)

try:
    page = urllib2.urlopen(req)
except urllib2.HTTPError, e:
    print e.fp.read()

content = page.read()
print content

In realtà, funziona solo con questa intestazione aggiuntiva:

'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',

Quale di queste intestazioni secondo te mancava dalla richiesta originale?

1
WireShark ha mostrato che è stato inviato solo lo User-Agent, insieme a Connection: close, Host: www.nseindia.com, Accept-Encoding: identity
andrean

1
Sei il benvenuto, beh, quello che ho fatto davvero è aver controllato l'URL dal tuo script in un browser e, poiché funzionava lì, ho semplicemente copiato tutte le intestazioni delle richieste inviate dal browser e le ho aggiunte qui, e quella era la soluzione.
andrean

1
@Mee hai dato un'occhiata alla risposta qui sotto? era indirizzato specificamente per python 3, controlla se funziona per te ...
andrean

1
prova ad aggiungere anche le altre intestazioni (dalla mia risposta) alla richiesta. ci sono ancora molti altri motivi per cui un server potrebbe restituire un 403, controlla anche le altre risposte sull'argomento. per quanto riguarda il target, google in particolare è difficile, un po 'difficile da raschiare, hanno implementato molti metodi per prevenire lo scraping.
andrean

50

Funzionerà in Python 3

import urllib.request

user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7'

url = "http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers"
headers={'User-Agent':user_agent,} 

request=urllib.request.Request(url,None,headers) #The assembled request
response = urllib.request.urlopen(request)
data = response.read() # The data u need

2
È vero che alcuni siti (inclusa Wikipedia) bloccano le stringhe di user agent non browser comuni, come "Python-urllib / xy" inviato dalle librerie di Python. Anche un semplice "Mozilla" o "Opera" di solito è sufficiente per aggirarlo. Questo non si applica alla domanda originale, ovviamente, ma è comunque utile sapere.
efotinis

7

Il sito Web di NSE è cambiato e gli script precedenti sono ottimali per il sito Web corrente. Questo frammento può raccogliere dettagli giornalieri sulla sicurezza. I dettagli includono il simbolo, il tipo di titolo, la chiusura precedente, il prezzo di apertura, il prezzo alto, il prezzo basso, il prezzo medio, la quantità negoziata, il fatturato, il numero di transazioni, le quantità consegnabili e il rapporto percentuale tra consegnato e negoziato. Questi sono presentati convenientemente come elenco di forma di dizionario.

Versione Python 3.X con richieste e BeautifulSoup

from requests import get
from csv import DictReader
from bs4 import BeautifulSoup as Soup
from datetime import date
from io import StringIO 

SECURITY_NAME="3MINDIA" # Change this to get quote for another stock
START_DATE= date(2017, 1, 1) # Start date of stock quote data DD-MM-YYYY
END_DATE= date(2017, 9, 14)  # End date of stock quote data DD-MM-YYYY


BASE_URL = "https://www.nseindia.com/products/dynaContent/common/productsSymbolMapping.jsp?symbol={security}&segmentLink=3&symbolCount=1&series=ALL&dateRange=+&fromDate={start_date}&toDate={end_date}&dataType=PRICEVOLUMEDELIVERABLE"




def getquote(symbol, start, end):
    start = start.strftime("%-d-%-m-%Y")
    end = end.strftime("%-d-%-m-%Y")

    hdr = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
         'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
         'Referer': 'https://cssspritegenerator.com',
         'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
         'Accept-Encoding': 'none',
         'Accept-Language': 'en-US,en;q=0.8',
         'Connection': 'keep-alive'}

    url = BASE_URL.format(security=symbol, start_date=start, end_date=end)
    d = get(url, headers=hdr)
    soup = Soup(d.content, 'html.parser')
    payload = soup.find('div', {'id': 'csvContentDiv'}).text.replace(':', '\n')
    csv = DictReader(StringIO(payload))
    for row in csv:
        print({k:v.strip() for k, v in row.items()})


 if __name__ == '__main__':
     getquote(SECURITY_NAME, START_DATE, END_DATE)

Oltre a questo è relativamente modulare e pronto per l'uso snippet.


Grazie uomo! questo ha funzionato per me invece della risposta sopra da @andrean
Nitish Kumar Pal

Ciao, davvero non so più dove sbattere la testa, ho provato questa soluzione e molte altre ma continuo a ricevere l'errore 403. C'è qualcos'altro che posso provare?
Francesco

Lo stato 403 ha lo scopo di informare che il tuo browser non è autenticato per utilizzare questo servizio. Può darsi che nel tuo caso richieda davvero l'autenticazione con autenticazione di base, oauth ecc.
Supreet Sethi
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.