2017-07-01 23 views
3

與我之前的問題Extracting p within h1 with Python/Scrapy相關但不同,Extracting p within h1 with Python/Scrapy,我遇到了Scrapy(用於Python)不會在h4標籤。在Scrapy中使用XPath提取HTML結果失敗,因爲內容是動態加載的

實例HTML是:

<div class="event-specifics"> 
<div class="event-location"> 
    <h3> Gourmet Matinee </h3> 
    <h4> 
    <span id="spanEventDetailPerformanceLocation">Knight Grove</span> 
    </h4> 
</div> 
</div> 

我試圖抓住span標籤內的文本 「騎士樹林」。當使用命令行上scrapy殼,

response.xpath('.//div[@class="event-location"]//span//text()').extract() 

回報:

['Knight Grove'] 

而且

response.xpath('.//div[@class="event-location"]/node()') 

返回整個節點,即:

['\n     ', '<h3>\n      Gourmet Matinee</h3>', '\n     ', '<h4><span id="spanEventDetailPerformanceLocation"><p>Knight Grove</p></span></h4>', '\n    '] 

但是,當那麼相同的Xpath將在a中運行蜘蛛,什麼都沒有返回。舉例來說,下面的蜘蛛代碼是爲了抓取上面示例HTML的頁面而寫的,https://www.clevelandorchestra.com/17-blossom--summer/1718-gourmet-matinees/2017-07-11-gourmet-matinee/。 (由於它與問題無關,因此部分代碼被刪除):

# -*- coding: utf-8 -*- 
import scrapy 
from scrapy.spiders import CrawlSpider, Rule 
from scrapy.loader import ItemLoader 
from concertscraper.items import Concert 
from scrapy.contrib.loader import XPathItemLoader 
from scrapy import Selector 
from scrapy.http import XmlResponse 

class ClevelandOrchestra(CrawlSpider): 
    name = 'clev2' 
    allowed_domains = ['clevelandorchestra.com'] 

    start_urls = ['https://www.clevelandorchestra.com/'] 

    rules = (
     Rule(LinkExtractor(allow=''), callback='parse_item', follow=True), 
    ) 

    def parse_item(self, response): 
    thisconcert = ItemLoader(item=Concert(), response=response) 
    for concert in response.xpath('.//div[@class="event-wrap"]'): 

     thisconcert.add_xpath('location','.//div[@class="event-location"]//span//text()') 

    return thisconcert.load_item() 

這不返回項目['location']。我也試過:

thisconcert.add_xpath('location','.//div[@class="event-location"]/node()') 

不同於上述關於小時內P中的問題,跨度標籤允許在HTML標記^ h內,除非是我弄錯了?

爲了清楚起見,'location'字段在Concert()對象中定義,並且我禁用了所有管道以排除故障。

h4範圍內的跨度可能在某種程度上是無效的HTML;如果沒有,可能是什麼原因造成的?

有趣的是,使用add_css()去大約相同的任務,像這樣:

thisconcert.add_css('location','.event-location') 

產生與跨度標籤存在,但內部文本丟失一個節點:

['<div class="event-location">\r\n' 
      '     <h3>\r\n' 
      '      BLOSSOM MUSIC FESTIVAL </h3>\r\n' 
      '     <h4><span ' 
      'id="spanEventDetailPerformanceLocation"></span></h4>\r\n' 
      '    </div>'] 

要確認這不是重複的:在這個特殊的例子中,在h4標籤內部的span標籤內部存在ap標籤;但是,如果沒有涉及p標籤,則會發生相同的行爲,例如:https://www.clevelandorchestra.com/1718-concerts-pdps/1718-rental-concerts/1718-rentals-other/2017-07-21-cooper-competition/?performanceNumber=16195

+1

您引用的跨度在示例網址中似乎爲空。文本節點因此不存在,所以它不返回任何內容。 –

+0

您可以提供有關您所看到的更多詳情嗎?對我來說,在FirePath中,Xpath完全隔離了我試圖從該URL提取的文本。跨度節點本身包含一個包含此文本的p節點 - 應該在text()之前由雙斜線捕獲。 – NFB

+1

Scrapy不是一個Web瀏覽器,所以它不會執行JavaScript等來更改頁面並像Web瀏覽器那樣渲染它。當你在網頁瀏覽器中加載它時,頁面上的腳本似乎必須填充該範圍的值(因此爲什麼你的xpath瀏覽器擴展工作),但scrapy不運行腳本並加載它(因此,它不會運行腳本) t找到跨度內的文本節點,因此失敗)。 –

回答

2

通過Ajax調用加載此內容。爲了獲取數據,您需要製作類似的POST請求,並且不要忘記添加內容類型爲:headers = {'content-type': "application/json"}的標頭,並且您將獲得Json文件作爲響應。 enter image description here

import requests 

url = "https://www.clevelandorchestra.com/Services/PerformanceService.asmx/GetToolTipPerformancesForCalendar" 
payload = {"startDate": "2017-06-30T21:00:00.000Z", "endDate": "2017-12-31T21:00:00.000Z"} 
headers = {'content-type': "application/json"} 

json_response = requests.post(url, json=payload, headers=headers).json() 
for performance in json_response['d']: 
    print(performance["performanceName"], performance["dateString"]) 

# Star-Spangled Spectacular Friday, June 30, 2017 
# Blossom: Tchaikovskys Spectacular 1812 Overture Saturday, July 1, 2017 
# Blossom: Tchaikovskys Spectacular 1812 Overture Sunday, July 2, 2017 
# Blossom: A Salute to America Monday, July 3, 2017 
# Blossom: A Salute to America Tuesday, July 4, 2017 
+0

這很好,謝謝。我已經改變了問題的標題以反映結果和答案。 – NFB

+1

沒問題,我很高興我能幫助你。如果你想使用Scrapy,你可以使用[這個問題]中的代碼(https://stackoverflow.com/questions/30342243/send-post-request-in-scrapy),我用'requests'做了我的例子。 – vold