2016-04-05 66 views
2

我試圖從Udacity的學生數量中取消課程的名稱,以找出哪些課程是最受歡迎的。我設法爲項目創建代碼:刮交互式網站

import scrapy 
class UdacityItem(scrapy.Item): 
    name=scrapy.Field() 
    users=scrapy.Field() 

和蜘蛛:

import scrapy 
from Udacity.items import UdacityItem 
import re 

class DmozSpider(scrapy.Spider): 
    name = "UdSpider" 
    allowed_domains = ["udacity.com"] 
    start_urls = ["https://www.udacity.com/courses/all"] 

    def parse(self, response): 

     sites = response.xpath('//h3/a') 
     for s in sites: 
      t=UdacityItem() 
      #name & url 
      t['name']=s.xpath('text()').extract()[0].strip() 
      url=response.urljoin(s.xpath('@href').extract()[0]) 
      #request 
      req=scrapy.Request(url, callback=self.second) 
      req.meta['item']=t 
      #execute 
      yield req 

    def second(self,response): 
     t=response.meta['item'] 
     strong =response.xpath('//strong[@data-course-student-count]/text()').extract()[0] 
     t['users']=strong 
     yield t 

結果,我發現了,當然名字,但不是學生,我得到的文本「千人數」。當我在瀏覽器中打開一個example website時,我發現'千位'是基本值,後來(在1-2秒內),這段文本正在變成一個合適的數字(我希望得到)。

這裏是我的問題:

  1. 爲什麼這個更換是怎麼回事?這是JavaScript代碼嗎?我想 喜歡瞭解這種變化的機制。
  2. 我如何捕捉正確數量的學生使用scrapy?我希望這是可能的。

非常感謝您的幫助。

回答

2

要獲得註冊數量,您必須模擬API請求https://www.udacity.com/api/summaries端點的特定課程ID,可以從URL本身提取 - 例如,https://www.udacity.com/course/javascript-promises--ud898 URL爲ud898

完整的蜘蛛:

import json 

import re 
from urllib import quote_plus 

import scrapy 


class UdacityItem(scrapy.Item): 
    name = scrapy.Field() 
    users = scrapy.Field() 


class DmozSpider(scrapy.Spider): 
    name = "UdSpider" 
    allowed_domains = ["udacity.com"] 
    start_urls = ["https://www.udacity.com/courses/all"] 

    def parse(self, response): 
     sites = response.xpath('//h3/a') 
     for s in sites: 
      t = UdacityItem() 
      # name & url 
      t['name'] = s.xpath('text()').extract()[0].strip() 
      url = response.urljoin(s.xpath('@href').extract()[0]) 
      # request 
      req = scrapy.Request(url, callback=self.second) 
      req.meta['item'] = t 
      # execute 
      yield req 

    def second(self, response): 
     queries = [{ 
      "limit": 1, 
      "model": "CourseStudentsSummary", 
      "locator": { 
       "sample_frequency": "daily", 
       "content_context": [{ 
        "node_key": re.search(r'--(.*?)$', response.url).group(1) 
       }] 
      } 
     }] 
     yield scrapy.Request(method="GET", 
          url="https://www.udacity.com/api/summaries?queries=" + quote_plus(json.dumps(queries)), 
          callback=self.parse_totals) 

    def parse_totals(self, response): 
     print(json.loads(response.body[5:].strip())["summaries"]["default"][0]["data"]["total_enrollments"]) 
+0

親愛alecxe。感謝您的答覆。現在我有解決方案,但仍然沒有看到加載html和發送API請求之間的鏈接。當我查看文檔時,我找不到對此負責的代碼。你如何確定你需要提出API請求?我想JavaScript代碼是負責在文檔末尾加載的,我是對的嗎? – michalk

+1

@michalk我已經使用了瀏覽器開發工具 - 網絡選項卡和僅過濾XHR請求;在頁面加載過程中有幾個XHR請求,我檢查了他們,發現響應中的總入學人數。然後,在Scrapy..hope中做出了相同的請求。 – alecxe