2014-10-21 18 views
10

Kodum, [align = center tags] [http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY] öğesinden başarıyla başlıyor ve td öğelerini bir metin dosyasına yazar. Bununla birlikte, yukarıdaki sitede, kazıma yapmak istediğim birden fazla sayfa var. Örneğin, yukarıdaki url ile, "sayfa 2" bağlantısına tıkladığımda, genel URL değişmeyecektir. Sayfa kaynağına baktım ve bir sonraki sayfaya ilerlemek için bir javascript kodu gördüm.Birden çok sayfayı BeautifulSoup ve Python ile kazıyın

Verilerim, listelenen tüm mevcut sayfalardan veri kazımak için nasıl değiştirilir? Sadece sayfa 1 için çalışır

Kodum:

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

Bu istek veya gerçekten Yemeği poosible olmayan diğer sizden selenyum veya WebDriver gibi bir web sürücüsü ile gitmek zorunda olduğunu yapmak istiyorsanız, html şeyler aracını çağır ama istek bu şekilde daha karmaşıktır. iyi şanslar – brunsgaard

+0

Gerçekten basit bir URL manipülasyonu. Google Chrome'un inceleme aracını veya Firefox için Firebug'u kullanarak "POST" isteklerini kontrol edin. Cevabımı aşağıya bakın. – Manhattan

+0

@Nanashi, cevabınızda önerdiğin şeyi nasıl yapacağını açıklayabilirsin –

cevap

36
İşin püf noktası burada diğer görüntülemek için linke tıkladığında ve sayfa değiştirme eyleminin dışarı geliyor isteklerini kontrol etmektir

sayfaları. Bunu kontrol etmenin yolu, Chrome'un inceleme aracını kullanmaktır (F12 tuşlarına basarak) veya Firebug eklentisini Firefox'a yüklemek. Chrome'un bu aracı kullanarak inceleme aracını kullanacağım. Ayarlarım için aşağıya bakın.

enter image description here

Şimdi, biz görmek istiyorum başka bir sayfaya bir GET istek veya sayfayı değiştiren POST istek ya olduğunu. Araç açıkken, bir sayfa numarasına tıklayın. Gerçekten kısa bir an için, görünecek sadece bir istek olacak ve bu bir POST yöntemidir. Diğer tüm elemanlar hızlı bir şekilde sayfayı takip eder ve doldurur. Aradığımız şey için aşağıya bakın. Yukarıdaki POST yöntemine

enter image description here

tıklayın. Sekmeleri olan bir çeşit alt pencere getirmelidir. Headers sekmesine tıklayın. Bu sayfa istek başlıklarını, hemen hemen diğer tarafın (örneğin, sitenin) sizden bağlanabilmesi için ihtiyaç duyacağınız tanımlama bilgilerini listeler (bu başkası benden daha iyi bir başkasını açıklayabilir). URL, sayfa numaraları, yer işaretçileri veya kategoriler gibi değişkenlere sahip olduğunda, daha sık olmamakla birlikte, site sorgu dizeleri kullanır. Uzun hikaye kısa, bir SQL sorgusuna benzer (aslında, bu bir SQL sorgusudur, bazen) sitenin ihtiyaç duyduğunuz bilgileri almasını sağlar. Bu durumda, sorgu dizesi parametreleri için istek başlıklarını kontrol edebilirsiniz. Biraz aşağı kaydır ve bulmalısın. Gördüğünüz gibi

enter image description here

, sorgu dizesi parametreleri bizim URL içinde değişkenleri eşleşir. Altında biraz, Form Data'un altında pageNum: 2 ile görebilirsiniz. Bu anahtar.

POST istekleri daha çok form istekleri olarak bilinir çünkü bunlar form gönderirken, web sitelerine giriş yaptığınızda yapılan isteklerdir. Temel olarak, bilgi göndermeniz gereken her şey. Çoğu kullanıcının görmediği şey, POST isteğinin izledikleri bir URL'ye sahip olmasıdır. Bunun iyi bir örneği, bir web sitesine giriş yaptığınızda ve çok kısa bir süre içinde, /index.html veya somesuch'a yerleşmeden önce adres çubuğunuzun bir tür anlamsız URL'ye dönüştüğünü gösterir.

Yukarıdaki paragrafın anlamı, form verisini URL'nize ekleyebileceğiniz (ancak her zaman yapamayacağınız) ve yürütme sırasında sizin için POST isteğinizi gerçekleştirmenizdir. Eklemek istediğiniz tam dizeyi bilmek için view source'a tıklayın. o URL'ye ekleyerek çalışırsa

enter image description here

test edin.

enter image description here

işte, işe yarıyor. Şimdi, asıl zorluk: son sayfayı otomatik olarak alma ve tüm sayfaları kazıma. Kodun çok fazla var. Yapılması gereken tek şey, sayfaların sayısını almak, kazıma yapılacak URL'lerin bir listesini oluşturmak ve bunların üzerinde yineleme yapmaktır.

Modifiye kod aşağıda:

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

Biz doğru bağlantıları almak için normal ifadeleri kullanın. Sonra liste kavramasını kullanarak, bir URL dizeleri listesi oluşturduk. Sonunda, onların üzerinde yineliyoruz.

Sonuçlar: yardımcı

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

Umut.

DÜZENLEME:

sırf can sıkıntısı dışında, ben sadece tüm sınıf dizin için bir kazıyıcı yarattı düşünüyorum. Ayrıca, yalnızca tek bir sayfa olduğunda hata vermemek için hem yukarıdaki hem de yukarıdaki kodları güncellerim.

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

Kullanılabilir sayfaların uzunluğunu veya miktarını belirlemek için ne yapabilirim? –

+0

Şu an bunu yapıyorum. :) Düzenlemeyi bir jiffy içinde bekleyin. – Manhattan

+0

Cheers @Nanashi yardım için gerçekten minnettar! –