2014-10-21 96 views
10

我的代碼成功地從[http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY]中刪除了tr align = center標籤,並將td元素寫入文本文件。用BeautifulSoup和Python刮掉多個頁面

但是,在上面的網站上有多個頁面可用,我希望這些頁面能夠被抓取。

例如,通過上面的網址,當我點擊「第2頁」鏈接時,整體網址不會改變。我查看了頁面源代碼並看到了JavaScript代碼以進入下一頁。

如何更改我的代碼以從所有可用的列出頁面中抓取數據?

我的代碼,第1頁只適用:

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

這是不是要求或真正poosible任何其他去取HTML東西的工具,如果你想這樣做,你必須去與像硒或webdriver的網絡驅動器,但它的方式更加複雜,要求。 。祝你好運 – brunsgaard 2014-10-21 23:03:30

+0

這真的只是簡單的URL操作。只需使用Google Chrome的檢測工具或Firefox的Firebug檢查「POST」請求即可。請參閱下面的答案。 – Manhattan 2014-10-21 23:05:28

+0

@Nanashi,你也許應該解釋一下如何在你的回答中做你的建議 – 2014-10-21 23:06:51

回答

36

這裏的竅門是檢查在進出換頁動作來的請求時您點擊鏈接查看的其他頁面。檢查的方法是使用Chrome的檢測工具(通過按F12)或在Firefox中安裝Firebug擴展。我將在這個答案中使用Chrome的檢測工具。請參閱下面的設置。現在

enter image description here

,我們希望看到的要麼是GET請求到另一個頁面或POST請求改變頁面。工具打開時,點擊頁碼。對於一個非常短暫的時刻,只會出現一個請求,並且這是一個POST方法。所有其他元素將快速跟隨並填充頁面。請參閱下文了解我們正在尋找的內容。

enter image description here

點擊上面POST方法。它應該彈出一個包含製表符的排序子窗口。點擊Headers標籤。這個頁面列出了請求標題,幾乎是另一方(例如站點)需要的標識信息,以便您能夠連接(其他人可以比我更好地解釋這個問題)。

只要網址包含頁碼,位置標記或類別等變量,通常情況下,網站就會使用查詢字符串。長話短說,它類似於一個SQL查詢(實際上,它有時是一個SQL查詢),它允許該站點提取所需的信息。如果是這種情況,您可以檢查查詢字符串參數的請求標頭。向下滾動一下,你應該找到它。

enter image description here

正如你所看到的,查詢字符串參數在我們的URL匹配的變量。稍微低一點,你可以看到Form Data下面有pageNum: 2。這是關鍵。

POST請求通常被稱爲表單請求,因爲這些是您在提交表單,登錄到網站等時提出的請求類型。基本上,幾乎任何您必須提交信息的地方。大多數人沒有看到的是POST請求有一個他們關注的URL。一個很好的例子就是當你登錄到一個網站,並且非常簡單地看到你的地址欄變成某種亂碼網址之後才決定在/index.html或某些地方。

以上段落的基本含義是,您可以(但不總是)將表單數據追加到您的URL中,並且它將執行POST請求。要知道您必須追加的確切字符串,請點擊view source

enter image description here

測試,如果它的工作原理是將其添加到URL。

enter image description here

的Et瞧,它的工作原理。現在,真正的挑戰是:自動獲取最後一頁,並抓取所有頁面。你的代碼非常多。剩下要做的事情就是獲取頁面的數量,構建一個需要抓取的URL列表,並對它們進行迭代。

修改代碼如下:

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

我們使用正則表達式來獲得正確的鏈接。然後使用列表理解,我們建立了一個URL字符串列表。最後,我們重複它們。

結果:

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

希望有所幫助。

編輯:

在百無聊賴中,我想我只是創造了整個類目錄的刮刀。而且,當只有一個可用頁面時,我更新上面和下面的代碼,以便不出錯。

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

如何確定可用頁面的長度或數量? – 2014-10-21 23:12:51

+0

這就是我現在正在做的。 :)等待編輯在jiffy。 – Manhattan 2014-10-21 23:14:33

+0

乾杯@Nanashi真的很感謝幫助! – 2014-10-21 23:30:14