2014-10-21 33 views
10

Mein Code schabt erfolgreich tr align = Center-Tags aus [http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY] und schreibt die Td-Elemente in eine Textdatei.Kratzen mehrere Seiten mit BeautifulSoup und Python

Allerdings gibt es mehrere Seiten auf der oben genannten Website, in denen ich gerne kratzen könnte.

Zum Beispiel, mit der obigen URL, wenn ich den Link zu "Seite 2" klicken die allgemeine URL ändert sich nicht. Ich schaute auf die Seitenquelle und sah einen JavaScript-Code, um zur nächsten Seite zu gelangen.

Wie kann mein Code geändert werden, um Daten von allen verfügbaren aufgelisteten Seiten zu kratzen?

Mein Code, der nur für Seite 1 funktioniert:

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

Es ist nicht wirklich poosible mit Anfragen oder anderer html Sachen Werkzeug holen gehen, wenn Sie, dass Sie mit einem Web-Treiber wie Selen oder WebDriver gehen müssen tun wollen, aber es ist viel komplizierter, dass Anfrage. Viel Glück – brunsgaard

+0

Es ist nur einfache URL-Manipulation, wirklich. Überprüfen Sie einfach die 'POST'-Anfragen mit dem Inspektionstool von Google Chrome oder Firebug für Firefox. Siehe meine Antwort unten. – Manhattan

+0

@Nanashi, Sie sollten vielleicht erklären, wie Sie das tun, was Sie in Ihrer Antwort vorschlagen –

Antwort

36

Der Trick hier ist, um die Anfragen zu überprüfen, die in den und aus dem Seitenwechsel Aktion kommen, wenn Sie auf den Link klicken, den anderen zu sehen Seiten. Um dies zu überprüfen, verwenden Sie das Prüfwerkzeug von Chrome (über die Tasten F12) oder installieren Sie die Firebug-Erweiterung in Firefox. Ich werde in dieser Antwort das Überprüfungstool von Chrome verwenden. Siehe unten für meine Einstellungen.

enter image description here

Nun, was wollen wir sehen, ist entweder ein GET Anfrage auf eine andere Seite oder eine POST Anforderung, die die Seite ändert. Klicken Sie bei geöffnetem Werkzeug auf eine Seitennummer. Für einen wirklich kurzen Moment wird nur eine Anfrage erscheinen und es ist eine POST Methode. Alle anderen Elemente werden schnell folgen und die Seite füllen. Nachstehend finden Sie, wonach wir suchen.

enter image description here

Klicken Sie auf die oben POST Methode. Es sollte ein Unterfenster mit Registerkarten erscheinen. Klicken Sie auf die Registerkarte Headers. Diese Seite listet die Anforderungsheader auf, so ziemlich das Identifizierungskram, das die andere Seite (die Seite zum Beispiel) von Ihnen braucht, um sich verbinden zu können (jemand anderes kann das viel besser erklären als ich).

Wenn die URL Variablen wie Seitennummern, Ortsmarkierungen oder Kategorien enthält, verwendet die Site häufig Query-Strings. Lange Geschichte kurz gemacht, es ist ähnlich wie eine SQL-Abfrage (tatsächlich ist es manchmal eine SQL-Abfrage), die es der Website ermöglicht, die Informationen, die Sie benötigen, zu ziehen. Wenn dies der Fall ist, können Sie die Anforderungsheader für Abfragezeichenfolgenparameter überprüfen. Scrolle ein wenig runter und du solltest es finden.

enter image description here

Wie Sie sehen können, passen Sie die Query-String-Parameter, um die Variablen in unserer URL. Ein wenig darunter können Sie Form Data mit pageNum: 2 darunter sehen. Das ist der Schlüssel.

POST Anfragen werden häufiger als Formularanforderungen bezeichnet, da dies die Art von Anfragen ist, die beim Senden von Formularen, beim Anmelden bei Websites usw. gestellt werden. Im Grunde genommen alles, wo Sie Informationen einreichen müssen. Was die meisten Leute nicht sehen, ist, dass POST Anfragen eine URL haben, der sie folgen. Ein gutes Beispiel hierfür ist, wenn Sie sich bei einer Website anmelden und kurz gesagt, dass sich Ihre Adressleiste in eine Art Kauderwelsch-URL verwandelt, bevor Sie sich auf /index.html oder so etwas festlegen.

Was der obige Absatz im Grunde bedeutet, dass Sie die Formulardaten an Ihre URL (aber nicht immer) anhängen können und es die POST Anfrage für Sie bei der Ausführung ausführt. Um die genaue Zeichenfolge zu kennen, die Sie anhängen müssen, klicken Sie auf view source.

enter image description here

-Test, wenn es durch Zugabe zu der URL funktioniert.

enter image description here

Et voila, es funktioniert. Jetzt die eigentliche Herausforderung: die letzte Seite automatisch abrufen und alle Seiten scrapen. Dein Code ist ziemlich gut da. Die einzigen Dinge, die noch erledigt werden müssen, sind die Anzahl der Seiten zu erhalten, eine Liste von URLs zu erstellen und sie zu durchlaufen.

Modified-Code ist unter:

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') 

Wir reguläre Ausdrücke verwenden, die richtigen Links zu erhalten. Dann haben wir mithilfe des Listenverständnisses eine Liste von URL-Strings erstellt. Schließlich iterieren wir über sie.

Ergebnisse:

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

Hoffnung, das hilft.

EDIT:

Aus purer Langeweile, ich glaube, ich nur einen Schaber für die gesamte Klasse Verzeichnis erstellt. Außerdem aktualisiere ich sowohl die obigen als auch die folgenden Codes, um keine Fehler auszuschließen, wenn nur eine einzige Seite verfügbar ist.

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

Was kann ich tun, um die Länge oder Menge der verfügbaren Seiten zu bestimmen? –

+0

Das mache ich jetzt. :) Warte auf die Bearbeitung im Handumdrehen. – Manhattan

+0

Cheers @Nanashi wirklich die Hilfe zu schätzen wissen! –

Verwandte Themen