2016-09-21 53 views
2

我對Python和Scrapy相當陌生,並且遇到了如何在Scrapy的幫助下創建嵌套JSON的問題。在Scrapy中嵌套項目數據

從XP中選擇我想要的元素在XPath Helper和一些Google的幫助下沒有問題。但我不太清楚我應該如何獲得我想要的JSON結構。

的JSON結構,我希望會是這樣的:

{"menu": { 
    "Monday": { 
     "alt1": "Item 1", 
     "alt2": "Item 2", 
     "alt3": "Item 3" 
    }, 
    "Tuesday": { 
     "alt1": "Item 1", 
     "alt2": "Item 2", 
     "alt3": "Item 3" 
    } 
}} 

的HTML看起來像:

<ul> 
    <li class="title"><h2>Monday</h2></li> 
    <li>Item 1</li> 
    <li>Item 2</li> 
    <li>Item 3</li> 
</ul> 
<ul> 
    <li class="title"><h2>Tuesday</h2></li> 
    <li>Item 1</li> 
    <li>Item 2</li> 
    <li>Item 3</li> 
</ul> 

我發現https://stackoverflow.com/a/25096896/6856987,我卻無法適應這個適合我的需要。我非常感謝在正確的方向上推動我如何實現這一目標。

編輯:隨着由Padraic提供的微調,我設法讓我更接近我想要完成的一步。我提出了以下幾點,這比我之前的情況略有改善。 JSON仍然不是我想要的地方。

Scrapy蜘蛛:

import scrapy 
from dmoz.items import DmozItem 

class DmozSpider(scrapy.Spider): 
    name = "dmoz" 
    start_urls = ['http://urlto.com'] 

    def parse(self, response): 
     uls = response.xpath('//ul[position() >= 1 and position() < 6]') 
     item = DmozItem() 
     item['menu'] = {} 
     item['menu'] = {"restaurant": "name"} 
     for ul in uls: 
       item['menu']['restaurant']['dayOfWeek'] = ul.xpath("li/h2/text()").extract() 
       item['menu']['restaurant']['menuItem'] = ul.xpath("li/text()").extract() 
       yield item 

生成的JSON:

[ 
    { 
     "menu":{ 
      "dayOfWeek":[ 
       "Monday" 
      ], 
      "menuItem":[ 
       "Item 1", 
       "Item 2", 
       "Item 3" 
      ] 
     } 
    }, 
    { 
     "menu":{ 
      "dayOfWeek":[ 
       "Tuesday" 
      ], 
      "menuItem":[ 
       "Item 1", 
       "Item 2", 
       "Item 3" 
      ] 
     } 
    } 
] 

可以肯定的感覺就像我在做一千零件一個事情不對的,希望有人更聰明比我可以點我是正確的方式。

+0

我可以看到'dmoz.items.DmozItem'嗎? – Sam

回答

0

你只需要找到所有的ULS然後提取LIS將它們分組,下面的示例使用LXML:

from lxml import html 

h = """<ul> 
    <li class="title"><h2>Monday</h2></li> 
    <li>Item 1</li> 
    <li>Item 2</li> 
    <li>Item 3</li> 
</ul> 
<ul> 
    <li class="title"><h2>Tuesday</h2></li> 
    <li>Item 1</li> 
    <li>Item 2</li> 
    <li>Item 3</li> 
</ul>""" 

tree = html.fromstring(h) 

uls = tree.xpath("//ul") 

data = {} 
# iterate over all uls 
for ul in uls: 
    # extract the ul's li's 
    lis = ul.xpath("li") 
    # use the h2 text as the key and all the text from the remaining as values 
    # with enumerate to add the alt logic 
    data[lis[0].xpath("h2")[0].text] = {"alt{}".format(i): node.text for i, node in enumerate(lis[1:], 1)} 

print(data) 

這將使你:

{'Monday': {'alt1': 'Item 1', 'alt2': 'Item 2', 'alt3': 'Item 3'}, 
'Tuesday': {'alt1': 'Item 1', 'alt2': 'Item 2', 'alt3': 'Item 3'}} 

如果你想把它變成一個單一的comporehension:

data = {lis[0].xpath("h2")[0].text: 
       {"alt{}".format(i): node.text for i, node in enumerate(lis[1:], 1)} 
        for lis in (ul.xpath("li") for ul in tree.xpath("//ul"))} 

在你的問題和foll處理你的編輯代碼由於相同的所需輸出:

def parse(self, response): 
    uls = response.xpath('//ul[position() >= 1 and position() < 6]') 
    item = DmozItem() 
    # just create an empty dict 
    item['menu'] = {} 
    for ul in uls: 
     # for each ul, add a key value pair {day: {alti: each li_text skipping the first}} 
     item['menu'][ul.xpath("li/h2/text()").extract_first()]\ 
      = {"alt{}".format(i): node.text for i, node in enumerate(ul.xpath("li[postition() > 1]/text()").extract(), 1)} 
    # yield outside the loop 
    yield item 

這會給你像一個字典數據:

In [15]: d = {"menu":{'Monday': {'alt1': 'Item 1', 'alt2': 'Item 2', 'alt3': 'Item 3'}, 
        'Tuesday': {'alt1': 'Item 1', 'alt2': 'Item 2', 'alt3': 'Item 3'}}} 

In [16]: d["menu"]["Tuesday"] 
Out[16]: {'alt1': 'Item 1', 'alt2': 'Item 2', 'alt3': 'Item 3'} 

In [17]: d["menu"]["Monday"] 
Out[17]: {'alt1': 'Item 1', 'alt2': 'Item 2', 'alt3': 'Item 3'} 

In [18]: d["menu"]["Monday"]["alt1"] 
Out[18]: 'Item 1' 

符合你原來的問題預計產值超過你的新的,但我看不出有什麼優勢,你是什麼在新邏輯中添加"dayOfWeek"等。

+0

感謝您的推動,Padraic。它讓我更接近了一點,但是我很難將它翻譯成Scrapy。我用更多的信息更新了我原來的問題。 – Kristoffer

+0

Padraic,再次感謝你的出色幫助。我不得不將'node.text'改爲'node',否則會拋出一個錯誤('AttributeError:'unicode'對象沒有屬性'text')。有趣的是,它沒有以正確的順序返回項目(或子項目),在實際爬行中,我按照以下順序獲取它們:星期五,星期四,星期四,星期三,星期一。但我確信我可以解決這個問題,或者解決它。再次感謝! – Kristoffer

+0

@Kristoffer,不用擔心,字典是無序的,如果你想要命令你應該使用'collections.OrderedDict'代替正規字典 –