2014-08-28 47 views
6

我正在運行這個課程網站的刮板,我想知道是否有更快的方式來刮頁面,一旦我把它放入美麗的。它比我預期的要長。加速beautifulsoup

小貼士?

from selenium import webdriver 
from selenium.webdriver.common.keys import Keys 
from selenium.webdriver.support.ui import Select 
from selenium.webdriver.support import expected_conditions as EC 

from bs4 import BeautifulSoup 

driver = webdriver.PhantomJS() 
driver.implicitly_wait(10) # seconds 
driver.get("https://acadinfo.wustl.edu/Courselistings/Semester/Search.aspx") 
select = Select(driver.find_element_by_name("ctl00$Body$ddlSchool")) 

parsedClasses = {} 

for i in range(len(select.options)): 
    print i 
    select = Select(driver.find_element_by_name("ctl00$Body$ddlSchool")) 
    select.options[i].click() 
    upperLevelClassButton = driver.find_element_by_id("Body_Level500") 
    upperLevelClassButton.click() 
    driver.find_element_by_name("ctl00$Body$ctl15").click() 

    soup = BeautifulSoup(driver.page_source, "lxml") 

    courses = soup.select(".CrsOpen") 
    for course in courses: 
     courseName = course.find_next(class_="ResultTable")["id"][13:] 
     parsedClasses[courseName] = [] 
     print courseName 
     for section in course.select(".SecOpen"): 
      classInfo = section.find_all_next(class_="ItemRowCenter") 
      parsedClasses[courseName].append((int(classInfo[0].string), int(classInfo[1].string), int(classInfo[2].string))) 

print parsedClasses 
print parsedClasses['FL2014' + 'A46' + '3284'] 

driver.quit() 
+0

使用'lxml'直接(與XPath表達式),如果你關心速度。 – roippi 2014-08-28 01:26:50

+0

這實質上是一個代碼審查請求,因此不適合SO。 SE網絡中有一個專門用於代碼評論的網站:http://codereview.stackexchange.com/ – Louis 2014-08-28 10:10:22

+1

@Louis我不同意,它也是關於從搜索結果中獲取數據的替代方法。這不僅僅是代碼和質量。 – alecxe 2014-08-28 13:42:21

回答

10

好吧,你真的可以加速這一增長:

既然這是ASP.NET生成的表單,並且由於它的安全特性,事情變得更加複雜一些。下面是完整的代碼,不要害怕它 - 我添加的意見和開放的問題:

import re 
from bs4 import BeautifulSoup, SoupStrainer 
import requests 

# start session and get the search page 
session = requests.Session() 
response = session.get('https://acadinfo.wustl.edu/Courselistings/Semester/Search.aspx') 

# parse the search page using SoupStrainer and lxml 
strainer = SoupStrainer('form', attrs={'id': 'form1'}) 
soup = BeautifulSoup(response.content, 'lxml', parse_only=strainer) 

# get the view state, event target and validation values 
viewstate = soup.find('input', id='__VIEWSTATE').get('value') 
eventvalidation = soup.find('input', id='__EVENTVALIDATION').get('value') 
search_button = soup.find('input', value='Search') 
event_target = re.search(r"__doPostBack\('(.*?)'", search_button.get('onclick')).group(1) 

# configure post request parameters 
data = { 
    '__EVENTTARGET': event_target, 
    '__EVENTARGUMENT': '', 
    '__LASTFOCUS': '', 
    '__VIEWSTATE': viewstate, 
    '__EVENTVALIDATION': eventvalidation, 
    'ctl00$Body$ddlSemester': '201405', 
    'ctl00$Body$ddlSession': '', 
    'ctl00$Body$ddlDept': '%', 
    'ctl00$Body$ddlAttributes': '0', 
    'ctl00$Body$Days': 'rbAnyDay', 
    'ctl00$Body$Time': 'rbAnyTime', 
    'ctl00$Body$cbMorning': 'on', 
    'ctl00$Body$cbAfternoon': 'on', 
    'ctl00$Body$cbEvening': 'on', 
    'ctl00$Body$tbStart': '9:00am', 
    'ctl00$Body$tbEnds': '5:00pm', 
    'ctl00$Body$ddlUnits': '0', 
    'ctl00$Body$cbHideIStudy': 'on', 
    'ctl00$Body$courseList$hidHoverShow': 'Y', 
    'ctl00$Body$courseList$hidDeptBarCnt': '', 
    'ctl00$Body$courseList$hidSiteURL': 'https://acadinfo.wustl.edu/Courselistings', 
    'ctl00$Body$courseList$hidExpandDetail': '', 
    'ctl00$Body$hidDay': ',1,2,3,4,5,6,7', 
    'ctl00$Body$hidLevel': '1234', 
    'ctl00$Body$hidDefLevel': '' 
} 

# get the list of options 
strainer = SoupStrainer('div', attrs={'id': 'Body_courseList_tabSelect'}) 
options = soup.select('#Body_ddlSchool > option') 
for option in options: 
    print "Processing {option} ...".format(option=option.text) 

    data['ctl00$Body$ddlSchool'] = option.get('value') 

    # make the search post request for a particular option 
    response = session.post('https://acadinfo.wustl.edu/Courselistings/Semester/Search.aspx', 
          data=data) 
    result_soup = BeautifulSoup(response.content, parse_only=strainer) 
    print [item.text[:20].replace('&nbsp', ' ') + '...' for item in result_soup.select('div.CrsOpen')] 

打印:

Processing Architecture ... 
[u'A46 ARCH 100...', u'A46 ARCH 111...', u'A46 ARCH 209...', u'A46 ARCH 211...', u'A46 ARCH 266...', u'A46 ARCH 305...', u'A46 ARCH 311...', u'A46 ARCH 323...', u'A46 ARCH 328...', u'A46 ARCH 336...', u'A46 ARCH 343...', u'A46 ARCH 350...', u'A46 ARCH 355...', u'A46 ARCH 411...', u'A46 ARCH 422...', u'A46 ARCH 428...', u'A46 ARCH 436...', u'A46 ARCH 445...', u'A46 ARCH 447...', u'A46 ARCH 465...', u'A48 LAND 451...', u'A48 LAND 453...', u'A48 LAND 461...'] 
Processing Art ... 
[u'F10 ART 1052...', u'F10 ART 1073...', u'F10 ART 213A...', u'F10 ART 215A...', u'F10 ART 217B...', u'F10 ART 221A...', u'F10 ART 231I...', u'F10 ART 241D...', u'F10 ART 283T...', u'F10 ART 301A...', u'F10 ART 311E...', u'F10 ART 313D...', u'F10 ART 315B...', u'F10 ART 317H...', u'F10 ART 323A...', u'F10 ART 323B...', u'F10 ART 323C...', u'F10 ART 329C...', u'F10 ART 337E...', u'F10 ART 337F...', u'F10 ART 337H...', u'F10 ART 385A...', u'F10 ART 391M...', u'F10 ART 401A...', u'F10 ART 411E...', u'F10 ART 413D...', u'F10 ART 415B...', u'F10 ART 417H...', u'F10 ART 423A...', u'F10 ART 423B...', u'F10 ART 423C...', u'F10 ART 429C...', u'F10 ART 433C...', u'F10 ART 433D...', u'F10 ART 433E...', u'F10 ART 433K...', u'F10 ART 461C...', u'F10 ART 485A...', u'F20 ART 111P...', u'F20 ART 115P...', u'F20 ART 1186...', u'F20 ART 119C...', u'F20 ART 127A...', u'F20 ART 133B...', u'F20 ART 135G...', u'F20 ART 135I...', u'F20 ART 135J...', u'F20 ART 1361...', u'F20 ART 1363...', u'F20 ART 1713...', u'F20 ART 219C...', u'F20 ART 2363...', u'F20 ART 2661...', u'F20 ART 281S...', u'F20 ART 311P...', u'F20 ART 315P...', u'F20 ART 3183...', u'F20 ART 333B...', u'F20 ART 335A...', u'F20 ART 335J...', u'F20 ART 3713...', u'F20 ART 381S...', u'F20 ART 415P...', u'F20 ART 435I...'] 
... 

當然,還有事情需要改進,比如,我已對其他表單值進行了硬編碼 - 您應該分析可能的值並進行適當的設置。

另一個改進是配合這部長達grequests

GRequests允許您使用與GEVENT的要求輕鬆地進行異步 HTTP請求。


正如你所看到的,當你在更高的層次,並通過webdriver的瀏覽器進行交互 - 你不擔心未來的服務器,讓你的數據的實際要求。這使得它很容易自動化,但可能會非常緩慢。當您進入低級自動化時,您有更多的選擇來加快速度,但實施複雜性增長非常快。另外,請考慮這種解決方案的可靠性。所以可能會堅持「黑盒子」解決方案,並保持selenium


我也試圖解決使用問題:

但由於不同的原因失敗(可以爲您提供相關的錯誤信息)。但是,所有這3種工具都應該有助於簡化解決方案。

也看到類似的主題:

+0

哇!所以是的 - 我使用Selenium的原因之一是因爲我覺得他們可以少量改變網站,並且非常容易地打破我的腳本......但是我也認識到運行虛幻網頁瀏覽器的速度有多慢。我也只是開心地開玩笑,認爲可能會更容易跳過所有的發佈數據,因爲該網站看起來像一團糟。你是如何計算哪些字段需要填充的? – tbondwilkinson 2014-08-28 16:20:34

+0

@tbondwilkinson正好。我使用了Chrome提供的瀏覽器開發工具。在Firefox的情況下,你可以使用螢火蟲。幾乎必須有網絡抓取。 – alecxe 2014-08-28 16:22:01