2014-10-21 24 views
10

Il mio codice cancella con successo i tag tr align = center da [http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY] e scrive gli elementi td in un file di testo.Scrittura di più pagine con BeautifulSoup e Python

Tuttavia, ci sono più pagine disponibili nel sito in alto in cui vorrei essere in grado di grattare.

Ad esempio, con l'url sopra, quando faccio clic sul collegamento a "pagina 2" l'url generale NON cambia. Ho guardato il sorgente della pagina e ho visto un codice javascript per passare alla pagina successiva.

In che modo è possibile modificare il codice per acquisire dati da tutte le pagine elencate disponibili?

Il mio codice che funziona per la pagina di 1 solo:

import bs4 
import requests 

response = requests.get('http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY') 

soup = bs4.BeautifulSoup(response.text) 
soup.prettify() 

acct = open("/Users/it/Desktop/accounting.txt", "w") 

for tr in soup.find_all('tr', align='center'): 
    stack = [] 
    for td in tr.findAll('td'): 
     stack.append(td.text.replace('\n', '').replace('\t', '').strip()) 

    acct.write(", ".join(stack) + '\n') 
+0

In realtà non è poosible con richieste o qualsiasi altro andare a prendere strumento roba html, se si vuole fare che si deve andare con un autista web come selenio o WebDriver, ma è molto più complicato che richiesta. . buona fortuna – brunsgaard

+0

E 'solo una semplice manipolazione degli URL, davvero. Basta controllare le richieste del 'POST' usando lo strumento di ispezione di Google Chrome o Firebug per Firefox. Vedi la mia risposta qui sotto. – Manhattan

+0

@Nanashi, dovresti forse spiegare come fare ciò che suggerisci nella tua risposta –

risposta

36

Il trucco è quello di verificare le richieste che stanno venendo dentro e fuori l'azione pagina di cambio quando si fa clic sul link per visualizzare l'altra pagine. Il modo per verificarlo è utilizzare lo strumento di ispezione di Chrome (premendo F12) o installando l'estensione Firebug in Firefox. Userò lo strumento di ispezione di Chrome in questa risposta. Vedi sotto per le mie impostazioni.

enter image description here

Ora, quello che vogliamo vedere è sia una richiesta GET a un'altra pagina o una richiesta POST che cambia la pagina. Mentre lo strumento è aperto, fai clic su un numero di pagina. Per un momento veramente breve, ci sarà solo una richiesta che apparirà, ed è un metodo POST. Tutti gli altri elementi seguiranno e riempiranno rapidamente la pagina. Vedi sotto per quello che stiamo cercando.

enter image description here

Cliccare sul metodo di cui sopra POST. Dovrebbe apparire una sottofinestra che ha le schede. Fare clic sulla scheda Headers. Questa pagina elenca le intestazioni delle richieste, praticamente le informazioni di identificazione che l'altro lato (il sito, ad esempio) ha bisogno di te per essere in grado di connettersi (qualcun altro può spiegare questo muuuch meglio di me).

Ogni volta che l'URL ha variabili come numeri di pagina, indicatori di posizione o categorie, più spesso no, il sito utilizza stringhe di query. Lunga storia fatta in breve, è simile a una query SQL (in realtà, è una query SQL, a volte) che consente al sito di estrarre le informazioni necessarie. In tal caso, è possibile controllare le intestazioni delle richieste per i parametri della stringa di query. Scorri un po 'e dovresti trovarlo.

enter image description here

Come si può vedere, i parametri di stringa di query corrispondono alle variabili nel nostro URL. Un po 'più in basso, è possibile vedere Form Data con pageNum: 2 sotto di esso. Questa è la chiave.

POST Le richieste sono più comunemente note come richieste di modulo perché sono il tipo di richieste fatte quando si inviano moduli, si accede a siti Web, ecc. In pratica, praticamente tutto ciò che è necessario inviare. Ciò che la maggior parte delle persone non vede è che le richieste POST hanno un URL che seguono. Un buon esempio di questo è quando si accede a un sito Web e, molto brevemente, vedere la propria barra degli indirizzi trasformarsi in una sorta di URL senza senso prima di stabilirsi su /index.html o somesuch.

Ciò che il paragrafo precedente significa in sostanza è che è possibile (ma non sempre) aggiungere i dati del modulo al proprio URL e che eseguirà la richiesta POST per l'esecuzione. Per conoscere la stringa esatta da aggiungere, fare clic su view source.

enter image description here

prova se funziona con l'aggiunta alla URL.

enter image description here

Et voilà, funziona. Ora, la vera sfida: ottenere automaticamente l'ultima pagina e raschiare tutte le pagine. Il tuo codice è praticamente lì. L'unica cosa che rimane da fare è ottenere il numero di pagine, costruire un elenco di URL da raschiare e scorrere su di essi.

codice

Modified è qui sotto:

from bs4 import BeautifulSoup as bsoup 
import requests as rq 
import re 

base_url = 'http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY' 
r = rq.get(base_url) 

soup = bsoup(r.text) 
# Use regex to isolate only the links of the page numbers, the one you click on. 
page_count_links = soup.find_all("a",href=re.compile(r".*javascript:goToPage.*")) 
try: # Make sure there are more than one page, otherwise, set to 1. 
    num_pages = int(page_count_links[-1].get_text()) 
except IndexError: 
    num_pages = 1 

# Add 1 because Python range. 
url_list = ["{}&pageNum={}".format(base_url, str(page)) for page in range(1, num_pages + 1)] 

# Open the text file. Use with to save self from grief. 
with open("results.txt","wb") as acct: 
    for url_ in url_list: 
     print "Processing {}...".format(url_) 
     r_new = rq.get(url_) 
     soup_new = bsoup(r_new.text) 
     for tr in soup_new.find_all('tr', align='center'): 
      stack = [] 
      for td in tr.findAll('td'): 
       stack.append(td.text.replace('\n', '').replace('\t', '').strip()) 
      acct.write(", ".join(stack) + '\n') 

Usiamo le espressioni regolari per ottenere i collegamenti adeguati. Quindi utilizzando la comprensione delle liste, abbiamo creato un elenco di stringhe URL. Infine, li iteriamo su di loro.

Risultati:

Processing http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY&pageNum=1... 
Processing http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY&pageNum=2... 
Processing http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY&pageNum=3... 
[Finished in 6.8s] 

enter image description here

Speranza che aiuta.

EDIT:

Per pura noia, penso che ho appena creato un raschietto per l'intera directory di classe. Inoltre, aggiorno entrambi i codici sopra e sotto per non dare errori quando è disponibile una sola pagina.

from bs4 import BeautifulSoup as bsoup 
import requests as rq 
import re 

spring_2015 = "http://my.gwu.edu/mod/pws/subjects.cfm?campId=1&termId=201501" 
r = rq.get(spring_2015) 
soup = bsoup(r.text) 
classes_url_list = [c["href"] for c in soup.find_all("a", href=re.compile(r".*courses.cfm\?campId=1&termId=201501&subjId=.*"))] 
print classes_url_list 

with open("results.txt","wb") as acct: 
    for class_url in classes_url_list: 
     base_url = "http://my.gwu.edu/mod/pws/{}".format(class_url) 
     r = rq.get(base_url) 

     soup = bsoup(r.text) 
     # Use regex to isolate only the links of the page numbers, the one you click on. 
     page_count_links = soup.find_all("a",href=re.compile(r".*javascript:goToPage.*")) 
     try: 
      num_pages = int(page_count_links[-1].get_text()) 
     except IndexError: 
      num_pages = 1 

     # Add 1 because Python range. 
     url_list = ["{}&pageNum={}".format(base_url, str(page)) for page in range(1, num_pages + 1)] 

     # Open the text file. Use with to save self from grief. 
     for url_ in url_list: 
      print "Processing {}...".format(url_) 
      r_new = rq.get(url_) 
      soup_new = bsoup(r_new.text) 
      for tr in soup_new.find_all('tr', align='center'): 
       stack = [] 
       for td in tr.findAll('td'): 
        stack.append(td.text.replace('\n', '').replace('\t', '').strip()) 
       acct.write(", ".join(stack) + '\n') 
+0

Cosa posso fare per determinare la lunghezza o la quantità di pagine disponibili? –

+0

Questo è quello che sto facendo ora. :) Attendi la modifica in un batter d'occhio. – Manhattan

+0

Cheers @Nanashi apprezza molto l'aiuto! –