2016-01-06 10 views
5

Desidero scaricare tutti gli .xls o .xlsx o .csv da questo sito Web in una cartella specificata.Scaricare file .xls da una pagina Web utilizzando Python e BeautifulSoup

https://www.rbi.org.in/Scripts/bs_viewcontent.aspx?Id=2009 

Ho esaminato Mechanize, bella zuppa, urllib2 ecc Mechanize non funziona in Python 3, urllib2 ha avuto anche problemi con Python 3, ho cercato soluzione, ma non ho potuto. Quindi, attualmente sto cercando di farlo funzionare usando Beautiful Soup.

ho trovato un po 'di codice di esempio e ha tentato di modificarlo per soddisfare il mio problema, come segue -

from bs4 import BeautifulSoup 
# Python 3.x 
from urllib.request import urlopen, urlretrieve, quote 
from urllib.parse import urljoin 

url = 'https://www.rbi.org.in/Scripts/bs_viewcontent.aspx?Id=2009/' 
u = urlopen(url) 
try: 
    html = u.read().decode('utf-8') 
finally: 
    u.close() 

soup = BeautifulSoup(html) 
for link in soup.select('div[webpartid] a'): 
    href = link.get('href') 
    if href.startswith('javascript:'): 
     continue 
    filename = href.rsplit('/', 1)[-1] 
    href = urljoin(url, quote(href)) 
    try: 
     urlretrieve(href, filename) 
    except: 
     print('failed to download') 

Tuttavia, quando viene eseguito questo codice non estrarre i file dalla pagina di destinazione, né in uscita qualsiasi messaggio di errore (ad es. "download non riuscito").

  • Come posso utilizzare BeautifulSoup per selezionare i file di Excel dalla pagina?
  • Come posso scaricare questi file su un file locale usando Python?
+0

Puoi descrivere in che modo il tuo codice "non ha funzionato"? Il codice postato è rientrato in modo errato e quindi non funzionerebbe affatto. – mfitzp

+0

Il codice è stato eseguito a volte ma non ha mai creato alcun file. Per quanto riguarda la rientranza, mi scuso mentre postando Devo averlo rovinato, ma mi assicuro che quando ho eseguito il codice, mi sono occupato dell'indentazione –

+1

Ho una soluzione funzionante per questo problema, ma la domanda è chiusa quindi non posso più postarla . L'ho postato come Gist qui https://gist.github.com/mfitzp/29522e2ac4057bf01745 – mfitzp

risposta

2

I problemi con lo script come lo distingue sono:

  1. Il url termina con una / che dà una pagina non valida quando richiesto, non elenca i file che si desidera scaricare.
  2. Il selettore CSS in soup.select(...) sta selezionando div con l'attributo webpartid che non esiste da nessuna parte in quel documento collegato.
  3. Stai partecipando all'URL e citandolo, anche se i link sono indicati nella pagina come URL assoluti e non hanno bisogno di quotazioni.
  4. Il blocco try:...except: interrompe la visualizzazione degli errori generati durante il tentativo di download del file. L'utilizzo di un blocco except senza un'eccezione specifica è una cattiva pratica e dovrebbe essere evitato.

Una versione modificata del codice che sarà ottenere i file corretti e tentare di scaricarli è la seguente:

from bs4 import BeautifulSoup 
# Python 3.x 
from urllib.request import urlopen, urlretrieve, quote 
from urllib.parse import urljoin 

# Remove the trailing/you had, as that gives a 404 page 
url = 'https://www.rbi.org.in/Scripts/bs_viewcontent.aspx?Id=2009' 
u = urlopen(url) 
try: 
    html = u.read().decode('utf-8') 
finally: 
    u.close() 

soup = BeautifulSoup(html, "html.parser") 

# Select all A elements with href attributes containing URLs starting with http:// 
for link in soup.select('a[href^="http://"]'): 
    href = link.get('href') 

    # Make sure it has one of the correct extensions 
    if not any(href.endswith(x) for x in ['.csv','.xls','.xlsx']): 
     continue 

    filename = href.rsplit('/', 1)[-1] 
    print("Downloading %s to %s..." % (href, filename)) 
    urlretrieve(href, filename) 
    print("Done.") 

Tuttavia, se si esegue questo si noterà che un'eccezione urllib.error.HTTPError: HTTP Error 403: Forbidden viene lanciato, anche se il file è scaricabile nel browser. All'inizio pensavo che si trattasse di un controllo di rinvio (per evitare il collegamento in hotlink), tuttavia se guardi la richiesta nel tuo browser (ad esempio gli strumenti per sviluppatori di Chrome) noterai che la richiesta iniziale http:// viene bloccata anche lì, quindi Chrome tenta una richiesta https:// per lo stesso file.

In altre parole, la richiesta deve passare tramite HTTPS per funzionare (nonostante ciò che dicono gli URL nella pagina). Per risolvere questo problema è necessario riscrivere lo http: a https: prima di utilizzare l'URL per la richiesta. Il seguente codice modificherà correttamente gli URL e scaricherà i file.Ho anche aggiunto una variabile per specificare la cartella di output, che viene aggiunto al nome del file utilizzando os.path.join:

import os 
from bs4 import BeautifulSoup 
# Python 3.x 
from urllib.request import urlopen, urlretrieve 

URL = 'https://www.rbi.org.in/Scripts/bs_viewcontent.aspx?Id=2009' 
OUTPUT_DIR = '' # path to output folder, '.' or '' uses current folder 

u = urlopen(URL) 
try: 
    html = u.read().decode('utf-8') 
finally: 
    u.close() 

soup = BeautifulSoup(html, "html.parser") 
for link in soup.select('a[href^="http://"]'): 
    href = link.get('href') 
    if not any(href.endswith(x) for x in ['.csv','.xls','.xlsx']): 
     continue 

    filename = os.path.join(OUTPUT_DIR, href.rsplit('/', 1)[-1]) 

    # We need a https:// URL for this site 
    href = href.replace('http://','https://') 

    print("Downloading %s to %s..." % (href, filename)) 
    urlretrieve(href, filename) 
    print("Done.") 
+0

Splendidamente spiegato, mi rendo conto di avere così tanto da imparare. Ti sono così grato. –

1

ho trovato questo per essere un buon esempio di lavoro, utilizzando i BeautifulSoup4, requests e wget moduli per Python 2.7:

import requests 
import wget 
import os 

from bs4 import BeautifulSoup, SoupStrainer 

url = 'https://www.rbi.org.in/Scripts/bs_viewcontent.aspx?Id=2009' 

file_types = ['.xls', '.xlsx', '.csv'] 

for file_type in file_types: 

    response = requests.get(url) 

    for link in BeautifulSoup(response.content, 'html.parser', parse_only=SoupStrainer('a')): 
     if link.has_attr('href'): 
      if file_type in link['href']: 
       full_path = url + link['href'] 
       wget.download(full_path) 
1
i tried above code still giving me urllib.error.HTTPError: HTTP Error 403: Forbidden 


Also tried by adding user agents my modified code 


import os 

from bs4 import BeautifulSoup 
# Python 3.x 
from urllib.request import Request,urlopen, urlretrieve 

headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'} 
URL = Request('https://www.rbi.org.in/scripts/bs_viewcontent.aspx?Id=2009', headers=headers) 

#URL = 'https://www.rbi.org.in/scripts/bs_viewcontent.aspx?Id=2009' 

OUTPUT_DIR = 'E:\python\out' # path to output folder, '.' or '' uses current folder 

u = urlopen(URL) 
try: 
    html = u.read().decode('utf-8') 
finally: 
    u.close() 

soup = BeautifulSoup(html, "html.parser") 
for link in soup.select('a[href^="http://"]'): 
    href = link.get('href') 
    if not any(href.endswith(x) for x in ['.csv','.xls','.xlsx']): 
     continue 

    filename = os.path.join(OUTPUT_DIR, href.rsplit('/', 1)[-1]) 

    # We need a https:// URL for this site 
    href = href.replace('http://','https://') 

    print("Downloading %s to %s..." % (href, filename)) 
    urlretrieve(href, filename) 
    print("Done.") 
0

questo ha funzionato meglio per me ... usando python3

import os 
import urllib 

from bs4 import BeautifulSoup 
# Python 3.x 
from urllib.request import urlopen, urlretrieve 
from urllib.error import HTTPError 

URL = 'https://www.rbi.org.in/Scripts/bs_viewcontent.aspx?Id=2009' 
OUTPUT_DIR = '' # path to output folder, '.' or '' uses current folder 

u = urlopen(URL) 
try: 
    html = u.read().decode('utf-8') 
finally: 
    u.close() 

soup = BeautifulSoup(html, "html.parser") 
for link in soup.select('a[href^="http://"]'): 
    href = link.get('href') 
if not any(href.endswith(x) for x in ['.csv','.xls','.xlsx']): 
    continue 

filename = os.path.join(OUTPUT_DIR, href.rsplit('/', 1)[-1]) 

# We need a https:// URL for this site 
href = href.replace('http://','https://') 

try: 
    print("Downloading %s to %s..." % (href, filename)) 
    urlretrieve(href, filename) 
    print("Done.") 
except urllib.error.HTTPError as err: 
    if err.code == 404: 
     continue 
Problemi correlati